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 9e9f19905a1ebc70c09a411f4c1b5cd3dd5e7d55
parent 0e4cddcf6a8804b26750d62df47bc919ba60835c
Author: gearsix <gearsix@tuta.io>
Date:   Fri,  3 Feb 2023 19:27:36 +0000

v1 changes; removed DEPRECIATED code and a few fixes

- Fix to ReadDataFormat / ReadTemplateLanguage
- Fix to cmd/dati.go
- Removed: ReadDataFilepath, ReadTemplateFilepath, {Is,}SupportedDataLangs,
  {Is,}SupportedTemplateLangs, etc...
- renamed examples/suti.cfg to examples/dati.cfg - fixes dati_test

Diffstat:
Mcmd/dati.go | 6+++---
Mdata.go | 35++++++++---------------------------
Mdata_test.go | 75+++++++++++++++++++++------------------------------------------------------
Rexamples/suti.cfg -> examples/dati.cfg | 0
Mtemplate.go | 82+++++++++++++++++++++++++++++++------------------------------------------------
Mtemplate_test.go | 54++++++++++--------------------------------------------
6 files changed, 74 insertions(+), 178 deletions(-)

diff --git a/cmd/dati.go b/cmd/dati.go @@ -95,7 +95,7 @@ func main() { opts.GlobalDataPaths = loadFilePaths(opts.GlobalDataPaths...) for _, path := range opts.GlobalDataPaths { var d Data - err = dati.LoadDataFilepath(path, &d) + err = dati.LoadDataFile(path, &d) assert(err, "failed to load global data '%s'", path) data = append(data, d) } @@ -109,13 +109,13 @@ func main() { data = make([]Data, 0) for _, path := range opts.DataPaths { var d Data - err = dati.LoadDataFilepath(path, &d) + err = dati.LoadDataFile(path, &d) assert(err, "failed to load data '%s'", path) data = append(data, d) } global[opts.DataKey] = data - template, err = dati.LoadTemplateFilepath(opts.RootPath, opts.PartialPaths...) + template, err = dati.LoadTemplateFile(opts.RootPath, opts.PartialPaths...) assert(err, "unable to load templates") out, err = template.Execute(global) diff --git a/data.go b/data.go @@ -48,7 +48,11 @@ func ReadDataFormat(path string) DataFormat { } ext := filepath.Ext(path) - ext = strings.ToLower(path) + if len(ext) == 0 { + ext = path // assume `path` the name of the format + } + + ext = strings.ToLower(ext) if len(ext) > 0 && ext[0] == '.' { ext = ext[1:] } @@ -61,26 +65,9 @@ func ReadDataFormat(path string) DataFormat { return "" } -// **DEPRECIATED** please use SupportedFormat -var SupportedDataLangs = []string{"json", "yaml", "toml"} - -// **DEPRECIATED** please use ReadDataFormat -func IsSupportedDataLang(lang string) int { - lang = strings.ToLower(lang) - if len(lang) > 0 && lang[0] == '.' { - lang = lang[1:] - } - for i, l := range []DataFormat{JSON, YAML, TOML} { - if lang == string(l) { - return i - } - } - return -1 -} - // LoadData attempts to load all data from `in` as the data language `lang` // and writes the result in the pointer `outp`. -func LoadData(format string, in io.Reader, outp interface{}) error { +func LoadData(format DataFormat, in io.Reader, outp interface{}) error { inbuf, e := ioutil.ReadAll(in) if e != nil { return e @@ -88,7 +75,7 @@ func LoadData(format string, in io.Reader, outp interface{}) error { return nil } - switch ReadDataFormat(format) { + switch format { case JSON: e = json.Unmarshal(inbuf, outp) case YAML: @@ -110,16 +97,10 @@ func LoadDataFile(path string, outp interface{}) error { defer f.Close() if e == nil { - lang := filepath.Ext(path)[1:] // don't include '.' - if e = LoadData(lang, f, outp); e != nil { + if e = LoadData(ReadDataFormat(path), f, outp); e != nil { e = fmt.Errorf("failed to load data '%s': %s", path, e.Error()) } } return e } - -// **DEPRECIATED** please use LoadDataFile -func LoadDataFilepath(path string, outp interface{}) error { - return LoadDataFile(path, outp) -} diff --git a/data_test.go b/data_test.go @@ -26,36 +26,6 @@ import ( "testing" ) -func TestIsSupportedDataLang(t *testing.T) { - exts := []string{ - ".json", "json", "JSON", ".JSON", - ".yaml", "yaml", "YAML", ".YAML", - ".toml", "toml", "TOML", ".TOML", - ".misc", "-", ".", "", - } - - for i, ext := range exts { - var target int - if i < 4 { - target = 0 - } else if i < 8 { - target = 1 - } else if i < 12 { - target = 2 - } else { - target = -1 - } - - if IsSupportedDataLang(ext) != target { - if target == -1 { - t.Fatalf("%s is not a supported data language", ext) - } else { - t.Fatalf("%s did not return %s", ext, SupportedDataLangs[target]) - } - } - } -} - func TestReadDataFormat(t *testing.T) { exts := []string{ ".json", "json", "JSON", ".JSON", @@ -66,7 +36,7 @@ func TestReadDataFormat(t *testing.T) { for i, ext := range exts { var target DataFormat - + if i < 4 { target = JSON } else if i < 8 { @@ -75,21 +45,22 @@ func TestReadDataFormat(t *testing.T) { target = TOML } - if ReadDataFormat(ext) != target { + fmt := ReadDataFormat(ext) + if fmt != target { if target == "" { - t.Fatalf("%s is not a supported data language", ext) + t.Fatalf("%s is not a supported data language", fmt) } else { - t.Fatalf("%s did not return %s", ext, target) + t.Fatalf("%s did not return %s", fmt, target) } } } } -var good = map[string]string{ - "json": `{"eg":0}`, - "yaml": `eg: 0 +var good = map[DataFormat]string{ + JSON: `{"eg":0}`, + YAML: `eg: 0 `, - "toml": `eg = 0 + TOML: `eg = 0 `, } @@ -109,7 +80,7 @@ func writeTestFile(t *testing.T, path string, Data string) { return } -func validateData(t *testing.T, d interface{}, e error, lang string) { +func validateData(t *testing.T, d interface{}, e error, lang DataFormat) { var b []byte if e != nil { @@ -117,11 +88,11 @@ func validateData(t *testing.T, d interface{}, e error, lang string) { } switch lang { - case "json": + case JSON: b, e = json.Marshal(d) - case "yaml": + case YAML: b, e = yaml.Marshal(d) - case "toml": + case TOML: b, e = toml.Marshal(d) } @@ -142,23 +113,19 @@ func TestLoadData(t *testing.T) { validateData(t, d, e, lang) } - if e = LoadData("json", strings.NewReader(badData), &d); e == nil { + if e = LoadData(JSON, strings.NewReader(badData), &d); e == nil { t.Fatalf("bad data passed") } - if e = LoadData("toml", strings.NewReader(""), &d); e != nil { + if e = LoadData(TOML, strings.NewReader(""), &d); e != nil { t.Fatalf("empty data failed %s, %s", d, e) } - if e = LoadData("void", strings.NewReader("shouldn't pass"), &d); e == nil { + if e = LoadData("", strings.NewReader("shouldn't pass"), &d); e == nil { t.Fatalf("invalid data language passed") } return } -func TestLoadDataFilepath(t *testing.T) { - TestLoadDataFile(t) -} - func TestLoadDataFile(t *testing.T) { var d interface{} var e error @@ -166,27 +133,27 @@ func TestLoadDataFile(t *testing.T) { tdir := os.TempDir() for lang, data := range good { - p = tdir + "/good." + lang + p = tdir + "/good." + string(lang) writeTestFile(t, p, data) - e = LoadDataFilepath(p, &d) + e = LoadDataFile(p, &d) validateData(t, d, e, lang) } p = tdir + "/bad.json" writeTestFile(t, p, badData) - e = LoadDataFilepath(p, &d) + e = LoadDataFile(p, &d) if e == nil { t.Fatalf("bad data passed") } p = tdir + "/empty.json" writeTestFile(t, p, "") - e = LoadDataFilepath(p, &d) + e = LoadDataFile(p, &d) if e != nil { t.Fatalf("empty file failed: %s", e) } - if e = LoadDataFilepath("non-existing-file.toml", &d); e == nil { + if e = LoadDataFile("non-existing-file.toml", &d); e == nil { t.Fatalf("non-existing file passed: %s, %s", d, e) } diff --git a/examples/suti.cfg b/examples/dati.cfg diff --git a/template.go b/template.go @@ -41,16 +41,20 @@ const ( MST TemplateLanguage = "mst" ) -// ReadTemplateFormat returns the *TemplateLanguage* that the file +// ReadTemplateLanguage returns the *TemplateLanguage* that the file // extension of `path` matches. If the file extension of `path` does // not match any *TemplateLanguage*, then an "" is returned. -func ReadTemplateFormat(path string) TemplateLanguage { +func ReadTemplateLangauge(path string) TemplateLanguage { if len(path) == 0 { return "" } ext := filepath.Ext(path) - ext = strings.ToLower(path) + if len(ext) == 0 { + ext = path // assume `path` the name of the format + } + + ext = strings.ToLower(ext) if len(ext) > 0 && ext[0] == '.' { ext = ext[1:] } @@ -63,23 +67,6 @@ func ReadTemplateFormat(path string) TemplateLanguage { return "" } -// **DEPRECIATED** please use TemplateLanguage -var SupportedTemplateLangs = []string{"tmpl", "hmpl", "mst"} - -// **DEPRECIATED** please use ReadTemplateFormat -func IsSupportedTemplateLang(lang string) int { - lang = strings.ToLower(lang) - if len(lang) > 0 && lang[0] == '.' { - lang = lang[1:] - } - for i, l := range SupportedTemplateLangs { - if lang == l { - return i - } - } - return -1 -} - func getTemplateType(path string) string { return strings.TrimPrefix(filepath.Ext(path), ".") } @@ -123,11 +110,6 @@ func (t *Template) Execute(d interface{}) (result bytes.Buffer, err error) { return } -// **DEPRECIATED** please use LoadTemplateFile -func LoadTemplateFilepath(rootPath string, partialPaths ...string) (t Template, e error) { - return LoadTemplateFile(rootPath, partialPaths...) -} - // LoadTemplateFilepath loads a Template from file `root`. All files in `partials` // that have the same template type (identified by file extension) are also // parsed and associated with the parsed root template. @@ -140,7 +122,7 @@ func LoadTemplateFile(rootPath string, partialPaths ...string) (t Template, e er return } - lang := strings.TrimPrefix(filepath.Ext(rootPath), ".") + lang := ReadTemplateLangauge(rootPath) rootName := strings.TrimSuffix(filepath.Base(rootPath), filepath.Ext(rootPath)) @@ -176,7 +158,7 @@ func LoadTemplateFile(rootPath string, partialPaths ...string) (t Template, e er // return a `LoadTemplate` call using them as parameters. // The `partials` map should have the template name to assign the partial template to in the // string key and the template data in as the value. -func LoadTemplateString(lang string, rootName string, root string, partials map[string]string) (t Template, e error) { +func LoadTemplateString(lang TemplateLanguage, rootName string, root string, partials map[string]string) (t Template, e error) { p := make(map[string]io.Reader) for name, partial := range partials { p[name] = strings.NewReader(partial) @@ -184,6 +166,29 @@ func LoadTemplateString(lang string, rootName string, root string, partials map[ 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`. +// `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`. +func LoadTemplate(lang TemplateLanguage, rootName string, root io.Reader, partials map[string]io.Reader) (t Template, e error) { + t.Name = rootName + + switch TemplateLanguage(lang) { + case TMPL: + t.T, e = loadTemplateTmpl(rootName, root, partials) + case HMPL: + t.T, e = loadTemplateHmpl(rootName, root, partials) + case MST: + t.T, e = loadTemplateMst(rootName, root, partials) + default: + e = fmt.Errorf("'%s' is not a supported template language", lang) + } + + return +} + func loadTemplateTmpl(rootName string, root io.Reader, partials map[string]io.Reader) (*tmpl.Template, error) { var template *tmpl.Template @@ -245,26 +250,3 @@ func loadTemplateMst(rootName string, root io.Reader, partials map[string]io.Rea return template, nil } - -// 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`. -func LoadTemplate(lang string, rootName string, root io.Reader, partials map[string]io.Reader) (t Template, e error) { - t.Name = rootName - - switch TemplateLanguage(lang) { - case TMPL: - t.T, e = loadTemplateTmpl(rootName, root, partials) - case HMPL: - t.T, e = loadTemplateHmpl(rootName, root, partials) - case MST: - t.T, e = loadTemplateMst(rootName, root, partials) - default: - e = fmt.Errorf("'%s' is not a supported template language", lang) - } - - return -} diff --git a/template_test.go b/template_test.go @@ -19,8 +19,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. import ( "bytes" - "os" "io/ioutil" + "os" "path/filepath" "reflect" "strings" @@ -45,37 +45,7 @@ const mstResult = `0 0` const mstRootBad = `{{> badPartial.mst}}{{#doesnt-exist}}{{/exit}}` const mstPartialBad = `p{{$}}{{ > noexist}` -func TestIsSupportedTemplateLang(t *testing.T) { - exts := []string{ - ".tmpl", "tmpl", "TMPL", ".TMPL", - ".hmpl", "hmpl", "HMPL", ".HMPL", - ".mst", "mst", "MST", ".MST", - ".NONE", "-", ".", "", - } - - for i, ext := range exts { - var target int - if i < 4 { - target = 0 - } else if i < 8 { - target = 1 - } else if i < 12 { - target = 2 - } else { - target = -1 - } - - if IsSupportedTemplateLang(ext) != target { - if target == -1 { - t.Fatalf("%s is not a supported data language", ext) - } else { - t.Fatalf("%s did not return %s", ext, SupportedTemplateLangs[target]) - } - } - } -} - -func TestReadTemplateFormat(t *testing.T) { +func TestReadTemplateLanguage(t *testing.T) { exts := []string{ ".tmpl", "tmpl", "TMPL", ".TMPL", ".hmpl", "hmpl", "HMPL", ".HMPL", @@ -95,7 +65,7 @@ func TestReadTemplateFormat(t *testing.T) { target = "" } - if ReadTemplateFormat(ext) != target { + if ReadTemplateLangauge(ext) != target { if target == "" { t.Fatalf("%s is not a supported data language", ext) } else { @@ -152,10 +122,6 @@ func validateTemplateFile(t *testing.T, template Template, rootPath string, part validateTemplate(t, template, rType, rName, pNames...) } -func TestLoadTemplateFilepath(t *testing.T) { - TestLoadTemplateFile(t) -} - func TestLoadTemplateFile(t *testing.T) { t.Parallel() @@ -196,19 +162,19 @@ func TestLoadTemplateFile(t *testing.T) { createFile(badPartials[len(badPartials)-1], mstPartialBad) for i, root := range goodRoots { // good root, good partials - if template, e := LoadTemplateFilepath(root, goodPartials[i]); e != nil { + if template, e := LoadTemplateFile(root, goodPartials[i]); e != nil { t.Fatal(e) } else { validateTemplateFile(t, template, root, goodPartials[i]) } } for i, root := range badRoots { // bad root, good partials - if _, e := LoadTemplateFilepath(root, goodPartials[i]); e == nil { + if _, e := LoadTemplateFile(root, goodPartials[i]); e == nil { t.Fatalf("no error for bad template with good partials\n") } } for i, root := range badRoots { // bad root, bad partials - if _, e := LoadTemplateFilepath(root, badPartials[i]); e == nil { + if _, e := LoadTemplateFile(root, badPartials[i]); e == nil { t.Fatalf("no error for bad template with bad partials\n") } } @@ -217,9 +183,9 @@ func TestLoadTemplateFile(t *testing.T) { func TestLoadTemplateString(t *testing.T) { var err error var template Template - var templateType string + var templateType TemplateLanguage - testInvalid := func(templateType string, template Template) { + testInvalid := func(templateType TemplateLanguage, template Template) { t.Logf("invalid '%s' template managed to load", templateType) if buf, err := template.Execute(""); err == nil { t.Fatalf("invalid '%s' template managed to execute: %s", templateType, buf.String()) @@ -227,7 +193,7 @@ func TestLoadTemplateString(t *testing.T) { } name := "test" - templateType = "tmpl" + templateType = TMPL if _, err = LoadTemplateString(templateType, name, tmplRootGood, map[string]string{"tmplPartialGood": tmplPartialGood}); err != nil { t.Fatalf("'%s' template failed to load", templateType) @@ -270,7 +236,7 @@ func TestLoadTemplateString(t *testing.T) { } } -// func TestLoadTemplateString(t *testing.T) {} // This is tested by TestLoadTemplateFilepath and TestLoadTemplateString +// func TestLoadTemplateString(t *testing.T) {} // This is tested by TestLoadTemplateFile and TestLoadTemplateString func validateExecute(t *testing.T, results string, expect string, e error) { if e != nil {