dati

A Go library/binary to parse & execute data against template langauges.
git clone git://src.gearsix.net/dati
Log | Files | Refs | Atom | README | LICENSE

commit ab45d1b8595dec2fdb98f1370e1ffc4d65a2099e
parent d85964737a3213a281bdaef6e2e9a93fda706429
Author: gearsix <gearsix@tuta.io>
Date:   Sat, 18 Feb 2023 19:05:36 +0000

standardised package errors; added .String() to custom types.

Also made minor improvements to error handling and comment doc in a few
places.

Diffstat:
Mdata.go | 38+++++++++++++++++++++-----------------
Mtemplate.go | 39+++++++++++++++++++++++++++++----------
2 files changed, 50 insertions(+), 27 deletions(-)

diff --git a/data.go b/data.go @@ -34,12 +34,22 @@ import ( // data files (lower-case) type DataFormat string +// String returns the typical file extension used to +// represent `df` +func (df DataFormat) String() string { + return string(df) +} + const ( JSON DataFormat = "json" YAML DataFormat = "yaml" TOML DataFormat = "toml" ) +var ErrUnsupportedData = func(format string) error { + return fmt.Errorf("data format '%s' is not supported", format) +} + // IsDataFile checks if `path` is one of the known *DatFormat*s. func IsDataFormat(path string) bool { return ReadDataFormat(path) != "" @@ -64,7 +74,7 @@ func ReadDataFormat(path string) DataFormat { } for _, fmt := range []DataFormat{JSON, YAML, TOML} { - if string(fmt) == ext { + if fmt.String() == ext { return fmt } } @@ -89,7 +99,7 @@ func LoadData(format DataFormat, in io.Reader, out interface{}) error { case TOML: err = toml.Unmarshal(inbuf, out) default: - err = fmt.Errorf("'%s' is not a supported data language", format) + err = ErrUnsupportedData(format.String()) } return err @@ -100,15 +110,12 @@ func LoadData(format DataFormat, in io.Reader, out interface{}) error { // as a json). The result is written to the value pointed at by `outp`. func LoadDataFile(path string, outp interface{}) error { file, err := os.Open(path) - defer file.Close() - - if err == nil { - if err = LoadData(ReadDataFormat(path), file, outp); err != nil { - err = fmt.Errorf("failed to load data '%s': %s", path, err.Error()) - } + if err != nil { + return err } + defer file.Close() - return err + return LoadData(ReadDataFormat(path), file, outp) } // WriteData attempts to write `data` as `format` to `outp`. @@ -123,7 +130,7 @@ func WriteData(format DataFormat, data interface{}, w io.Writer) error { case TOML: err = toml.NewEncoder(w).Encode(data) default: - err = fmt.Errorf("'%s' is not a supported data language", format) + err = ErrUnsupportedData(format.String()) } return err @@ -132,15 +139,12 @@ func WriteData(format DataFormat, data interface{}, w io.Writer) error { // WriteDataFile attempts to write `data` as `format` to the file at `path`. // If `force` is *true*, then any existing files will be overwritten. func WriteDataFile(format DataFormat, data interface{}, path string) (f *os.File, err error) { - f, err = os.Open(path) + if f, err = os.Open(path); err != nil { + return + } defer f.Close() - if err == nil { - if err = WriteData(format, data, f); err != nil { - err = fmt.Errorf("faild to write data '%s': %s", path, err.Error()) - } - } - if err != nil { + if err = WriteData(format, data, f); err != nil { f = nil } diff --git a/template.go b/template.go @@ -19,6 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. import ( "bytes" + "errors" "fmt" hmpl "html/template" "io" @@ -36,12 +37,31 @@ import ( // Template files (lower-case) type TemplateLanguage string +func (t TemplateLanguage) String() string { + return string(t) +} + const ( TMPL TemplateLanguage = "tmpl" HMPL TemplateLanguage = "hmpl" MST TemplateLanguage = "mst" ) +var ( + ErrUnsupportedTemplate = func(format string) error { + return fmt.Errorf("template language '%s' is not supported", format) + } + ErrUnknownTemplateType = func(templateType string) error { + return fmt.Errorf("unable to infer template type '%s'", templateType) + } + ErrRootPathIsDir = func(path string) error { + return fmt.Errorf("rootPath path must be a file, not a directory (%s)", path) + } + ErrNilTemplate = errors.New("template is nil") +) + +// IsTemplateLanguage will return a bool if the file found at `path` +// is a known *TemplateLanguage*, based upon it's file extension. func IsTemplateLanguage(path string) bool { return ReadTemplateLangauge(path) != "" } @@ -65,7 +85,7 @@ func ReadTemplateLangauge(path string) TemplateLanguage { } for _, fmt := range []TemplateLanguage{TMPL, HMPL, MST} { - if string(fmt) == ext { + if fmt.String() == ext { return fmt } } @@ -91,7 +111,7 @@ func (t *Template) Execute(data interface{}) (result bytes.Buffer, err error) { var params []reflect.Value tType := reflect.TypeOf(t.T) if tType == nil { - err = fmt.Errorf("template.T is nil") + err = ErrNilTemplate return } switch tType.String() { @@ -102,7 +122,7 @@ func (t *Template) Execute(data interface{}) (result bytes.Buffer, err error) { funcName = "FRender" params = []reflect.Value{reflect.ValueOf(&result), reflect.ValueOf(data)} default: - err = fmt.Errorf("unable to infer template type '%s'", reflect.TypeOf(t.T).String()) + err = ErrUnknownTemplateType(reflect.TypeOf(t.T).String()) } if err == nil { @@ -123,7 +143,7 @@ func LoadTemplateFile(rootPath string, partialPaths ...string) (t Template, err if stat, err = os.Stat(rootPath); err != nil { return } else if stat.IsDir() { - err = fmt.Errorf("rootPath path must be a file, not a directory: %s", rootPath) + err = ErrRootPathIsDir(rootPath) return } @@ -171,12 +191,11 @@ func LoadTemplateString(lang TemplateLanguage, rootName string, root string, par return LoadTemplate(lang, rootName, strings.NewReader(root), p) } -// LoadTemplate loads a Template from `root` of type `lang`, named -// `name`. `lang` must be an element in `SupportedTemplateLangs`. +// LoadTemplate loads a Template from `root` of type `lang`, named `name`. +// `lang` must be an element in `SupportedTemplateLangs`. // `name` is optional, if empty the template name will be "template". -// `root` should be a string of template, with syntax matching that of -// `lang`. `partials` should be a string of template, with syntax -// matching that of `lang`. +// `root` should be a string of template, with syntax matching that of `lang`. +// `partials` should be a string of template, with syntax matching that of `lang`. func LoadTemplate(lang TemplateLanguage, rootName string, root io.Reader, partials map[string]io.Reader) (t Template, err error) { t.Name = rootName @@ -188,7 +207,7 @@ func LoadTemplate(lang TemplateLanguage, rootName string, root io.Reader, partia case MST: t.T, err = loadTemplateMst(rootName, root, partials) default: - err = fmt.Errorf("'%s' is not a supported template language", lang) + err = ErrUnsupportedTemplate(lang.String()) } return