├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── main.go
└── temple
├── README.md
├── assets
└── bindata.go
├── build.go
├── build_test.go
├── doc.go
├── dom.go
├── funcs_test.go
├── templates
└── generated.go.tmpl
├── temple.go
├── temple_test.go
├── test_files
├── layouts
│ └── app.tmpl
├── partials
│ └── todo.tmpl
├── run.go
└── templates
│ └── todos
│ └── index.tmpl
└── test_util.go
/.gitignore:
--------------------------------------------------------------------------------
1 | temple/test_files/templates.go
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ------------
3 |
4 | Feedback, bug reports, and pull requests are greatly appreciated :)
5 |
6 | ### Issues
7 |
8 | The following are all great reasons to submit an issue:
9 |
10 | 1. You found a bug in the code.
11 | 2. Something is missing from the documentation or the existing documentation is unclear.
12 | 3. You have an idea for a new feature.
13 |
14 | If you are thinking about submitting an issue please remember to:
15 |
16 | 1. Describe the issue in detail.
17 | 2. If applicable, describe the steps to reproduce the error, which probably should include some example code.
18 | 3. Mention details about your platform: OS, version of gopherjs, browser, etc.
19 |
20 | ### Pull Requests
21 |
22 | In order to submit a pull request:
23 |
24 | 1. Fork the repository.
25 | 2. Create a new "feature branch" with a descriptive name (e.g. fix-database-error).
26 | 3. Make your changes in the feature branch.
27 | 4. Run the tests to make sure that they still pass. Updated the tests if needed.
28 | 5. Submit a pull request to merge your feature branch into the *master* branch.
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Copyright (C) 2015, Alex Browne
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Humble/Temple
2 | =============
3 |
4 | [](https://github.com/go-humble/temple/releases)
5 | [](https://godoc.org/github.com/go-humble/temple)
6 |
7 | A library and a command line tool for sanely managing go templates, with the ability
8 | to share them between client and server. The library and code generated by the cli are
9 | both compatible with [gopherjs](https://github.com/gopherjs/gopherjs), so you can compile
10 | to javascript and run in the browser. Temple works great as a stand-alone package or in
11 | combination with other packages in the [Humble Framework](https://github.com/go-humble/humble).
12 |
13 | This README is specific to the command line tool, which reads .tmpl files in your project and
14 | generates go source code. The command line tool uses the library (mainly the Build function).
15 | The README for the library can be found at
16 | [github.com/go-humble/temple/temple](https://github.com/go-humble/temple/tree/develop/temple).
17 |
18 |
19 | What Does the Command Line Tool Do?
20 | -----------------------------------
21 |
22 | The command line tool first reads the contents of all the .tmpl files in the specified src directory
23 | (and it's sub-directories). Then it generates go code at the specified dest file which compiles the
24 | templates. The generated code uses strings which contain the content of source files as arguments to
25 | [`template.Parse`](http://golang.org/pkg/html/template/#Template.Parse).
26 |
27 | This is useful for a few reasons. If you're building and deploying binary executables, it means you
28 | no longer have to ship a templates folder with your binary distribution. It also makes it possible
29 | for you to use templates in code that has been compiled to javascript with gopherjs and is running
30 | in a browser. Since code generated by temple works exactly the same on the server and client, it also
31 | enables you to share templates between them. Check out
32 | [go-humble/examples/people](https://github.com/go-humble/examples/tree/master/people) for an example of
33 | how shared templates can work.
34 |
35 |
36 | Browser Support
37 | ---------------
38 |
39 | Temple is regularly tested with IE9+ and the latest versions of Chrome, Safari, and Firefox.
40 |
41 | Javascript code generated with gopherjs uses typed arrays, so in order to work with IE9,
42 | you will need a
43 | [polyfill for typed arrays](https://github.com/inexorabletash/polyfill/blob/master/typedarray.js).
44 |
45 |
46 | Installation
47 | ------------
48 |
49 | Install the temple command line tool with the following.
50 |
51 | ```bash
52 | go get -u github.com/go-humble/temple
53 | ```
54 |
55 | You may also need to install gopherjs. The latest version is recommended. Install
56 | gopherjs with:
57 |
58 | ```bash
59 | go get -u github.com/gopherjs/gopherjs
60 | ```
61 |
62 |
63 | Usage Guide
64 | -----------
65 |
66 | ### Basic Usage
67 |
68 | The temple command line tool has one main subcommand called `build`. Typical usage will look
69 | something like this:
70 |
71 | `temple build templates templates/templates.go`
72 |
73 | The first argument, in this case `templates`, is a directory which contains your .tmpl files.
74 | The second argument, in this case `templates/templates.go` is the name of a file where generated
75 | code will be written. If the file does not exist, temple will create it for you, and any previous
76 | content will be overwritten.
77 |
78 | You can run `temple help` to learn more about the possible commands and `temple help build` to
79 | learn more about the build command specifically.
80 |
81 | ### Generated Code
82 |
83 | The code generated by the temple command line tool will look something like this:
84 |
85 | ```go
86 | package templates
87 |
88 | // This package has been automatically generated with temple.
89 | // Do not edit manually!
90 |
91 | import (
92 | "github.com/go-humble/temple/temple"
93 | )
94 |
95 | var (
96 | GetTemplate func(name string) (*temple.Template, error)
97 | GetPartial func(name string) (*temple.Partial, error)
98 | GetLayout func(name string) (*temple.Layout, error)
99 | MustGetTemplate func(name string) *temple.Template
100 | MustGetPartial func(name string) *temple.Partial
101 | MustGetLayout func(name string) *temple.Layout
102 | )
103 |
104 | func init() {
105 | var err error
106 | g := temple.NewGroup()
107 |
108 | if err = g.AddPartial("head", `...`); err != nil {
109 | panic(err)
110 | }
111 |
112 | if err = g.AddLayout("app", `...`); err != nil {
113 | panic(err)
114 | }
115 |
116 | if err = g.AddTemplate("people/index", `...`); err != nil {
117 | panic(err)
118 | }
119 |
120 | GetTemplate = g.GetTemplate
121 | GetPartial = g.GetPartial
122 | GetLayout = g.GetLayout
123 | MustGetTemplate = g.MustGetTemplate
124 | MustGetPartial = g.MustGetPartial
125 | MustGetLayout = g.MustGetLayout
126 | }
127 | ```
128 |
129 | The code creates a single template [`Group`](http://godoc.org/github.com/go-humble/temple/temple/#Group)
130 | and adds the templates, partials, and layouts (if applicable) to the group. Then it exposes the methods of
131 | the group for getting templates, partials, and layouts as exported global functions.
132 |
133 | The [temple.Template](http://godoc.org/github.com/go-humble/temple/temple/#Template),
134 | [temple.Partial](http://godoc.org/github.com/go-humble/temple/temple/#Partial), and
135 | [temple.Layout](http://godoc.org/github.com/go-humble/temple/temple/#Layout) types all inherit from
136 | the builtin
137 | [Template type from the html/template package](http://golang.org/pkg/html/template/#Template). That
138 | means you can render them like regular templates with the
139 | [`Execute`](http://golang.org/pkg/html/template/#Template.Execute) method. Temple also provides an
140 | additional method for rendering templates in the dom called
141 | [`ExecuteEl`](http://godoc.org/github.com/go-humble/temple/temple/#ExecuteEl).
142 |
143 | ### Naming conventions
144 |
145 | In go, every template needs to have a name. temple assigns a name to each template based on its
146 | filename and location relative to the src directory. So for example, if you had a template file
147 | located at `templates/people/show.tmpl` and `templates` was your src directory, the name assigned
148 | to the template would be `"people/show"`.
149 |
150 | ### Partials and Layouts
151 |
152 | Temple uses two optional groups called "partials" and "layouts" to help organize template files.
153 | You can specify a directory that contains partials with the `--partials` flag, and a directory
154 | that contains layouts with the `--layouts` flag. Any .tmpl files found in these directories will
155 | be treated specially, and they should not overlap with each other or the src directory with all
156 | your regular templates ("regular templates" is the name we'll use to refer to .tmpl files in the
157 | src directory that are neither partials or layouts). This organization feature is completely optional,
158 | so if you don't want to use it, you omit the `--partials` and `--layouts` flags and manage your
159 | templates any way you want.
160 |
161 | Before continuing, it is recommended that you read the documentation for the
162 | [text/template](http://golang.org/pkg/text/template/) and
163 | [html/template](http://golang.org/pkg/html/template/) packages. In addition, this
164 | article about
165 | [template inheritence in go](https://elithrar.github.io/article/approximating-html-template-inheritance/)
166 | will help explain some of the concepts that temple uses.
167 |
168 | #### Partials
169 |
170 | Partials are templates which typically represent only part of a full page. For example, you might
171 | have a partial for rendering a single model or a partial for the head section of your html. Partials
172 | are associated with (i.e., added to the parse tree of) all other partials, in addition to layouts and
173 | regular templates. That means you can render a partial inside of a regular template or layout with the
174 | `template` action. The name of the partial templates is based on its filename and location relative to the
175 | partials directory. [`PartialsPrefix`](http://godoc.org/github.com/albrow/prtty#pkg-variables) is added
176 | to the template name of all partials, which by default is simply `"partials/"`.
177 |
178 | So if your partials directory is `my-partials`, and you have the following partial template file located
179 | at `my-partials/head.tmpl`:
180 |
181 | ```handlebars
182 |
183 | Example Humble Application
184 |
185 |
186 | ```
187 |
188 | You could render it inside of another template like so:
189 |
190 | ```handlebars
191 |
192 |
193 | {{ template "partials/head" }}
194 |
195 |
196 |
197 | ```
198 |
199 | Check out the partials in
200 | [go-humble/examples/people](https://github.com/go-humble/examples/tree/master/people/shared/templates/partials)
201 | for a more in-depth example.
202 |
203 | #### Layouts
204 |
205 | Layouts are templates which define the structure for a page and require another template to fill in
206 | the details. Typically, layouts will use one or more `template` actions to render partials or regular
207 | templates inside of some structure. Layouts are associated with (i.e., added to the parse tree of) all
208 | regular templates and have access to partials. That means you can render layouts inside of a regular template,
209 | typically after declaring some sub-template that the layout expects to be defined. The name of the layout
210 | templates is based on its filename and location relative to the layouts directory.
211 | [`LayoutsPrefix`](http://godoc.org/github.com/go-humble/temple#pkg-variables) is added to the template
212 | name of all layouts, which by default is simply `"layouts/"`.
213 |
214 | For example, if your layouts directory is `my-layouts`, and you have the following layout template file
215 | located at `my-layouts/app.tmpl`:
216 |
217 | ```handlebars
218 |
219 |
220 |
221 | Example Humble Application
222 |
223 |
224 | {{ template "content" }}
225 |
226 |
227 | ```
228 |
229 | You could then render a template inside of the layout by first defining the "content" sub-template and
230 | then rendering the layout:
231 |
232 | ```handlebars
233 | {{ define "content" }}
234 | Hello, Content!
235 | {{ end }}
236 | {{ template "layouts/app" }}
237 | ```
238 |
239 | If you rendered the template (not the layout), the output would look like this:
240 |
241 | ```html
242 |
243 |
244 |
245 | Example Humble Application
246 |
247 |
248 | Hello, Content!
249 |
250 |
251 | ```
252 |
253 | Check out the layouts in
254 | [go-humble/examples/people](https://github.com/go-humble/examples/tree/master/people/shared/templates/layouts)
255 | for a more in-depth example.
256 |
257 | Testing
258 | -------
259 |
260 | Temple uses regular go testing, so you can run the all the tests with `go test ./...`.
261 |
262 |
263 | Contributing
264 | ------------
265 |
266 | See [CONTRIBUTING.md](https://github.com/go-humble/temple/blob/master/CONTRIBUTING.md)
267 |
268 |
269 | License
270 | -------
271 |
272 | Temple is licensed under the MIT License. See the [LICENSE](https://github.com/go-humble/temple/blob/master/LICENSE)
273 | file for more information.
274 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Alex Browne.
2 | // All rights reserved. Use of this source code is
3 | // governed by the MIT license, which can be found
4 | // in the LICENSE file.
5 |
6 | // Temple is a command-line tool for managing go templates which
7 | // supports sharing templates between a client and server. It generates
8 | // code which is compatible with gopherjs and can be compiled to
9 | // javascript to run in the browser.
10 | //
11 | // Version 0.1.3
12 | package main
13 |
14 | import (
15 | "fmt"
16 | "io/ioutil"
17 | "os"
18 |
19 | "github.com/albrow/prtty"
20 | "github.com/go-humble/temple/temple"
21 | "github.com/spf13/cobra"
22 | )
23 |
24 | const (
25 | version = "temple version 0.1.1"
26 | )
27 |
28 | var (
29 | verbose = false
30 | )
31 |
32 | // setQuiet effectively causes all loggers to print
33 | // to /dev/null. However, error will still be printed
34 | // out to stderr.
35 | func setQuiet() {
36 | prtty.AllLoggers.SetOutput(ioutil.Discard)
37 | prtty.Error.Output = os.Stderr
38 | }
39 |
40 | // setVerbose sets all loggers to print to stdout,
41 | // except for the Error logger, which will print to
42 | // stderr.
43 | func setVerbose() {
44 | prtty.AllLoggers.SetOutput(os.Stdout)
45 | prtty.Error.Output = os.Stderr
46 | }
47 |
48 | func main() {
49 | // Define build command
50 | cmdBuild := &cobra.Command{
51 | Use: "build ",
52 | Short: "Compile the templates in the src directory and write generated go code to the dest file.",
53 | Long: ``,
54 | Run: func(cmd *cobra.Command, args []string) {
55 | if len(args) != 2 {
56 | prtty.Error.Fatal("temple build requires exactly 2 arguments: the src directory and the dest file.")
57 | }
58 | if verbose {
59 | setVerbose()
60 | } else {
61 | setQuiet()
62 | }
63 | partials := cmd.Flag("partials").Value.String()
64 | layouts := cmd.Flag("layouts").Value.String()
65 | packageName := cmd.Flag("package").Value.String()
66 | if err := temple.Build(args[0], args[1], partials, layouts, packageName); err != nil {
67 | prtty.Error.Fatal(err)
68 | }
69 | },
70 | }
71 | cmdBuild.Flags().String("partials", "", "(optional) The directory to look for partials. Partials are .tmpl files that are associated with layouts and all other templates.")
72 | cmdBuild.Flags().String("layouts", "", "(optional) The directory to look for layouts. Layouts are .tmpl files which have access to partials and are associated with all other templates.")
73 | cmdBuild.Flags().String("package", "", "(optional) The package name for the generated go file. If not provided, the default will be the directory where the go file is created.")
74 | cmdBuild.Flags().BoolVarP(&verbose, "verbose", "v", false, "If set to true, temple will print out information while building.")
75 |
76 | // Define version command
77 | cmdVersion := &cobra.Command{
78 | Use: "version",
79 | Short: "Print the current version number.",
80 | Run: func(cmd *cobra.Command, args []string) {
81 | fmt.Println(version)
82 | },
83 | }
84 |
85 | // Define the root command
86 | rootCmd := &cobra.Command{
87 | Use: "temple",
88 | Short: "A command line tool for sharing go templates between a client and server.",
89 | Long: `
90 | A command line tool for sharing go templates between a client and server.
91 | Visit https://github.com/albrow/temple for source code, example usage, documentation, and more.`,
92 | }
93 | rootCmd.AddCommand(cmdBuild, cmdVersion)
94 | if err := rootCmd.Execute(); err != nil {
95 | prtty.Error.Fatal(err)
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/temple/README.md:
--------------------------------------------------------------------------------
1 | Humble/Temple
2 | =============
3 |
4 | [](https://godoc.org/github.com/go-humble/temple/temple)
5 |
6 | Version 0.1.3
7 |
8 | A library and a command line tool for sanely managing go templates, with the ability
9 | to share them between client and server. The library and code generated by the cli are
10 | both compatible with [gopherjs](https://github.com/gopherjs/gopherjs), so you can compile
11 | to javascript and run in the browser. Temple works great as a stand-alone package or in
12 | combination with other packages in the [Humble Framework](https://github.com/go-humble/humble).
13 |
14 | This README is specific to the library, which offers helper functions and methods for
15 | managing templates and rendering them in the DOM. The README for the command line
16 | tool can be found at
17 | [github.com/go-humble/temple](https://github.com/go-humble/temple).
18 |
19 |
20 | What Does the Library Do?
21 | -------------------------
22 |
23 | The temple library can be used on its own or in conjunction with code generated by the
24 | command line tool. It offers some utility functions for organizing templates into distinct
25 | categories: regular templates, partials, and layouts. It also lets you load templates from
26 | files or load inline templates from the DOM, and provides helper methods for rendering
27 | to the DOM.
28 |
29 | Temple uses the builtin [html/template package](http://golang.org/pkg/html/template/).
30 | If you are not already familiar with go's builtin templates, it is highly recommended
31 | that you read the documentation for them before continuing.
32 |
33 |
34 | Browser Support
35 | ---------------
36 |
37 | Temple is regularly tested with IE9+ and the latest versions of Chrome, Safari, and Firefox.
38 |
39 | Javascript code generated with gopherjs uses typed arrays, so in order to work with IE9,
40 | you will need a
41 | [polyfill for typed arrays](https://github.com/inexorabletash/polyfill/blob/master/typedarray.js).
42 |
43 |
44 | Installation
45 | ------------
46 |
47 | Install the temple library with the following.
48 |
49 | ```bash
50 | go get github.com/go-humble/temple/temple`
51 | ```
52 |
53 | You may also need to install gopherjs. The latest version is recommended. Install
54 | gopherjs with:
55 |
56 | ```
57 | go get -u github.com/gopherjs/gopherjs
58 | ```
59 |
60 |
61 | Quickstart Guide
62 | ----------------
63 |
64 | ### Loading Templates
65 |
66 | All templates, partials, and layouts must belong to a group. To create a new group, use
67 | the `NewGroup` function:
68 |
69 | ```go
70 | g := NewGroup()
71 | ```
72 |
73 | #### From a String
74 |
75 | To add template to the group, you can use the `AddTemplate` method. It takes
76 | two arguments, the name of the template and the source.
77 |
78 | ```go
79 | if err := g.AddTemplate("home", "
Home
"); err != nil {
80 | // Handle err
81 | }
82 | ```
83 |
84 | #### From a File
85 |
86 | To add a template file, you can use the `AddTemplateFile` method, which takes the name of
87 | the template and the path to the file as an argument.
88 |
89 | ```go
90 | if err := g.AddTemplateFile("home", "templates/home.tmpl"); err != nil {
91 | // Handle err
92 | }
93 | ```
94 |
95 | #### From a Directory
96 |
97 | You can also add multiple files in a directory at once with the `AddTemplateFiles` method.
98 | When you use this method, the templates created from the files will automatically get a
99 | name based on the filename and location relative to the given directory. So for example,
100 | if you had a template file located at `templates/people/show.tmpl` and passed `templates`
101 | as the `dir` argument, the name assigned to the template would be `"people/show"`.
102 |
103 | ```go
104 | if err := g.AddTemplateFiles("templates"); err != nil {
105 | // Handle err
106 | }
107 | ```
108 |
109 | #### From the DOM
110 |
111 | Finally, if you compile to javascript with gopherjs, you can load inline templates from the
112 | DOM with the `AddInlineTemplate` method.
113 |
114 | ```go
115 | if err := g.AddInlineTemplate(document.QuerySelector("script[type='text/template']#home")); err != nil {
116 | // Handle err
117 | }
118 | ```
119 |
120 | The method expects a `dom.Element` from the gopherjs
121 | [dom bindings](http://godoc.org/honnef.co/go/js/dom) as an argument. Typically this would be
122 | a script tag that looks something like:
123 |
124 | ```
125 |
128 | ```
129 |
130 | The `AddInlineTemplate` method will use the id property of the element as the template name,
131 | and the innerHTML of the given element as the template source.
132 |
133 | You can also load multiple inline templates (as well as partials and layouts) at once with
134 | the [`AddAllInline`](http://godoc.org/github.com/go-humble/temple/temple/#Group.AddAllInline)
135 | method, which scans the DOM for script tags with a `type` attribute of "text/template".
136 |
137 | ```go
138 | if err := g.AddAllInline(); err != nil {
139 | // Handle err
140 | }
141 | ```
142 |
143 | It uses the id property as the template name, and the special `data-kind` attribute to
144 | distinguish between regular templates, partials, and layouts.
145 |
146 |
147 | ### Getting Templates
148 |
149 | Once a template has been added to a group, you can get it with the `GetTemplate` method:
150 |
151 | ```go
152 | homeTmpl, err := g.GetTemplate("home")
153 | if err != nil {
154 | // Handle error
155 | }
156 | ```
157 |
158 | This returns a pointer to a [`temple.Template`](http://godoc.org/github.com/go-humble/temple/temple/#Template),
159 | which is merely a wrapper around the [`template.Template`](http://golang.org/pkg/html/template/#Template)
160 | type from the builtin html/template package. `temple.Template` has all the same methods as a
161 | builtin template, and also introduces an
162 | [`ExecuteEl`](http://godoc.org/github.com/go-humble/temple/temple/#Layout.ExecuteEl) method for
163 | rendering the template to the DOM.
164 |
165 | In some cases, you just want to fail fast if a template is not found. You can use the
166 | `MustGetTemplate` method, which will panic instead of returning an error. This is analogous
167 | to the [`Temlate.Must`](http://golang.org/pkg/text/template/#Must) method in the text/template
168 | and html/template packages in the standard library, and is useful for variable declarations.
169 |
170 | ```go
171 | var (
172 | homeTmpl = g.MustGetTemplate("home")
173 | indexTmpl = g.MustGetTemplate("index")
174 | todoTmpl = g.MustGetTemplate("todo")
175 | )
176 | ```
177 |
178 | ### Rendering Templates
179 |
180 | #### To an io.Writer
181 |
182 | To render a template to an `io.Writer`, you can just use the `Execute` method. Since
183 | `http.ResponseWriter` implements `io.Writer` it is common to render templates this way on
184 | the server:
185 |
186 | ```go
187 | func HomeHandler(res http.ResponseWriter, req *http.Request) {
188 | homeTmpl, err := g.GetTemplate("home")
189 | if err != nil {
190 | // Handle error
191 | }
192 | if err := homeTmpl.Execute(res, nil); err != nil {
193 | // Handle error
194 | }
195 | }
196 | ```
197 |
198 | The second argument to `Execute` is the data that will be passed into the template.
199 |
200 | #### To an Element in the DOM
201 |
202 | You can also render a template to an element in the DOM with the `ExecuteEl` method. This
203 | is the most common way to render templates for code which has been compiled to javascript
204 | with gopherjs and is running in the browser.
205 |
206 | ```go
207 | homeTmpl, err := g.GetTemplate("home")
208 | if err != nil {
209 | // Handle error
210 | }
211 | if err := homeTmpl.ExecuteEl(document.QuerySelector("body"), nil); err != nil {
212 | // Handle err
213 | }
214 | ```
215 |
216 | ### Partials and Layouts
217 |
218 | Temple uses two optional groups called "partials" and "layouts" to help organize templates.
219 | To add partials or layouts, use the same methods for adding templates, but replace the word
220 | `Template` with `Partial` or `Layout` (e.g. `AddLayout`, `AddInlinePartials`, `AddLayoutFile`).
221 |
222 | Before continuing, it is recommended that you read the documentation for the
223 | [text/template](http://golang.org/pkg/text/template/) and
224 | [html/template](http://golang.org/pkg/html/template/) packages. In addition, this
225 | article about
226 | [template inheritence in go](https://elithrar.github.io/article/approximating-html-template-inheritance/)
227 | will help explain some of the concepts that temple uses.
228 |
229 | #### Partials
230 |
231 | Partials are templates which typically represent only part of a full page. For example, you might
232 | have a partial for rendering a single model or a partial for the head section of your html. Partials
233 | are associated with (i.e., added to the parse tree of) all other partials, in addition to layouts and
234 | regular templates. That means you can render a partial inside of a regular template or layout with the
235 | `template` action. [`PartialsPrefix`](http://godoc.org/github.com/albrow/prtty#pkg-variables) is added
236 | to the template name of all partials, which by default is simply `"partials/"`.
237 |
238 | So for example, you could have partials located in the `my-partials` directory and add them to a group
239 | with `g.AddPartialFiles("my-partials")`. Let's say you have the following partial file located at
240 | `my-partials/head.tmpl`:
241 |
242 | ```handlebars
243 |
244 | Example Humble Application
245 |
246 |
247 | ```
248 |
249 | Let's also say that you have regular template files located in the `my-templates` directory, which you
250 | have added to the same group with `g.AddTemplateFiles("my-templates")`. And the following regular template
251 | located at `my-templates/index.tmpl`:
252 |
253 | ```handlebars
254 |
255 |
256 | {{ template "partials/head" }}
257 |
258 |
259 |
260 | ```
261 |
262 | Then, if you rendered the template with the following code:
263 |
264 | ```go
265 | indexTmpl, err := g.GetTemplate("index")
266 | if err != nil {
267 | // Handle error
268 | }
269 | if err := indexTmpl.Execute(os.Stdout, nil); err != nil {
270 | // Handle err
271 | }
272 | ```
273 |
274 | You would see the following output:
275 |
276 | ```
277 |
278 |
279 |
280 | Example Humble Application
281 |
282 |
283 |
284 |
285 |
286 | ```
287 |
288 | Check out the partials in
289 | [go-humble/examples/people](https://github.com/go-humble/examples/tree/master/people/shared/templates/partials)
290 | for a more in-depth example.
291 |
292 | #### Layouts
293 |
294 | Layouts are templates which define the structure for a page and require another template to fill in
295 | the details. Typically, layouts will use one or more `template` actions to render partials or regular
296 | templates inside of some structure. Layouts are associated with (i.e., added to the parse tree of) all
297 | regular templates and have access to partials. That means you can render layouts inside of a regular template,
298 | typically after declaring some sub-template that the layout expects to be defined.
299 | [`LayoutsPrefix`](http://godoc.org/github.com/go-humble/temple#pkg-variables) is added to the template
300 | name of all layouts, which by default is simply `"layouts/"`.
301 |
302 | So for example, you could have layouts located in the `my-layouts` directory, and add them to a group
303 | with `g.AddLayoutFiles("my-layouts")`. Let's say you have the following layout file located at
304 | `my-layouts/app.tmpl`:
305 |
306 | ```handlebars
307 |
308 |
309 |
310 | Example Humble Application
311 |
312 |
313 | {{ template "content" . }}
314 |
315 |
316 | ```
317 |
318 | Let's also say that you have regular template files located in the `my-templates` directory, which you
319 | have added to the same group with `g.AddTemplateFiles("my-templates")`. And the following regular template
320 | located at `my-templates/hello.tmpl`:
321 |
322 | ```handlebars
323 | {{ define "content" }}
324 | Hello, {{ . }}!
325 | {{ end }}
326 | {{ template "layouts/app" . }}
327 | ```
328 |
329 | Notice that we used the `.` in both the `{{ template "content" . }}` and the `{{ template "layouts/app" . }}`
330 | expressions to pass in the template data from the regular template to the layout. If you
331 | rendered the template with the following code:
332 |
333 | ```go
334 | helloTmpl, err := g.GetTemplate("hello")
335 | if err != nil {
336 | // Handle error
337 | }
338 | if err := helloTmpl.Execute(os.Stdout, "World"); err != nil {
339 | // Handle err
340 | }
341 | ```
342 |
343 | You would see output that looked like this:
344 |
345 | ```html
346 |
347 |
348 |
349 | Example Humble Application
350 |
351 |
352 | Hello, World!
353 |
354 |
355 | ```
356 |
357 | Check out the layouts in
358 | [go-humble/examples/people](https://github.com/go-humble/examples/tree/master/people/shared/templates/layouts)
359 | for a more in-depth example.
360 |
361 | Testing
362 | -------
363 |
364 | Temple uses regular go testing, so you can run the all the tests with `go test .`.
365 |
366 |
367 | Contributing
368 | ------------
369 |
370 | See [CONTRIBUTING.md](https://github.com/go-humble/temple/blob/master/CONTRIBUTING.md)
371 |
372 |
373 | License
374 | -------
375 |
376 | Temple is licensed under the MIT License. See the [LICENSE](https://github.com/go-humble/temple/blob/master/LICENSE)
377 | file for more information.
378 |
--------------------------------------------------------------------------------
/temple/assets/bindata.go:
--------------------------------------------------------------------------------
1 | package assets
2 |
3 | import (
4 | "bytes"
5 | "compress/gzip"
6 | "fmt"
7 | "io"
8 | "strings"
9 | "os"
10 | "time"
11 | "io/ioutil"
12 | "path"
13 | "path/filepath"
14 | )
15 |
16 | func bindata_read(data []byte, name string) ([]byte, error) {
17 | gz, err := gzip.NewReader(bytes.NewBuffer(data))
18 | if err != nil {
19 | return nil, fmt.Errorf("Read %q: %v", name, err)
20 | }
21 |
22 | var buf bytes.Buffer
23 | _, err = io.Copy(&buf, gz)
24 | clErr := gz.Close()
25 |
26 | if err != nil {
27 | return nil, fmt.Errorf("Read %q: %v", name, err)
28 | }
29 | if clErr != nil {
30 | return nil, err
31 | }
32 |
33 | return buf.Bytes(), nil
34 | }
35 |
36 | type asset struct {
37 | bytes []byte
38 | info os.FileInfo
39 | }
40 |
41 | type bindata_file_info struct {
42 | name string
43 | size int64
44 | mode os.FileMode
45 | modTime time.Time
46 | }
47 |
48 | func (fi bindata_file_info) Name() string {
49 | return fi.name
50 | }
51 | func (fi bindata_file_info) Size() int64 {
52 | return fi.size
53 | }
54 | func (fi bindata_file_info) Mode() os.FileMode {
55 | return fi.mode
56 | }
57 | func (fi bindata_file_info) ModTime() time.Time {
58 | return fi.modTime
59 | }
60 | func (fi bindata_file_info) IsDir() bool {
61 | return false
62 | }
63 | func (fi bindata_file_info) Sys() interface{} {
64 | return nil
65 | }
66 |
67 | var _templates_generated_go_tmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x53\x4d\x6f\xdb\x38\x10\x3d\x8b\xbf\x62\xe2\x93\x1c\x78\xa5\xdd\x05\xf6\x92\x45\x0e\x69\x1a\x04\x01\x12\x37\x40\xdc\x7b\x68\x6a\x2c\xb1\x95\x48\x81\x1c\xda\x31\x0c\xff\xf7\x0e\x25\xd9\xb1\xf3\xe1\x53\x7b\xb2\xc9\x79\x6f\xde\xe3\xcc\xd3\x66\x93\x9f\x8b\xe4\xda\xb6\x6b\xa7\xcb\x8a\xe0\xdf\xbf\xff\xf9\x0f\xae\x6a\x7c\x81\x2f\xce\xae\x0c\x66\x22\xb9\xaa\x6b\xe8\x8a\x1e\x1c\x7a\x74\x4b\x2c\x32\xf8\xee\x11\xec\x02\xa8\xd2\x1e\xbc\x0d\x4e\x21\x28\x5b\x20\x68\x2f\x92\xd2\x2e\xd1\x19\x2c\x60\xbe\x66\x00\xc2\xc3\xdd\x0c\x6a\xad\xd0\x78\x9c\xc0\xaa\xd2\xaa\x02\x25\x0d\xcc\x11\x16\x36\x98\x42\x24\xda\x74\xb8\xfb\xbb\xeb\x9b\xe9\xd3\x0d\x2c\x74\xcd\xba\x22\x99\x7e\x9b\xdd\x5c\xf4\x12\xf1\x8a\x7b\x03\x36\x73\x2c\x0a\x6e\xbd\xd4\x12\x4a\xfb\xd7\x5c\x9b\x42\x92\x84\xb4\x22\x6a\xfd\x45\x9e\x97\x9a\xaa\x30\xcf\x94\x6d\xf2\x1f\x84\x18\x56\x68\xf2\x57\xdc\x58\x24\x77\x0b\x58\xdb\x00\xaa\x92\xa6\xe4\x96\x34\x89\x3e\x7c\x70\x08\x64\xc1\x05\xc3\x5d\xa1\x44\x83\x4e\x12\x42\x96\x67\x59\xb6\xe7\x18\x64\x61\x46\x69\xe3\x49\xf2\x50\xa2\xe7\x03\x0f\xf8\x82\x2a\x90\x9c\xd7\xfc\xca\x7d\x23\x82\xd3\x8e\xc4\x79\xbe\xdd\x8a\x56\xaa\x9f\x92\xed\x6c\x36\x90\x3d\xf6\xff\xa7\xb2\x41\xe0\x92\xc8\x73\x98\xc5\x11\xec\x30\x95\xf4\x6c\x19\x0d\xc8\x40\xb6\x91\xa4\x15\x7b\x59\xef\x3d\x17\xb0\x62\x41\x20\x6c\xda\x38\x45\x66\x7f\xb5\x60\x2c\x01\x16\x9a\xa0\x91\x26\x44\xf8\x99\x10\xba\x69\xad\x23\x48\x45\x32\x3a\xb0\xc8\xce\xaa\xd0\xf0\x1b\xf2\xbe\xc3\xf0\x33\x12\x63\x21\x96\xd2\x45\xf8\x2d\xd2\x2c\x5e\xc6\x01\x2d\x82\x51\xa9\x89\x56\x3d\x39\x6d\xca\x31\xa4\xe7\x83\xf4\x0e\x33\x01\x74\xce\xba\x71\x47\x7c\x94\x8e\xb4\xac\x4f\xf1\x06\xc8\x11\xed\x5e\xf2\xfc\xe9\x14\xab\x47\xbc\x92\x1e\x82\xa7\xd3\x46\xdf\xfa\xdc\x73\x3e\xf7\xf8\xc6\xe2\x9e\xf1\xa9\xbd\x63\x77\x71\x86\x11\xc3\x01\xd2\x94\x8e\x61\x23\x92\x38\x52\xb6\xdc\xdb\xe6\x2f\x07\x2e\x2e\x77\xab\x9b\xe2\xea\xd6\xd9\xd0\xa6\xfc\x1a\xce\x85\xeb\xf2\xba\x93\xf6\x31\x1a\x89\x5e\x74\xe4\x4b\x28\xb3\xab\xa2\x18\x4a\xe9\x28\xa6\x68\x88\xcf\x68\x02\xcf\xf1\xf8\xe4\x14\x9f\x9e\xc7\xff\x77\x84\xb3\x4b\x30\xba\x8e\xfa\x49\x2b\x8d\x56\x29\x5f\xb2\xca\xb6\x13\x42\x53\x74\xb9\x3b\x10\xed\xed\x7f\xa4\xd9\x57\xfe\x80\xe4\x6e\x2b\x1f\x89\xee\x6a\xbf\x49\xf6\x28\xd0\x51\xe2\xe0\x7c\x14\xda\xa1\xb6\xdf\xfe\xeb\xe6\x87\xca\xb0\xe6\x77\xe1\x8b\xe5\x37\x77\xef\xd2\x76\x80\xf9\x24\x5e\x07\x88\x41\x68\xfb\x2b\x00\x00\xff\xff\x1e\x4e\x7e\x4b\xbe\x05\x00\x00")
68 |
69 | func templates_generated_go_tmpl_bytes() ([]byte, error) {
70 | return bindata_read(
71 | _templates_generated_go_tmpl,
72 | "templates/generated.go.tmpl",
73 | )
74 | }
75 |
76 | func templates_generated_go_tmpl() (*asset, error) {
77 | bytes, err := templates_generated_go_tmpl_bytes()
78 | if err != nil {
79 | return nil, err
80 | }
81 |
82 | info := bindata_file_info{name: "templates/generated.go.tmpl", size: 1470, mode: os.FileMode(420), modTime: time.Unix(1432862983, 0)}
83 | a := &asset{bytes: bytes, info: info}
84 | return a, nil
85 | }
86 |
87 | // Asset loads and returns the asset for the given name.
88 | // It returns an error if the asset could not be found or
89 | // could not be loaded.
90 | func Asset(name string) ([]byte, error) {
91 | cannonicalName := strings.Replace(name, "\\", "/", -1)
92 | if f, ok := _bindata[cannonicalName]; ok {
93 | a, err := f()
94 | if err != nil {
95 | return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
96 | }
97 | return a.bytes, nil
98 | }
99 | return nil, fmt.Errorf("Asset %s not found", name)
100 | }
101 |
102 | // MustAsset is like Asset but panics when Asset would return an error.
103 | // It simplifies safe initialization of global variables.
104 | func MustAsset(name string) []byte {
105 | a, err := Asset(name)
106 | if (err != nil) {
107 | panic("asset: Asset(" + name + "): " + err.Error())
108 | }
109 |
110 | return a
111 | }
112 |
113 | // AssetInfo loads and returns the asset info for the given name.
114 | // It returns an error if the asset could not be found or
115 | // could not be loaded.
116 | func AssetInfo(name string) (os.FileInfo, error) {
117 | cannonicalName := strings.Replace(name, "\\", "/", -1)
118 | if f, ok := _bindata[cannonicalName]; ok {
119 | a, err := f()
120 | if err != nil {
121 | return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
122 | }
123 | return a.info, nil
124 | }
125 | return nil, fmt.Errorf("AssetInfo %s not found", name)
126 | }
127 |
128 | // AssetNames returns the names of the assets.
129 | func AssetNames() []string {
130 | names := make([]string, 0, len(_bindata))
131 | for name := range _bindata {
132 | names = append(names, name)
133 | }
134 | return names
135 | }
136 |
137 | // _bindata is a table, holding each asset generator, mapped to its name.
138 | var _bindata = map[string]func() (*asset, error){
139 | "templates/generated.go.tmpl": templates_generated_go_tmpl,
140 | }
141 |
142 | // AssetDir returns the file names below a certain
143 | // directory embedded in the file by go-bindata.
144 | // For example if you run go-bindata on data/... and data contains the
145 | // following hierarchy:
146 | // data/
147 | // foo.txt
148 | // img/
149 | // a.png
150 | // b.png
151 | // then AssetDir("data") would return []string{"foo.txt", "img"}
152 | // AssetDir("data/img") would return []string{"a.png", "b.png"}
153 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error
154 | // AssetDir("") will return []string{"data"}.
155 | func AssetDir(name string) ([]string, error) {
156 | node := _bintree
157 | if len(name) != 0 {
158 | cannonicalName := strings.Replace(name, "\\", "/", -1)
159 | pathList := strings.Split(cannonicalName, "/")
160 | for _, p := range pathList {
161 | node = node.Children[p]
162 | if node == nil {
163 | return nil, fmt.Errorf("Asset %s not found", name)
164 | }
165 | }
166 | }
167 | if node.Func != nil {
168 | return nil, fmt.Errorf("Asset %s not found", name)
169 | }
170 | rv := make([]string, 0, len(node.Children))
171 | for childName := range node.Children {
172 | rv = append(rv, childName)
173 | }
174 | return rv, nil
175 | }
176 |
177 | type _bintree_t struct {
178 | Func func() (*asset, error)
179 | Children map[string]*_bintree_t
180 | }
181 | var _bintree = &_bintree_t{nil, map[string]*_bintree_t{
182 | "templates": &_bintree_t{nil, map[string]*_bintree_t{
183 | "generated.go.tmpl": &_bintree_t{templates_generated_go_tmpl, map[string]*_bintree_t{
184 | }},
185 | }},
186 | }}
187 |
188 | // Restore an asset under the given directory
189 | func RestoreAsset(dir, name string) error {
190 | data, err := Asset(name)
191 | if err != nil {
192 | return err
193 | }
194 | info, err := AssetInfo(name)
195 | if err != nil {
196 | return err
197 | }
198 | err = os.MkdirAll(_filePath(dir, path.Dir(name)), os.FileMode(0755))
199 | if err != nil {
200 | return err
201 | }
202 | err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
203 | if err != nil {
204 | return err
205 | }
206 | err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
207 | if err != nil {
208 | return err
209 | }
210 | return nil
211 | }
212 |
213 | // Restore assets under the given directory recursively
214 | func RestoreAssets(dir, name string) error {
215 | children, err := AssetDir(name)
216 | if err != nil { // File
217 | return RestoreAsset(dir, name)
218 | } else { // Dir
219 | for _, child := range children {
220 | err = RestoreAssets(dir, path.Join(name, child))
221 | if err != nil {
222 | return err
223 | }
224 | }
225 | }
226 | return nil
227 | }
228 |
229 | func _filePath(dir, name string) string {
230 | cannonicalName := strings.Replace(name, "\\", "/", -1)
231 | return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
232 | }
233 |
234 |
--------------------------------------------------------------------------------
/temple/build.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Alex Browne.
2 | // All rights reserved. Use of this source code is
3 | // governed by the MIT license, which can be found
4 | // in the LICENSE file.
5 |
6 | package temple
7 |
8 | import (
9 | "bytes"
10 | "errors"
11 | "github.com/albrow/prtty"
12 | "github.com/go-humble/temple/temple/assets"
13 | "go/format"
14 | "io/ioutil"
15 | "os"
16 | "path/filepath"
17 | "text/template"
18 | )
19 |
20 | // Build is the function called when you run the build sub-command
21 | // in the command line tool. It compiles all the templates in the
22 | // src directory and generates go code in the dest file. If partials
23 | // and/or layouts are provided, it will add them to the generated file
24 | // with calls to AddPartial and AddLayout. If packageName is an empty
25 | // string, the package name will be the directory of the dest file.
26 | func Build(src, dest, partials, layouts, packageName string) error {
27 | prtty.Info.Println("--> building...")
28 | prtty.Default.Printf(" src: %s", src)
29 | prtty.Default.Printf(" dest: %s", dest)
30 | if partials != "" {
31 | prtty.Default.Printf(" partials: %s", partials)
32 | }
33 | if layouts != "" {
34 | prtty.Default.Printf(" layouts: %s", layouts)
35 | }
36 | if packageName != "" {
37 | prtty.Default.Printf(" package: %s", packageName)
38 | }
39 | dirs := sourceDirGroup{
40 | templates: src,
41 | partials: partials,
42 | layouts: layouts,
43 | }
44 | if err := checkCompileTemplates(dirs); err != nil {
45 | return err
46 | }
47 | if err := generateFile(dirs, dest, packageName); err != nil {
48 | return err
49 | }
50 | prtty.Info.Println("--> done!")
51 | return nil
52 | }
53 |
54 | // checkCompileTemplates compiles the templates, partials, and layouts
55 | // in dirs with the correct associations to make sure that the templates
56 | // compile. If they don't, we can catch errors early and return them when
57 | // the command line tool is invoked, instead of at runtime.
58 | func checkCompileTemplates(dirs sourceDirGroup) error {
59 | prtty.Info.Println("--> checking for compilation errors...")
60 | if dirs.templates == "" {
61 | return errors.New("temple: templates dir cannot be an empty string.")
62 | }
63 | g := NewGroup()
64 | if dirs.partials != "" {
65 | prtty.Default.Println(" checking partials...")
66 | if err := g.AddPartialFiles(dirs.partials); err != nil {
67 | return err
68 | }
69 | }
70 | if dirs.layouts != "" {
71 | prtty.Default.Println(" checking layouts...")
72 | if err := g.AddLayoutFiles(dirs.layouts); err != nil {
73 | return err
74 | }
75 | }
76 | prtty.Default.Println(" checking templates...")
77 | if err := g.AddTemplateFiles(dirs.templates); err != nil {
78 | return err
79 | }
80 | return nil
81 | }
82 |
83 | // templateData is passed in to the template for the generated code.
84 | type templateData struct {
85 | PackageName string
86 | Templates []sourceFile
87 | Partials []sourceFile
88 | Layouts []sourceFile
89 | }
90 |
91 | // sourceFile represents the source file for a template, partial, or layout.
92 | type sourceFile struct {
93 | Name string
94 | Src string
95 | }
96 |
97 | // sourceDirGroup represents a group of source directories, consisting of a
98 | // directory for regular layouts and optionally for partials and layouts.
99 | // The directories for partials and layouts will be empty strings if they
100 | // were not provided.
101 | type sourceDirGroup struct {
102 | templates string
103 | partials string
104 | layouts string
105 | }
106 |
107 | // collectAllSourceFiles walks recursively through the directories in dirs
108 | // and collects all template, partial, and layout source files, adding them
109 | // to data.
110 | func (data *templateData) collectAllSourceFiles(dirs sourceDirGroup) error {
111 | if dirs.partials != "" {
112 | prtty.Info.Println("--> collecting partials...")
113 | partials, err := collectSourceFiles(dirs.partials)
114 | if err != nil {
115 | return err
116 | }
117 | data.Partials = partials
118 | }
119 | if dirs.layouts != "" {
120 | prtty.Info.Println("--> collecting layouts...")
121 | layouts, err := collectSourceFiles(dirs.layouts)
122 | if err != nil {
123 | return err
124 | }
125 | data.Layouts = layouts
126 | }
127 | prtty.Info.Println("--> collecting templates...")
128 | templates, err := collectSourceFiles(dirs.templates)
129 | if err != nil {
130 | return err
131 | }
132 | data.Templates = templates
133 | return nil
134 | }
135 |
136 | // generateFile generates go code containing the contents of all the
137 | // files in the sourceDirGroup and writes the code to the dest file. It
138 | // uses the given packageName if it is non-empty, and otherwise falls back
139 | // to the directory that dest is in. If a file already exists at dest, it
140 | // will be overwritten.
141 | func generateFile(dirs sourceDirGroup, dest, packageName string) error {
142 | prtty.Info.Println("--> generating go code...")
143 | if packageName == "" {
144 | packageName = filepath.Base(filepath.Dir(dest))
145 | }
146 | data := &templateData{
147 | PackageName: packageName,
148 | }
149 | if err := data.collectAllSourceFiles(dirs); err != nil {
150 | return err
151 | }
152 | if err := data.writeToFile(dest); err != nil {
153 | return err
154 | }
155 | return nil
156 | }
157 |
158 | //go:generate go-bindata --pkg=assets -o=assets/bindata.go templates/...
159 |
160 | // writeToFile writes the given templateData to the file located
161 | // at dest. It uses the template located at templates/generated.go.tmpl.
162 | // If there is already a file located at dest, it will be overwritten.
163 | func (data *templateData) writeToFile(dest string) error {
164 | tmplAsset, err := assets.Asset("templates/generated.go.tmpl")
165 | if err != nil {
166 | return err
167 | }
168 | generatedTmpl := template.Must(template.New("generated").Parse(string(tmplAsset)))
169 | buf := bytes.NewBuffer([]byte{})
170 | if err := generatedTmpl.Execute(buf, data); err != nil {
171 | return err
172 | }
173 | formatted, err := format.Source(buf.Bytes())
174 | if err != nil {
175 | return err
176 | }
177 | prtty.Success.Printf(" created %s", dest)
178 | return ioutil.WriteFile(dest, formatted, os.ModePerm)
179 | }
180 |
181 | // collectSourceFiles recursively walks through dir and its subdirectories
182 | // and returns an array of all the source files (files which end in .tmpl).
183 | func collectSourceFiles(dir string) ([]sourceFile, error) {
184 | sourceFiles := []sourceFile{}
185 | if err := collectTemplateFiles(dir, func(name, filename string) error {
186 | src, err := ioutil.ReadFile(filename)
187 | if err != nil {
188 | return err
189 | }
190 | prtty.Default.Printf(" %s", filename)
191 | sourceFiles = append(sourceFiles, sourceFile{
192 | Name: name,
193 | Src: string(src),
194 | })
195 | return nil
196 | }); err != nil {
197 | return nil, err
198 | }
199 | return sourceFiles, nil
200 | }
201 |
--------------------------------------------------------------------------------
/temple/build_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Alex Browne.
2 | // All rights reserved. Use of this source code is
3 | // governed by the MIT license, which can be found
4 | // in the LICENSE file.
5 |
6 | package temple
7 |
8 | import (
9 | "os/exec"
10 | "testing"
11 | )
12 |
13 | const (
14 | destFile = "test_files/templates.go"
15 | runFile = "test_files/run.go"
16 | )
17 |
18 | func TestBuild(t *testing.T) {
19 | // Generate a go source file with build
20 | if err := Build("test_files/templates", destFile, "test_files/partials", "test_files/layouts", "main"); err != nil {
21 | t.Error(err)
22 | }
23 | // Use go run to run the file together with the run file
24 | cmd := exec.Command("go", "run", destFile, runFile)
25 | output, err := cmd.CombinedOutput()
26 | if err != nil {
27 | t.Error(err)
28 | }
29 | expected := "Todos
One
Two
Three
"
30 | if string(output) != expected {
31 | t.Errorf("Output from generated code was not correct.\nExpected %s\nBut got: %s", expected, string(output))
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/temple/doc.go:
--------------------------------------------------------------------------------
1 | // Package temple is a library for managing go templates which
2 | // supports sharing templates between a client and server. It
3 | // is the library that powers the temple command line tool.
4 | // Temple provides lets you load templates from files or load
5 | // inline templates from the DOM. It also optionally organizes
6 | // templates into regular templates, partials, and layouts, associating
7 | // each template with other templates depending on which category
8 | // it belongs to. Temple is compatible with gopherjs and can be
9 | // compiled to javascript and run in a browser.
10 | //
11 | // Version 0.1.3
12 | package temple
13 |
--------------------------------------------------------------------------------
/temple/dom.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Alex Browne.
2 | // All rights reserved. Use of this source code is
3 | // governed by the MIT license, which can be found
4 | // in the LICENSE file.
5 |
6 | package temple
7 |
8 | import (
9 | "bytes"
10 | "honnef.co/go/js/dom"
11 | )
12 |
13 | // ExecuteEl executes an Executor with the given data and then
14 | // writes the result to the innerHTML of el. It only works if
15 | // you have compiled this code to javascript with gopherjs and
16 | // it is running in a browser.
17 | func ExecuteEl(e Executor, el dom.Element, data interface{}) error {
18 | // TODO: use a buffer pool
19 | buf := bytes.NewBuffer([]byte{})
20 | if err := e.Execute(buf, data); err != nil {
21 | return err
22 | }
23 | el.SetInnerHTML(buf.String())
24 | return nil
25 | }
26 |
27 | // ExecuteEl executes the template with the given data and then
28 | // writes the result to the innerHTML of el. It only works if
29 | // you have compiled this code to javascript with gopherjs and
30 | // it is running in a browser.
31 | func (t *Template) ExecuteEl(el dom.Element, data interface{}) error {
32 | return ExecuteEl(t, el, data)
33 | }
34 |
35 | // ExecuteEl executes the partial with the given data and then
36 | // writes the result to the innerHTML of el. It only works if
37 | // you have compiled this code to javascript with gopherjs and
38 | // it is running in a browser.
39 | func (p *Partial) ExecuteEl(el dom.Element, data interface{}) error {
40 | return ExecuteEl(p, el, data)
41 | }
42 |
43 | // ExecuteEl executes the layout with the given data and then
44 | // writes the result to the innerHTML of el. It only works if
45 | // you have compiled this code to javascript with gopherjs and
46 | // it is running in a browser.
47 | func (l *Layout) ExecuteEl(el dom.Element, data interface{}) error {
48 | return ExecuteEl(l, el, data)
49 | }
50 |
51 | // AddAllInline scans the DOM for inline templates which
52 | // must be script tags with the type "text/template". The id property
53 | // will be used for the name of each template, and the special
54 | // property "data-kind" can be used to distinguish between regular
55 | // templates, partials, and layouts. So, to declare an inline partial
56 | // for use with the AddAllInline method, use an opening script
57 | // tag that looks like:
58 | //