render

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 25, 2024 License: MIT Imports: 8 Imported by: 1

README

go-render

A simple and flexible solution to render a value to a io.Writer using different formats based on a format string argument.

GitHub tag (latest SemVer) Go Reference GitHub issues GitHub pull requests Coverage License Status

Designed around using a custom type/struct to render your output. Thanks to Go's marshaling interfaces, you get JSON, YAML, and XML support almost for free. While plain text output is supported by the type implementing io.Reader, io.WriterTo, fmt.Stringer, and error interfaces, or by simply being a type which can easily be type cast to a byte slice.

Originally intended to easily implement CLI tools which can output their data as plain text, as well as JSON/YAML with a simple switch of a format string. But it can just as easily render to any io.Writer.

The package is designed to be flexible and extensible with a sensible set of defaults accessible via package level functions. You can create your own Renderer for custom formats, or create new handlers that support custom formats.

Import

import "github.com/jimeh/go-render"

Usage

Basic usage to render a value to various formats into a io.Writer:

version := &Version{Version: "1.2.1", Stable: true, Latest: false}

err = render.Pretty(w, "text", version)
// 1.2.1 (stable: true, latest: false)

err = render.Pretty(w, "json", version)
// {
//   "version": "1.2.1",
//   "latest": false,
//   "stable": true
// }

err = render.Compact(w, "json", version)
// {"version":"1.2.1","latest":false,"stable":true}

err = render.Pretty(w, "yaml", version)
// version: 1.2.1
// latest: false
// stable: true

err = render.Pretty(w, "xml", version)
// <version latest="false" stable="true">1.2.1</version>

The above assumes the following Version struct:

type Version struct {
    Version string `json:"version" yaml:"version" xml:",chardata"`
    Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
    Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

func (v *Version) String() string {
    return fmt.Sprintf(
        "%s (stable: %t, latest: %t)", v.Version, v.Stable, v.Latest,
    )
}

Documentation

Please see the Go Reference for documentation and further examples.

License

MIT

Documentation

Overview

Package render provides a simple and flexible solutio to render a value to a io.Writer using different formats based on a format string argument.

It is designed around using a custom type/struct to render your output. Thanks to Go's marshaling interfaces, you get JSON, YAML, and XML support almost for free. While plain text output is supported by the type implementing io.Reader, io.WriterTo, fmt.Stringer, or error interfaces, or by simply being a type which can easily be type cast to a byte slice.

Originally intended to easily implement CLI tools which can output their data as plain text, as well as JSON/YAML with a simple switch of a format string. But it can just as easily render to any io.Writer.

The package is designed to be flexible and extensible with a sensible set of defaults accessible via package level functions. You can create your own Renderer for custom formats, or create new handlers that support custom formats.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// Err is the base error for the package. All errors returned by this
	// package are wrapped with this error.
	Err       = fmt.Errorf("render")
	ErrFailed = fmt.Errorf("%w: failed", Err)

	// ErrCannotRender is returned when a value cannot be rendered. This may be
	// due to the value not supporting the format, or the value itself not being
	// renderable. Only Renderer implementations should return this error.
	ErrCannotRender = fmt.Errorf("%w: cannot render", Err)

	// Base is a renderer that supports all formats. It is used by the package
	// level NewWith function to create new renderers with a sub-set of
	// formats.
	Base = New(map[string]Handler{
		"binary": &Binary{},
		"json":   &JSON{},
		"text":   &Text{},
		"xml":    &XML{},
		"yaml":   &YAML{},
	})

	// Default is the default renderer that is used by package level Render,
	// Compact, Pretty functions. It supports JSON, Text, and YAML formats.
	Default = Base.NewWith("json", "text", "yaml")
)
View Source
var ErrUnsupportedFormat = fmt.Errorf("%w: unsupported format", Err)

ErrUnsupportedFormat is returned when a format is not supported by any Handler.

View Source
var JSONDefualtIndent = "  "

