mirror of
https://github.com/jimeh/go-render.git
synced 2026-02-19 03:16:39 +00:00
refactor: focus around Render/Compact/Pretty/NewWith functions
This is yet another drastic refactor of public API and concepts. Hopefully the last one, as I'm now fairly happy with things.
This commit is contained in:
108
renderer.go
108
renderer.go
@@ -4,61 +4,86 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrUnsupportedFormat is returned when a format is not supported by a
|
||||
// renderer. Any method that accepts a format string may return this error.
|
||||
// ErrUnsupportedFormat is returned when a format is not supported by any
|
||||
// Handler.
|
||||
var ErrUnsupportedFormat = fmt.Errorf("%w: unsupported format", Err)
|
||||
|
||||
// Renderer is a renderer that delegates rendering to another renderer
|
||||
// based on a format value.
|
||||
// Renderer exposes methods for rendering values to different formats. The
|
||||
// Renderer delegates rendering to format specific handlers based on the format
|
||||
// string given.
|
||||
type Renderer struct {
|
||||
// Renderers is a map of format names to renderers. When Render is called,
|
||||
// the format is used to look up the renderer to use.
|
||||
Renderers map[string]FormatRenderer
|
||||
// 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
|
||||
}
|
||||
|
||||
// New returns a new Renderer that delegates rendering to the specified
|
||||
// renderers.
|
||||
// Handlers.
|
||||
//
|
||||
// Any renderers which implement the Formats interface, will also be set as the
|
||||
// renderer for all format strings returned by Format() on the renderer.
|
||||
func New(renderers map[string]FormatRenderer) *Renderer {
|
||||
newRenderers := make(map[string]FormatRenderer, len(renderers))
|
||||
// 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 New(handlers map[string]Handler) *Renderer {
|
||||
r := &Renderer{Handlers: make(map[string]Handler, len(handlers))}
|
||||
|
||||
for format, r := range renderers {
|
||||
newRenderers[format] = r
|
||||
for format, handler := range handlers {
|
||||
r.Add(format, handler)
|
||||
}
|
||||
|
||||
if x, ok := r.(Formats); ok {
|
||||
for _, f := range x.Formats() {
|
||||
if f != format {
|
||||
newRenderers[f] = r
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// 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 (r *Renderer) Add(format string, handler Handler) {
|
||||
if format != "" {
|
||||
r.Handlers[strings.ToLower(format)] = handler
|
||||
}
|
||||
|
||||
if x, ok := handler.(FormatsHandler); ok {
|
||||
for _, f := range x.Formats() {
|
||||
if f != "" && f != format {
|
||||
r.Handlers[strings.ToLower(f)] = handler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &Renderer{Renderers: newRenderers}
|
||||
}
|
||||
|
||||
// Render renders a value to an io.Writer using the specified format. If the
|
||||
// format is not supported, ErrUnsupportedFormat is returned.
|
||||
// Render renders a value to the given io.Writer using the specified format.
|
||||
//
|
||||
// If the format is supported, but the value cannot be rendered to the format,
|
||||
// the error returned by the renderer is returned. In most cases this will be
|
||||
// ErrCannotRender, but it could be a different error if the renderer returns
|
||||
// one.
|
||||
func (r *Renderer) Render(w io.Writer, format string, v any) error {
|
||||
renderer, ok := r.Renderers[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.
|
||||
func (r *Renderer) Render(
|
||||
w io.Writer,
|
||||
format string,
|
||||
pretty bool,
|
||||
v any,
|
||||
) error {
|
||||
handler, ok := r.Handlers[strings.ToLower(format)]
|
||||
if !ok {
|
||||
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, format)
|
||||
}
|
||||
|
||||
err := renderer.Render(w, v)
|
||||
prettyHandler, ok := handler.(PrettyHandler)
|
||||
var err error
|
||||
if pretty && ok {
|
||||
err = prettyHandler.RenderPretty(w, v)
|
||||
} else {
|
||||
err = handler.Render(w, v)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrCannotRender) {
|
||||
return fmt.Errorf("%w: %s", ErrUnsupportedFormat, format)
|
||||
}
|
||||
|
||||
// Ensure that the error is wrapped with ErrFailed if it is not already.
|
||||
if !errors.Is(err, ErrFailed) {
|
||||
return fmt.Errorf("%w: %w", ErrFailed, err)
|
||||
}
|
||||
@@ -69,14 +94,27 @@ func (r *Renderer) Render(w io.Writer, format string, v any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) OnlyWith(formats ...string) *Renderer {
|
||||
renderers := make(map[string]FormatRenderer, len(formats))
|
||||
// Compact is a convenience method that calls Render with pretty set to false.
|
||||
func (r *Renderer) Compact(w io.Writer, format string, v any) error {
|
||||
return r.Render(w, format, false, v)
|
||||
}
|
||||
|
||||
// Pretty is a convenience method that calls Render with pretty set to true.
|
||||
func (r *Renderer) Pretty(w io.Writer, format string, v any) error {
|
||||
return r.Render(w, format, true, v)
|
||||
}
|
||||
|
||||
// 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 (r *Renderer) NewWith(formats ...string) *Renderer {
|
||||
handlers := make(map[string]Handler, len(formats))
|
||||
|
||||
for _, format := range formats {
|
||||
if r, ok := r.Renderers[format]; ok {
|
||||
renderers[format] = r
|
||||
if r, ok := r.Handlers[strings.ToLower(format)]; ok {
|
||||
handlers[format] = r
|
||||
}
|
||||
}
|
||||
|
||||
return New(renderers)
|
||||
return New(handlers)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user