]> Cypherpunks repositories - gostls13.git/commitdiff
exp/template: construct sets from plain template files
authorRob Pike <r@golang.org>
Sat, 23 Jul 2011 08:10:30 +0000 (18:10 +1000)
committerRob Pike <r@golang.org>
Sat, 23 Jul 2011 08:10:30 +0000 (18:10 +1000)
This is the last piece (I hope) of the set creation code.
These helpers create sets from files containing individual
template definitions, free of {{define}} clauses. This
design is helpful if the templates live one per file,
undecorated.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4801052

src/pkg/exp/template/helper.go
src/pkg/exp/template/set.go
src/pkg/exp/template/set_test.go
src/pkg/exp/template/testdata/tmpl1.tmpl [new file with mode: 0644]
src/pkg/exp/template/testdata/tmpl2.tmpl [new file with mode: 0644]

index b0d9ca73393fdd0c80bc0afcddb847ad2c77d65a..5eb46ee1dfe308e8dcc5afcf581cec663d44f2b3 100644 (file)
@@ -13,6 +13,8 @@ import (
        "path/filepath"
 )
 
+// Functions and methods to parse a single template.
+
 // MustParse parses the template definition string to construct an internal
 // representation of the template for execution.
 // It panics if the template cannot be parsed.
@@ -57,6 +59,8 @@ func MustParseFile(filename string) *Template {
        return New(filepath.Base(filename)).MustParseFile(filename)
 }
 
+// Functions and methods to parse a set.
+
 // MustParse parses a string into a set of named templates.
 // It panics if the set cannot be parsed.
 func (s *Set) MustParse(text string) *Set {
@@ -160,3 +164,146 @@ func MustParseSetFiles(pattern string) *Set {
        }
        return set
 }
+
+// Functions and methods to parse stand-alone template files into a set.
+
+// ParseTemplateFile parses the named template files and adds
+// them to the set. Each template will named the base name of
+// its file.
+// Unlike with ParseFile, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFile is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func (s *Set) ParseTemplateFile(filenames ...string) os.Error {
+       for _, filename := range filenames {
+               t, err := ParseFile(filename)
+               if err != nil {
+                       return err
+               }
+               if err := s.add(t); err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+// MustParseTemplateFile is like ParseTemplateFile but
+// panics if there is an error.
+func (s *Set) MustParseTemplateFile(filenames ...string) {
+       err := s.ParseTemplateFile(filenames...)
+       if err != nil {
+               panic(err)
+       }
+}
+
+// ParseTemplateFiles parses the template files matched by the
+// patern and adds them to the set. Each template will named
+// the base name of its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func (s *Set) ParseTemplateFiles(pattern string) os.Error {
+       filenames, err := filepath.Glob(pattern)
+       if err != nil {
+               return err
+       }
+       for _, filename := range filenames {
+               t, err := ParseFile(filename)
+               if err != nil {
+                       return err
+               }
+               if err := s.add(t); err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+// MustParseTemplateFile is like ParseTemplateFiles but
+// panics if there is an error.
+func (s *Set) MustParseTemplateFiles(pattern string) {
+       err := s.ParseTemplateFiles(pattern)
+       if err != nil {
+               panic(err)
+       }
+}
+
+// ParseTemplateFile creates a set by parsing the named files,
+// each of which defines a single template. Each template will
+// named the base name of its file.
+// Unlike with ParseFile, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFile is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateFile(filenames ...string) (*Set, os.Error) {
+       set := new(Set)
+       for _, filename := range filenames {
+               t, err := ParseFile(filename)
+               if err != nil {
+                       return nil, err
+               }
+               if err := set.add(t); err != nil {
+                       return nil, err
+               }
+       }
+       return set, nil
+}
+
+// MustParseTemplateFile is like ParseTemplateFile but
+// panics if there is an error.
+func MustParseTemplateFile(filenames ...string) *Set {
+       set, err := ParseTemplateFile(filenames...)
+       if err != nil {
+               panic(err)
+       }
+       return set
+}
+
+// ParseTemplateFiles creates a set by parsing the files matched
+// by the pattern, each of which defines a single template. Each
+// template will named the base name of its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateFiles(pattern string) (*Set, os.Error) {
+       filenames, err := filepath.Glob(pattern)
+       if err != nil {
+               return nil, err
+       }
+       set := new(Set)
+       for _, filename := range filenames {
+               t, err := ParseFile(filename)
+               if err != nil {
+                       return nil, err
+               }
+               if err := set.add(t); err != nil {
+                       return nil, err
+               }
+       }
+       return set, nil
+}
+
+// MustParseTemplateFiles is like ParseTemplateFiles but
+// panics if there is a parse error or other problem
+// constructing the set.
+func MustParseTemplateFiles(pattern string) *Set {
+       set, err := ParseTemplateFiles(pattern)
+       if err != nil {
+               panic(err)
+       }
+       return set
+}
index ddf024eaf4f1b760a61a01d170c245c384d9ab03..dc64b4c9c3850af49240f60ce9800b45cd882aec 100644 (file)
@@ -43,20 +43,28 @@ func (s *Set) Funcs(funcMap FuncMap) *Set {
 // a set.
 // The return value is the set, so calls can be chained.
 func (s *Set) Add(templates ...*Template) *Set {
-       s.init()
        for _, t := range templates {
-               if t.set != nil {
-                       panic(fmt.Errorf("template: %q already in a set", t.name))
-               }
-               if _, ok := s.tmpl[t.name]; ok {
-                       panic(fmt.Errorf("template: %q already defined in set", t.name))
+               if err := s.add(t); err != nil {
+                       panic(err)
                }
-               s.tmpl[t.name] = t
-               t.set = s
        }
        return s
 }
 
+// add adds the argument template to the set.
+func (s *Set) add(t *Template) os.Error {
+       s.init()
+       if t.set != nil {
+               return fmt.Errorf("template: %q already in a set", t.name)
+       }
+       if _, ok := s.tmpl[t.name]; ok {
+               return fmt.Errorf("template: %q already defined in set", t.name)
+       }
+       s.tmpl[t.name] = t
+       t.set = s
+       return nil
+}
+
 // Template returns the template with the given name in the set,
 // or nil if there is no such template.
 func (s *Set) Template(name string) *Template {
index f79663eb06ecdddf56e24bf5ead484ed3c151228..c42d97a07b591108d0bdf8f6779f8e13dfa87615 100644 (file)
@@ -138,6 +138,23 @@ func TestParseSetFile(t *testing.T) {
        testExecute(setExecTests, set, t)
 }
 
+func TestSetParseFiles(t *testing.T) {
+       set := new(Set)
+       err := set.ParseFiles("DOES NOT EXIST")
+       if err == nil {
+               t.Error("expected error for non-existent file; got none")
+       }
+       err = set.ParseFiles("[x")
+       if err == nil {
+               t.Error("expected error for bad pattern; got none")
+       }
+       err = set.ParseFiles("testdata/file*.tmpl")
+       if err != nil {
+               t.Fatalf("error parsing files: %v", err)
+       }
+       testExecute(setExecTests, set, t)
+}
+
 func TestParseSetFiles(t *testing.T) {
        set, err := ParseSetFiles("DOES NOT EXIST")
        if err == nil {
@@ -147,9 +164,71 @@ func TestParseSetFiles(t *testing.T) {
        if err == nil {
                t.Error("expected error for bad pattern; got none")
        }
-       set, err = ParseSetFiles("testdata/*.tmpl")
+       set, err = ParseSetFiles("testdata/file*.tmpl")
        if err != nil {
                t.Fatalf("error parsing files: %v", err)
        }
        testExecute(setExecTests, set, t)
 }
+
+var templateFileExecTests = []execTest{
+       {"teset", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\ntemplate2\n", 0, true},
+}
+
+func TestSetParseTemplateFile(t *testing.T) {
+       set := new(Set)
+       err := set.ParseTemplateFile("DOES NOT EXIST")
+       if err == nil {
+               t.Error("expected error for non-existent file; got none")
+       }
+       err = set.ParseTemplateFile("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+       if err != nil {
+               t.Fatalf("error parsing files: %v", err)
+       }
+       testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateFile(t *testing.T) {
+       set, err := ParseTemplateFile("DOES NOT EXIST")
+       if err == nil {
+               t.Error("expected error for non-existent file; got none")
+       }
+       set, err = ParseTemplateFile("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+       if err != nil {
+               t.Fatalf("error parsing files: %v", err)
+       }
+       testExecute(templateFileExecTests, set, t)
+}
+
+func TestSetParseTemplateFiles(t *testing.T) {
+       set := new(Set)
+       err := set.ParseTemplateFiles("DOES NOT EXIST")
+       if err == nil {
+               t.Error("expected error for non-existent file; got none")
+       }
+       err = set.ParseTemplateFiles("[x")
+       if err == nil {
+               t.Error("expected error for bad pattern; got none")
+       }
+       err = set.ParseTemplateFiles("testdata/tmpl*.tmpl")
+       if err != nil {
+               t.Fatalf("error parsing files: %v", err)
+       }
+       testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateFiles(t *testing.T) {
+       set, err := ParseTemplateFiles("DOES NOT EXIST")
+       if err == nil {
+               t.Error("expected error for non-existent file; got none")
+       }
+       set, err = ParseTemplateFiles("[x")
+       if err == nil {
+               t.Error("expected error for bad pattern; got none")
+       }
+       set, err = ParseTemplateFiles("testdata/tmpl*.tmpl")
+       if err != nil {
+               t.Fatalf("error parsing files: %v", err)
+       }
+       testExecute(templateFileExecTests, set, t)
+}
diff --git a/src/pkg/exp/template/testdata/tmpl1.tmpl b/src/pkg/exp/template/testdata/tmpl1.tmpl
new file mode 100644 (file)
index 0000000..3d15b81
--- /dev/null
@@ -0,0 +1 @@
+template1
diff --git a/src/pkg/exp/template/testdata/tmpl2.tmpl b/src/pkg/exp/template/testdata/tmpl2.tmpl
new file mode 100644 (file)
index 0000000..a374d2f
--- /dev/null
@@ -0,0 +1 @@
+template2