JSONDefualtIndent is the default indentation string used by JSON instances when pretty rendering if no Indent value is set on the JSON instance itself.

View Source
var XMLDefualtIndent = "  "

XMLDefualtIndent is the default indentation string used by XML instances when pretty rendering if no Indent value is set.

View Source
var YAMLDefaultIndent = 2

Functions

func Compact

func Compact(w io.Writer, format string, v any) error

Compact is a convenience function that calls the Default renderer's Compact method. It is the same as calling Render with pretty set to false.

Example (Json)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Compact(os.Stdout, "json", data)
if err != nil {
	panic(err)
}
Output:

{"current":"1.2.2","versions":[{"version":"1.2.2","latest":true,"stable":true},{"version":"1.2.1","latest":false,"stable":true},{"version":"1.2.0","latest":false,"stable":true},{"version":"1.2.0-rc.0","latest":false,"stable":false},{"version":"1.1.0","latest":false,"stable":true}]}
Example (TextFromByteSlice)
data := []byte("Hello, World!1")

err := render.Compact(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

Hello, World!1
Example (TextFromIOReader)
var data io.Reader = strings.NewReader("Hello, World!!!1")

err := render.Compact(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

Hello, World!!!1
Example (TextFromString)
data := "Hello, World!"

err := render.Compact(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

Hello, World!
Example (TextFromStringer)
// The User struct has a String method which returns a string representation
// of a user:
//
//	func (ol *OutputList) String() string {
//		buf := &strings.Builder{}
//
//		for _, ver := range ol.Versions {
//			if ol.Current == ver.Version {
//				buf.WriteString("* ")
//			} else {
//				buf.WriteString("  ")
//			}
//
//			buf.WriteString(ver.Version)
//			if !ver.Stable {
//				buf.WriteString(" (pre-release)")
//			}
//			if ver.Latest {
//				buf.WriteString(" (latest)")
//			}
//
//			buf.WriteByte('\n')
//		}
//
//		return buf.String()
//	}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Compact(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

* 1.2.2 (latest)
  1.2.1
  1.2.0
  1.2.0-rc.0 (pre-release)
  1.1.0
Example (TextFromWriterTo)
// The Version struct has a WriteTo method which writes a string
// representation of a version to an io.Writer:
//
//	func (v *Version) WriteTo(w io.Writer) (int64, error) {
//		s := fmt.Sprintf(
//			"%s (stable: %t, latest: %t)", v.Version, v.Stable, v.Latest,
//		)
//		n, err := w.Write([]byte(s))
//
//		return int64(n), err
//	}

data := &Version{Version: "1.2.1", Stable: true, Latest: false}

err := render.Compact(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

1.2.1 (stable: true, latest: false)
Example (Xml)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

// Create a new renderer that supports XML in addition to the default JSON,
// Text, and YAML formats.
renderer := render.NewWith("json", "text", "xml", "yaml")

err := renderer.Compact(os.Stdout, "xml", data)
if err != nil {
	panic(err)
}
Output:

<versions-list><current>1.2.2</current><version latest="true" stable="true">1.2.2</version><version latest="false" stable="true">1.2.1</version><version latest="false" stable="true">1.2.0</version><version latest="false" stable="false">1.2.0-rc.0</version><version latest="false" stable="true">1.1.0</version></versions-list>
Example (Yaml)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Compact(os.Stdout, "yaml", data)
if err != nil {
	panic(err)
}
Output:

current: 1.2.2
versions:
  - version: 1.2.2
    latest: true
    stable: true
  - version: 1.2.1
    latest: false
    stable: true
  - version: 1.2.0
    latest: false
    stable: true
  - version: 1.2.0-rc.0
    latest: false
    stable: false
  - version: 1.1.0
    latest: false
    stable: true

func Pretty

func Pretty(w io.Writer, format string, v any) error

Pretty is a convenience function that calls the Default renderer's Pretty method. It is the same as calling Render with pretty set to true.

Example (Json)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Pretty(os.Stdout, "json", data)
if err != nil {
	panic(err)
}
Output:

{
  "current": "1.2.2",
  "versions": [
    {
      "version": "1.2.2",
      "latest": true,
      "stable": true
    },
    {
      "version": "1.2.1",
      "latest": false,
      "stable": true
    },
    {
      "version": "1.2.0",
      "latest": false,
      "stable": true
    },
    {
      "version": "1.2.0-rc.0",
      "latest": false,
      "stable": false
    },
    {
      "version": "1.1.0",
      "latest": false,
      "stable": true
    }
  ]
}
Example (TextFromByteSlice)
data := []byte("Hello, World!1")

err := render.Pretty(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

Hello, World!1
Example (TextFromIOReader)
var data io.Reader = strings.NewReader("Hello, World!!!1")

err := render.Pretty(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

Hello, World!!!1
Example (TextFromString)
data := "Hello, World!"

err := render.Pretty(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

Hello, World!
Example (TextFromStringer)
// The User struct has a String method which returns a string representation
// of a user:
//
//	func (ol *OutputList) String() string {
//		buf := &strings.Builder{}
//
//		for _, ver := range ol.Versions {
//			if ol.Current == ver.Version {
//				buf.WriteString("* ")
//			} else {
//				buf.WriteString("  ")
//			}
//
//			buf.WriteString(ver.Version)
//			if !ver.Stable {
//				buf.WriteString(" (pre-release)")
//			}
//			if ver.Latest {
//				buf.WriteString(" (latest)")
//			}
//
//			buf.WriteByte('\n')
//		}
//
//		return buf.String()
//	}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Pretty(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

* 1.2.2 (latest)
  1.2.1
  1.2.0
  1.2.0-rc.0 (pre-release)
  1.1.0
Example (TextFromWriterTo)
// The Version struct has a WriteTo method which writes a string
// representation of a version to an io.Writer:
//
//	func (v *Version) WriteTo(w io.Writer) (int64, error) {
//		s := fmt.Sprintf(
//			"%s (stable: %t, latest: %t)", v.Version, v.Stable, v.Latest,
//		)
//		n, err := w.Write([]byte(s))
//
//		return int64(n), err
//	}

data := &Version{Version: "1.2.1", Stable: true, Latest: false}

err := render.Pretty(os.Stdout, "text", data)
if err != nil {
	panic(err)
}
Output:

1.2.1 (stable: true, latest: false)
Example (Xml)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

// Create a new renderer that supports XML in addition to the default JSON,
// Text, and YAML formats.
renderer := render.NewWith("json", "text", "xml", "yaml")

err := renderer.Pretty(os.Stdout, "xml", data)
if err != nil {
	panic(err)
}
Output:

<versions-list>
  <current>1.2.2</current>
  <version latest="true" stable="true">1.2.2</version>
  <version latest="false" stable="true">1.2.1</version>
  <version latest="false" stable="true">1.2.0</version>
  <version latest="false" stable="false">1.2.0-rc.0</version>
  <version latest="false" stable="true">1.1.0</version>
</versions-list>
Example (Yaml)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Pretty(os.Stdout, "yaml", data)
if err != nil {
	panic(err)
}
Output:

current: 1.2.2
versions:
  - version: 1.2.2
    latest: true
    stable: true
  - version: 1.2.1
    latest: false
    stable: true
  - version: 1.2.0
    latest: false
    stable: true
  - version: 1.2.0-rc.0
    latest: false
    stable: false
  - version: 1.1.0
    latest: false
    stable: true

func Render

func Render(w io.Writer, format string, pretty bool, v any) error

Render renders the given value to the given writer using the given format. If pretty is true, the value will be rendered "pretty" if the target format supports it, otherwise it will be rendered in a compact way.

It uses the default renderer to render the value, which supports JSON, Text, and YAML formats out of the box.

If you need to support a custom set of formats, use the New function to create a new Renderer with the formats you need. If you need new custom renderers, manually create a new Renderer.

Example (CompactJSON)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Render(os.Stdout, "json", false, data)
if err != nil {
	panic(err)
}
Output:

{"current":"1.2.2","versions":[{"version":"1.2.2","latest":true,"stable":true},{"version":"1.2.1","latest":false,"stable":true},{"version":"1.2.0","latest":false,"stable":true},{"version":"1.2.0-rc.0","latest":false,"stable":false},{"version":"1.1.0","latest":false,"stable":true}]}
Example (CompactTextFromByteSlice)
data := []byte("Hello, World!1")

err := render.Render(os.Stdout, "text", false, data)
if err != nil {
	panic(err)
}
Output:

Hello, World!1
Example (CompactTextFromIOReader)
var data io.Reader = strings.NewReader("Hello, World!!!1")

err := render.Render(os.Stdout, "text", false, data)
if err != nil {
	panic(err)
}
Output:

Hello, World!!!1
Example (CompactTextFromString)
data := "Hello, World!"

err := render.Render(os.Stdout, "text", false, data)
if err != nil {
	panic(err)
}
Output:

Hello, World!
Example (CompactTextFromStringer)
// The User struct has a String method which returns a string representation
// of a user:
//
//	func (ol *OutputList) String() string {
//		buf := &strings.Builder{}
//
//		for _, ver := range ol.Versions {
//			if ol.Current == ver.Version {
//				buf.WriteString("* ")
//			} else {
//				buf.WriteString("  ")
//			}
//
//			buf.WriteString(ver.Version)
//			if !ver.Stable {
//				buf.WriteString(" (pre-release)")
//			}
//			if ver.Latest {
//				buf.WriteString(" (latest)")
//			}
//
//			buf.WriteByte('\n')
//		}
//
//		return buf.String()
//	}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Render(os.Stdout, "text", false, data)
if err != nil {
	panic(err)
}
Output:

* 1.2.2 (latest)
  1.2.1
  1.2.0
  1.2.0-rc.0 (pre-release)
  1.1.0
Example (CompactTextFromWriterTo)
// The Version struct has a WriteTo method which writes a string
// representation of a version to an io.Writer:
//
//	func (v *Version) WriteTo(w io.Writer) (int64, error) {
//		s := fmt.Sprintf(
//			"%s (stable: %t, latest: %t)", v.Version, v.Stable, v.Latest,
//		)
//		n, err := w.Write([]byte(s))
//
//		return int64(n), err
//	}

data := &Version{Version: "1.2.1", Stable: true, Latest: false}

err := render.Render(os.Stdout, "text", false, data)
if err != nil {
	panic(err)
}
Output:

1.2.1 (stable: true, latest: false)
Example (CompactXML)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

// Create a new renderer that supports XML in addition to the default JSON,
// Text, and YAML formats.
renderer := render.NewWith("json", "text", "xml", "yaml")

err := renderer.Render(os.Stdout, "xml", false, data)
if err != nil {
	panic(err)
}
Output:

<versions-list><current>1.2.2</current><version latest="true" stable="true">1.2.2</version><version latest="false" stable="true">1.2.1</version><version latest="false" stable="true">1.2.0</version><version latest="false" stable="false">1.2.0-rc.0</version><version latest="false" stable="true">1.1.0</version></versions-list>
Example (CompactYAML)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Render(os.Stdout, "yaml", false, data)
if err != nil {
	panic(err)
}
Output:

current: 1.2.2
versions:
  - version: 1.2.2
    latest: true
    stable: true
  - version: 1.2.1
    latest: false
    stable: true
  - version: 1.2.0
    latest: false
    stable: true
  - version: 1.2.0-rc.0
    latest: false
    stable: false
  - version: 1.1.0
    latest: false
    stable: true
Example (PrettyJSON)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Render(os.Stdout, "json", true, data)
if err != nil {
	panic(err)
}
Output:

{
  "current": "1.2.2",
  "versions": [
    {
      "version": "1.2.2",
      "latest": true,
      "stable": true
    },
    {
      "version": "1.2.1",
      "latest": false,
      "stable": true
    },
    {
      "version": "1.2.0",
      "latest": false,
      "stable": true
    },
    {
      "version": "1.2.0-rc.0",
      "latest": false,
      "stable": false
    },
    {
      "version": "1.1.0",
      "latest": false,
      "stable": true
    }
  ]
}
Example (PrettyTextFromByteSlice)
data := []byte("Hello, World!1")

err := render.Render(os.Stdout, "text", true, data)
if err != nil {
	panic(err)
}
Output:

Hello, World!1
Example (PrettyTextFromIOReader)
var data io.Reader = strings.NewReader("Hello, World!!!1")

err := render.Render(os.Stdout, "text", true, data)
if err != nil {
	panic(err)
}
Output:

Hello, World!!!1
Example (PrettyTextFromString)
data := "Hello, World!"

err := render.Render(os.Stdout, "text", true, data)
if err != nil {
	panic(err)
}
Output:

Hello, World!
Example (PrettyTextFromStringer)
// The User struct has a String method which returns a string representation
// of a user:
//
//	func (ol *OutputList) String() string {
//		buf := &strings.Builder{}
//
//		for _, ver := range ol.Versions {
//			if ol.Current == ver.Version {
//				buf.WriteString("* ")
//			} else {
//				buf.WriteString("  ")
//			}
//
//			buf.WriteString(ver.Version)
//			if !ver.Stable {
//				buf.WriteString(" (pre-release)")
//			}
//			if ver.Latest {
//				buf.WriteString(" (latest)")
//			}
//
//			buf.WriteByte('\n')
//		}
//
//		return buf.String()
//	}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Render(os.Stdout, "text", true, data)
if err != nil {
	panic(err)
}
Output:

* 1.2.2 (latest)
  1.2.1
  1.2.0
  1.2.0-rc.0 (pre-release)
  1.1.0
Example (PrettyTextFromWriterTo)
// The Version struct has a WriteTo method which writes a string
// representation of a version to an io.Writer:
//
//	func (v *Version) WriteTo(w io.Writer) (int64, error) {
//		s := fmt.Sprintf(
//			"%s (stable: %t, latest: %t)", v.Version, v.Stable, v.Latest,
//		)
//		n, err := w.Write([]byte(s))
//
//		return int64(n), err
//	}

data := &Version{Version: "1.2.1", Stable: true, Latest: false}

err := render.Render(os.Stdout, "text", true, data)
if err != nil {
	panic(err)
}
Output:

1.2.1 (stable: true, latest: false)
Example (PrettyXML)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

// Create a new renderer that supports XML in addition to the default JSON,
// Text, and YAML formats.
renderer := render.NewWith("json", "text", "xml", "yaml")

err := renderer.Render(os.Stdout, "xml", true, data)
if err != nil {
	panic(err)
}
Output:

<versions-list>
  <current>1.2.2</current>
  <version latest="true" stable="true">1.2.2</version>
  <version latest="false" stable="true">1.2.1</version>
  <version latest="false" stable="true">1.2.0</version>
  <version latest="false" stable="false">1.2.0-rc.0</version>
  <version latest="false" stable="true">1.1.0</version>
</versions-list>
Example (PrettyYAML)
type Version struct {
	Version string `json:"version" yaml:"version" xml:",chardata"`
	Latest  bool   `json:"latest" yaml:"latest" xml:"latest,attr"`
	Stable  bool   `json:"stable" yaml:"stable" xml:"stable,attr"`
}

type OutputList struct {
	Current  string    `json:"current" yaml:"current" xml:"current"`
	Versions []Version `json:"versions" yaml:"versions" xml:"version"`

	XMLName xml.Name `json:"-" yaml:"-" xml:"versions-list"`
}

data := &OutputList{
	Current: "1.2.2",
	Versions: []Version{
		{Version: "1.2.2", Stable: true, Latest: true},
		{Version: "1.2.1", Stable: true},
		{Version: "1.2.0", Stable: true},
		{Version: "1.2.0-rc.0", Stable: false},
		{Version: "1.1.0", Stable: true},
	},
}

err := render.Render(os.Stdout, "yaml", true, data)
if err != nil {
	panic(err)
}
Output:

current: 1.2.2
versions:
  - version: 1.2.2
    latest: true
    stable: true
  - version: 1.2.1
    latest: false
    stable: true
  - version: 1.2.0
    latest: false
    stable: true
  - version: 1.2.0-rc.0
    latest: false
    stable: false
  - version: 1.1.0
    latest: false
    stable: true

Types

type Binary

type Binary struct{}

Binary can render values which implment the encoding.BinaryMarshaler interface.

func (*Binary) Formats

func (br *Binary) Formats() []string

Formats returns a list of format strings that this Handler supports.

func (*Binary) Render

func (br *Binary) Render(w io.Writer, v any) error

Render writes result of calling MarshalBinary() on v. If v does not implment encoding.BinaryMarshaler the ErrCannotRander error will be returned.

type FormatsHandler

type FormatsHandler interface {
	// Formats returns a list of strings which all target the same format. In
	// most cases this would just be a single value, but multiple values are
	// supported for the sake of aliases, like "yaml" and "yml".
	Formats() []string
}

FormatsHandler is an optional interface that can be implemented by Handler implementations to return a list of formats that the handler supports. This is used by the New function to allow format aliases like "yml" for "yaml".

type Handler

type Handler interface {
	// Render writes v into w in the format that the Handler supports.
	//
	// If v does not implement a required interface, or otherwise cannot be
	// rendered to the format in question, then a ErrCannotRender error must be
	// returned. Any other errors should be returned as is.
	Render(w io.Writer, v any) error
}

Handler interface is for single format renderers, which can only render a single format. It is the basis of the multi-format support offerred by the render package.

type JSON

type JSON struct {
	// Prefix is the prefix added to each level of indentation when pretty
	// rendering.
	Prefix string

	// Indent is the string added to each level of indentation when pretty
	// rendering. If empty, two spaces will be used instead.
	Indent string
}

JSON is a Handler that marshals values to JSON.

func (*JSON) Formats

func (jr *JSON) Formats() []string

Formats returns a list of format strings that this Handler supports.

func (*JSON) Render

func (jr *JSON) Render(w io.Writer, v any) error

Render marshals the given value to JSON.

func (*JSON) RenderPretty

func (jr *JSON) RenderPretty(w io.Writer, v any) error

RenderPretty marshals the given value to JSON with line breaks and indentation.

type Multi

type Multi struct {
	Handlers []Handler
}

Multi is a Handler that tries multiple handlers until one succeeds.

func (*Multi) Formats

func (mr *Multi) Formats() []string

Formats returns a list of format strings that this Handler supports.

func (*Multi) Render

func (mr *Multi) Render(w io.Writer, v any) error

Render tries each handler in order until one succeeds. If none succeed, ErrCannotRender is returned. If a handler returns an error that is not ErrCannotRender, that error is returned.

func (*Multi) RenderPretty

func (mr *Multi) RenderPretty(w io.Writer, v any) error

RenderPretty tries each handler in order until one succeeds. If none succeed, ErrCannotRender is returned. If a handler returns an error that is not ErrCannotRender, that error is returned.

If a handler implements PrettyHandler, then the RenderPretty method is used instead of Render. Otherwise, the Render method is used.

type PrettyHandler

type PrettyHandler interface {
	// RenderPretty writes v into w in the format that the Handler supports,
	// using a pretty variant of the format. The exact definition of "pretty" is
	// up to the handler. Typically this would be mean adding line breaks and
	// indentation, like in the case of JSON and XML.
	//
	// If v does not implement a required interface, or otherwise cannot be
	// rendered to the format in question, then a ErrCannotRender error must be
	// returned. Any other errors should be returned as is.
	RenderPretty(w io.Writer, v any) error
}

PrettyHandler interface is a optional interface that can be implemented by Handler implementations to render a value in a pretty way. This is useful for formats that support pretty printing, like in the case of JSON and XML.

type Renderer

type Renderer struct {
	// Handlers is a map of format names to Handler. When Render is called,
	// the format is used to look up the Handler to use.
	Handlers map[string]Handler
}

Renderer exposes methods for rendering values to different formats. The Renderer delegates rendering to format specific handlers based on the format string given.

func New

func New(handlers map[string]Handler) *Renderer

New returns a new Renderer that delegates rendering to the specified Handlers.

Any Handlers which implement the FormatsHandler interface, will also be set as the handler for all format strings returned by Formats() on the handler.

func NewWith

func NewWith(formats ...string) *Renderer

NewWith creates a new Renderer with the given formats. Only formats on the BaseRender will be supported.

func (*Renderer) Add

func (r *Renderer) Add(format string, handler Handler)

Add adds a Handler to the Renderer. If the handler implements the FormatsHandler interface, the handler will be added for all formats returned by Formats().

func (*Renderer) Compact

func (r *Renderer) Compact(w io.Writer, format string, v any) error

Compact is a convenience method that calls Render with pretty set to false.

func (*Renderer) NewWith

func (r *Renderer) NewWith(formats ...string) *Renderer

NewWith creates a new Renderer with the formats given, if they have handlers in the currener Renderer. It essentially allows to restrict a Renderer to a only a sub-set of supported formats.

func (*Renderer) Pretty

func (r *Renderer) Pretty(w io.Writer, format string, v any) error

Pretty is a convenience method that calls Render with pretty set to true.

func (*Renderer) Render

func (r *Renderer) Render(
	w io.Writer,
	format string,
	pretty bool,
	v any,
) error

Render renders a value to the given io.Writer using the specified format.

If pretty is true, it will attempt to render the value with pretty formatting if the underlying Handler supports pretty formatting.

If the format is not supported or the value cannot be rendered to the format, a ErrUnsupportedFormat error is returned.

type Text

type Text struct{}

Text is a Handler that writes the given value to the writer as text, supporting multiple types and interfaces.

Supports rendering the following types as text:

  • []byte
  • []rune
  • string
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • bool
  • io.Reader
  • io.WriterTo
  • fmt.Stringer
  • error

If the value is of any other type, a ErrCannotRender error will be returned.

func (*Text) Formats

func (t *Text) Formats() []string

Formats returns a list of format strings that this Handler supports.

func (*Text) Render

func (t *Text) Render(w io.Writer, v any) error

Render writes the given value to the writer as text.

type XML

type XML struct {
	// Prefix is the prefix added to each level of indentation when pretty
	// rendering.
	Prefix string

	// Indent is the string added to each level of indentation when pretty
	// rendering. If empty, XMLDefualtIndent be used.
	Indent string
}

XML is a Renderer that marshals a value to XML.

func (*XML) Formats

func (x *XML) Formats() []string

Formats returns a list of format strings that this Handler supports.

func (*XML) Render

func (x *XML) Render(w io.Writer, v any) error

Render marshals the given value to XML.

func (*XML) RenderPretty

func (x *XML) RenderPretty(w io.Writer, v any) error

RenderPretty marshals the given value to XML with line breaks and indentation.

type YAML

type YAML struct {
	// Indent controls how many spaces will be used for indenting nested blocks
	// in the output YAML. When Indent is zero, YAMLDefaultIndent will be used.
	Indent int
}

YAML is a Handler that marshals the given value to YAML.

func (*YAML) Formats

func (y *YAML) Formats() []string

Formats returns a list of format strings that this Handler supports.

func (*YAML) Render

func (y *YAML) Render(w io.Writer, v any) error

Render marshals the given value to YAML.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL