github.com/goradd/got@v1.1.1/README.md (about)

     1  [![Go Reference](https://pkg.go.dev/badge/github.com/goradd/got.svg)](https://pkg.go.dev/github.com/goradd/got)
     2  ![Build Status](https://img.shields.io/github/actions/workflow/status/goradd/got/go.yml?branch=main)
     3  [![codecov](https://codecov.io/gh/goradd/got/branch/main/graph/badge.svg?token=FHU0NR2N1V)](https://codecov.io/gh/goradd/got)
     4  [![Go Report Card](https://goreportcard.com/badge/github.com/goradd/got)](https://goreportcard.com/report/github.com/goradd/got)
     5  [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#template-engines)
     6  # GoT
     7  
     8  GoT (short for Go Templates) is a flexible template engine that generates Go code.
     9  
    10  This approach creates extremely fast templates. It also gives you much more freedom than Go's template
    11  engine, since at any time you can just switch to Go code to do what you want.
    12  
    13  GoT has:
    14  - Mustache-like syntax similar to Go's built-in template engine
    15  - The ability to define new tags, so you can create your own template syntax
    16  - Include files, so you can create a library of tags and templates 
    17  
    18  The GoT syntax is easy to learn. Get started in minutes.
    19  
    20  - [Features](#features)
    21  - [Installation](#installation)
    22  - [Command Line Usage](#command-line-usage)
    23  - [Basic Syntax](#basic-syntax)
    24  - [Template Syntax](#template-syntax)
    25  - [License](#license)
    26  - [Acknowledgements](#acknowledgements)
    27  
    28  ## Features
    29  
    30  - **High performance**. Since the resulting template is go code, your template will be compiled to fast
    31  machine code.
    32  - **Easy to use**. The templates themselves are embedded into your go code. The template language is pretty 
    33  simple and you can do a lot with only a few tags. You can switch into and out of go code at will. Tags are 
    34  Mustache-like, so similar to Go's template engine.
    35  - **Flexible**. The template language makes very few assumptions about the go environment it is in. Most other
    36  template engines require you to call the template with a specific function signature. **GoT** gives you the
    37  freedom to call your templates how you want.
    38  - **Translation Support**. You can specify that you want to send your strings to a translator before 
    39  output.
    40  - **Error Support**. You can call into go code that returns errors, and have the template stop at that
    41  point and return an error to your wrapper function. The template will output its text up to that point,
    42  allowing you to easily see where in the template the error occurred.
    43  - **Include Files**. Templates can include other templates. You can specify
    44  a list of search directories for the include files, allowing you to put include files in a variety of
    45  locations, and have include files in one directory that override another directory.
    46  - **Custom Tags**. You can define named fragments that you can include at will, 
    47  and you can define these fragments in include files. To use these fragments, you just
    48  use the name of the fragment as the tag. This essentially gives you the ability to create your own template
    49  language. When you use a custom tag, you can also include parameters that will 
    50  replace placeholders in your fragment, giving you even more power to your custom tags. 
    51  - **Error Reporting**. Errors in your template files are identified by line and character
    52  number. No need to guess where the error is.
    53  
    54  Using other go libraries, you can have your templates compile when they are changed, 
    55  use buffer pools to increase performance, and more. Since the
    56  templates become go code, you can do what you want.
    57  
    58  
    59  ## Installation
    60  
    61  ```shell
    62  go install github.com/goradd/got/got@latest
    63  ```
    64  
    65  We also recommend installing `goimports` 
    66  and passing GoT the -i flag on the command line. That will format your Go code and 
    67  fix up the import lines of any generated go files.
    68  ```shell
    69  go install golang.org/x/tools/cmd/goimports@latest
    70  ```
    71  
    72  ## Command Line Usage
    73  
    74  ```shell
    75  got [options] [files]
    76  
    77  options:
    78  	- o: The output directory. If not specified, files will be output at the same 
    79  	     location as the corresponding template.
    80  	- t  fileType: If set, will process all files in the current directory with this suffix. 
    81  	     If not set, you must specify the files at the end of the command line.
    82  	- i: Run `goimports` on the output files, rather than `go fmt`
    83  	- I  directories and/or files:  A list of directories and/or files. 
    84  	     If a directory, it is used as the search path for include files. 
    85  	     If a file, it is automatically added to the front of every file that is processed.  
    86  	     Directories are searched in the order specified and first matching file will be used. 
    87  	     It will always look in the current directory last unless the current directory 
    88  	     is specified in the list in another location. Relative paths must start with a dot (.) 
    89  	     or double-dot (..).  Directories can start with a module name, and based on the 
    90  	     current directory, the correct go.mod file will be searched to know where to look 
    91  	     for include files.
    92  	- d  directory: When using the -t option, will specify a directory to search.
    93  	- v  verbose: Prints information about files being processed
    94  	- r  recursive: Recursively processes directories. Used with the -t option and possibley -d.
    95  	- f  force: Output files are normally not over-written if they are newer than the input file.
    96  	     This otpion will force all input files to over-write the output files.
    97  ```
    98  If a path described above starts with a module path, the actual disk location 
    99  will be substituted.
   100  
   101  examples:
   102  ```shell
   103  	got -t got -i -o ../templates
   104  	got -I .;../tmpl;example.com/projectTemplates file1.tmpl file2.tmpl
   105  ```
   106  
   107  ## Basic Syntax
   108  Template tags start with `{{` and end with `}}`.
   109  
   110  A template starts in go mode. To send simple text or html to output, surround the text with `{{` and `}}` tags
   111  with a space or newline separating the tags from the surrounding text. Inside the brackets you will be in 
   112  text mode.
   113  
   114  In the resulting Go code, text will get written to output by calling:
   115  
   116   ```_, err = io.WriteString(_w, <text>)``` 
   117  
   118  GoT assumes that the `_w` variable
   119  is available and satisfies the io.Writer interface
   120  and optionally the io.StringWriter interface.
   121  Usually you would do this by declaring a function at the top of your template that looks like this:
   122  
   123  ``` func f(_w io.Writer) (err error) ```
   124  
   125  After compiling the template output together with your program, you call
   126  this function to get the template output. 
   127  
   128  At a minimum, you will need to import the "io" package into the file with your template function.
   129  Depending on what tags you use, you might need to add 
   130  additional items to your import list. Those are mentioned below with each tag.
   131  
   132  ### Example
   133  Here is how you might create a very basic template. For purposes of this example, we will call the file
   134  `example.got` and put it in the `template` package, but you can name the file and package whatever you want.
   135  ```
   136  package template
   137  
   138  import "io"
   139  
   140  func OutTemplate(_w io.Writer) (err error) {
   141  	var world string = "World"
   142  {{
   143  <p>
   144      Hello {{world}}!
   145  </p>
   146  }}
   147    return // make sure the error gets returned
   148  }
   149  ```
   150  
   151  To compile this template, call GoT:
   152  ```shell
   153  got example.got
   154  ```
   155  
   156  This will create an `example.go` file, which you include in your program. You then can call the function
   157  you declared:
   158  ```go
   159  package main
   160  
   161  import (
   162  	"io"
   163  	"os"
   164  	"mypath/template"
   165  )
   166  
   167  func main() {
   168  	_ = template.OutTemplate(os.Stdout)
   169  }
   170  ```
   171  
   172  This simple example shows a mix of go code and template syntax in the same file. Using GoT's include files,
   173  you can separate your go code from template code.
   174  
   175  ## Template Syntax
   176  
   177  The following describes how the various open tags work. Most tags end with a ` }}`, unless otherwise indicated.
   178  Many tags have a short and a long form. Using the long form does not impact performance, its just there
   179  to help your templates have some human readable context to them.
   180  
   181  ### Static Text
   182      {{<space or newline>   Begin to output text as written.
   183      {{! or {{esc           Html escape the text. Html reserved characters, like < or > are 
   184                             turned into html entities first. This happens when the template is 
   185                             compiled, so that when the template runs, the string will already 
   186                             be escaped. 
   187      {{h or {{html          Html escape and html format double-newlines into <p> tags.
   188      {{t or {{translate     Send the text to a translator
   189  
   190  
   191  The `{{!` tag requires you to import the standard html package. `{{h` requires both the html and strings packages.
   192  
   193  `{{t` will wrap the static text with a call to t.Translate(). Its up to you to define this object and make it available to the template. The
   194  translation will happen during runtime of your program. We hope that a future implementation of GoT could
   195  have an option to send these strings to an i18n file to make it easy to send these to a translation service.
   196  
   197  #### Example
   198  In this example file, note that we start in Go mode, copying the text verbatim to the template file.
   199  ```
   200  package test
   201  
   202  import (
   203  	"io"
   204  	"fmt"
   205  )
   206  
   207  type Translater interface {
   208  	Translate(string) string
   209  }
   210  
   211  func staticTest(_w io.Writer) {
   212  {{
   213  <p>
   214  {{! Escaped html < }}
   215  </p>
   216  }}
   217  
   218  {{h
   219  	This is text that is both escaped.
   220  	 
   221  	And has html paragraphs inserted.
   222  }}
   223  
   224  }
   225  
   226  func translateTest(t Translater, buf *bytes.Buffer) {
   227  
   228  {{t Translate me to some language }}
   229  
   230  {{!t Translate & escape me > }}
   231  
   232  }
   233  ```
   234  
   235  ### Switching Between Go Mode and Template Mode
   236  From within any static text context described above you can switch into go context by using:
   237  
   238      {{g or {{go     Change to straight go code.
   239      
   240  Go code is copied verbatim to the final template. Use it to set up loops, call special processing functions, etc.
   241  End go mode using the `}}` closing tag. You can also include any other GoT tag inside of Go mode,
   242  meaning you can nest Go mode and all the other template tags.
   243  
   244  #### Example
   245  ```
   246  // We start a template in Go mode. The next tag switches to text mode, and then nests
   247  // switching back to go mode.
   248  {{ Here 
   249  {{go 
   250  io.WriteString(_w, "is") 
   251  }} some code wrapping text escaping to go. }}
   252  ```
   253  
   254  ### Dynamic Text
   255  The following tags are designed to surround go code that returns a go value. The value will be 
   256  converted to a string and sent to the buf. The go code could be a static value, or a function
   257  that returns a value.
   258  
   259      Tag                       Description                     Example
   260      
   261      {{=, {{s, or  {{string    Send a go string to output      {{= fmt.Sprintf("I am %s", sVar) }}
   262      {{i or {{int              Send an int to output           {{ The value is: {{i iVar }} }}
   263      {{u or {{uint             Send an unsigned Integer        {{ The value is: {{u uVar }} }}
   264      {{f or {{float            Send a floating point number    {{ The value is: {{f fVar }} }}
   265      {{b or {{bool             A boolean ("true" or "false")   {{ The value is: {{b bVar }} }}
   266      {{w or {{bytes            A byte slice                    {{ The value is: {{w byteSliceVar }} }}
   267      {{v or {{stringer or      Send any value that implements  {{ The value is: {{objVar}} }}
   268         {{goIdentifier}}       the Stringer interface.
   269  
   270  
   271  This last tag can be slower than the other tags since it uses fmt.Sprint() internally, 
   272  so if this is a heavily used template,  avoid it. Usually you will not notice a speed difference though,
   273  and the third option can be very convenient. This third option is simply any go variable surrounded by mustaches 
   274  with no spaces.
   275  
   276  The i, u, and f tags use the strconv package, so be sure to include that in your template.
   277  
   278  #### Escaping Dynamic Text
   279  
   280  Some value types potentially could produce html reserved characters. The following tags will html escape
   281  the output.
   282  
   283      {{!=, {{!s or {{!string    HTML escape a go string
   284      {{!w or {{!bytes           HTML escape a byte slice
   285      {{!v or {{!stringer        HTML escape a Stringer
   286      {{!h                       Escape a go string and html format breaks and newlines
   287  
   288  These tags require you to import the "html" package. The `{{!h` tag also requires the "strings" package.
   289  
   290  #### Capturing Errors
   291  
   292  These tags will receive two results, the first a value to send to output, and the second an error
   293  type. If the error is not nil, processing will stop and the error will be returned by the template function. Therefore, these
   294  tags expect to be included in a function that returns an error. Any template text
   295  processed so far will still be sent to the output buffer.
   296  
   297      {{=e, {{se, {{string,err      Output a go string, capturing an error
   298      {{!=e, {{!se, {{!string,err   HTML escape a go string and capture an error
   299      {{ie or {{int,err             Output a go int and capture an error
   300      {{ue or {{uint,err            Output a go uint and capture an error
   301      {{fe or {{float,err           Output a go float64 and capture an error
   302      {{be or {{bool,err            Output a bool ("true" or "false") and capture an error
   303      {{we, {{bytes,err             Output a byte slice and capture an error
   304      {{!we or {{!bytes,err         HTML escape a byte slice and capture an error
   305      {{ve, {{stringer,err          Output a Stringer and capture an error
   306      {{!ve or {{!stringer,err      HTML escape a Stringer and capture an error
   307      {{e, or {{err                 Execute go code that returns an error, and stop if the error is not nil
   308  
   309  ##### Example
   310  ```go
   311  func Tester(s string) (out string, err error) {
   312  	if s == "bad" {
   313  		err = errors.New("This is bad.")
   314  	}
   315  	return s
   316  }
   317  
   318  func OutTemplate(toPrint string, buf bytes.Buffer) error {
   319  {{=e Tester(toPrint) }}
   320  }
   321  ```
   322  
   323  ### Include Files
   324  #### Include a GoT source file
   325  
   326      {{: "fileName" }} or 
   327      {{include "fileName" }}   Inserts the given file name into the template.
   328  
   329   The included file will start in whatever mode the receiving template is in, as if the text was inserted
   330   at that spot, so if the include tags are  put inside of go code, the included file will start in go mode. 
   331   The file will then be processed like any other GoT file. Include files can refer to other include files,
   332   and so are recursive.
   333   
   334   Include files are searched for in the current directory, and in the list of include directories provided
   335   on the command line by the -I option.
   336  
   337  Example: `{{: "myTemplate.inc" }}`
   338  
   339  #### Include a text file
   340  
   341      {{:! "fileName" }} or             Inserts the given file name into the template
   342      {{includeEscaped "fileName" }}    and html escapes it.
   343      {{:h "fileName" }} or             Inserts the given file name into the template,
   344      {{includeAsHtml "fileName" }}     html escapes it, and converts newlines into html breaks.
   345  
   346  Use `{{:!` to include a file that you surround with a `<pre>` tag to include a text file
   347  and have it appear in an html document looking the same. Use `{{:h` to include a file
   348  without the `<pre>` tags, but if the file uses extra spaces for indent, those spaces will
   349  not indent in the html. These kinds of include files will not be searched for GoT commands.
   350   
   351  ### Defined Fragments
   352  
   353  Defined fragments start a block of text that can be included later in a template. The included text will
   354  be sent as is, and then processed in whatever mode the template processor is in, as if that text was simply
   355  inserted into the template at that spot. You can include the `{{` or `{{g` tags inside of the fragment to
   356  force the processor into the text or go modes if needed. The fragment can be defined
   357  any time before it is included, including being defined in other include files. 
   358  
   359  You can add optional parameters
   360  to a fragment that will be substituted for placeholders when the fragment is used. You can have up to 9
   361  placeholders ($1 - $9). Parameters should be separated by commas, and can be surrounded by quotes if needed
   362  to have a parameter that has a quote or comma in it.
   363  
   364      {{< fragName }} or {{define fragName }}   Start a block called "fragName".
   365      {{< fragName <count>}} or                 Start a block called "fragName" that will 
   366         {{define fragName <count>}}            have <count> parameters.
   367      {{> fragName param1,param2,...}} or       Substitute this tag for the given defined fragment.
   368        {{put fragName param1,param2,...}} or   
   369        {{fragName param1,param2,...}}
   370      {{>? fragName param1,param2,...}} or      Substitute this tag for the given defined fragment, 
   371        {{put? fragName param1,param2,...}}     but if the fragment is not defined, leave blank.
   372  
   373   
   374  If you attempt to use a fragment that was not previously defined, GoT will panic and stop compiling,
   375  unless you use {{>? or {{put? to include the fragment.
   376  
   377  param1, param2, ... are optional parameters that will be substituted for $1, $2, ... in the defined fragment.
   378  If a parameter is not included when using a fragment, an empty value will be substituted for the parameter in the fragment.
   379  
   380  The fragment name is NOT surrounded by quotes, and cannot contain any whitespace in the name. Blocks are ended with a
   381  `{{end fragName}}` tag. The end tag must be just like that, with no spaces after the fragName.
   382  
   383  The following fragments are predefined:
   384  * `{{templatePath}}` is the full path of the template file being processed
   385  * `{{templateName}}` is the base name of the template file being processed, including any extensions
   386  * `{{templateRoot}}` is the base name of the template file being processed without any extensions
   387  * `{{templateParent}}` is the directory name of the template file being processed, without the preceeding path
   388  * `{{outPath}}` is the full path of the output file being written
   389  * `{{outName}}` is the base name of the output file being written, including any extensions
   390  * `{{outRoot}}` is the base name of the output file being written without any extensions
   391  * `{{outParent}}` is the directory name of the output file being written, without the preceeding path
   392  
   393  Note that if you are using these in an included file, these will refer to the parent file. Multiple
   394  levels of includes will return the information for the top level file being processed. 
   395  
   396  #### Example
   397  ```
   398  
   399  {{< hFrag }}
   400  <p>
   401  This is my html body.
   402  </p>
   403  {{end hFrag}}
   404  
   405  {{< writeMe 2}}
   406  {{// The g tag here forces us to process the text as go code, 
   407       no matter where the fragment is included }}
   408  {{g 
   409  if "$2" != "" {
   410  	io.WriteString(_w, "$1")
   411  }
   412  }}
   413  {{end writeMe}}
   414  
   415  
   416  func OutTemplate(_w io.Writer) (err error) {
   417  {{
   418  	<html>
   419  		<body>
   420  			{{> hFrag }}
   421  		</body>
   422  	</html>
   423  }}
   424  
   425  {{writeMe "Help Me!", a}}
   426  {{writeMe "Help Me!", }}
   427   return
   428  }
   429  ```
   430  
   431  ### Comment Tags
   432  
   433      {{# or {{//       Comment the template. This is removed from the compiled template.
   434  
   435  These tags and anything enclosed in them is removed from the compiled template.
   436  
   437  ### Go Block Tags
   438      
   439      {{if <go condition>}}<text block>{{if}}                      
   440                             A convenience tag for surrounding text with a go "if" statement.
   441      {{if <go condition>}}<text block>{{else}}<text block>{{if}}  
   442                             Go "if" and "else" statement.
   443      {{if <go condition>}}<text block>{{elseif <go condition>}}<text block>{{if}}    
   444                             Go "if" and "else if" statement.
   445      {{for <go condition and optional range statement>}}<text block>{{for}}                                   
   446                             A convenience tag for surrounding text with a go "for" statement.
   447  
   448  These tags are substitutes for switching into GO mode and using a `for` or `if` statements. 
   449  `<text block>` will be in text mode to begin with, so that whatever you put there
   450  will be output, but you can switch to go mode if needed.
   451  
   452  ####Example
   453  
   454  ```
   455  {{
   456  {{for num,item := range items }}
   457  <p>Item {{num}} is {{item}}</p>
   458  {{for}}
   459  }}
   460  ```
   461  ### Join Tags
   462  
   463      {{join <slice>, <string>}}<text block>{{join}}    Joins the items of a slice with a string.
   464  
   465  Join will output the `<text block>` for each item of `<slice>`. Within `<text block>` the variable
   466  `_i` will be an integer representing the index of the slice item, and `_j` will be the
   467  item itself. `<text block>` starts in text mode, but you can put GoT commands in it. `<string>` will be output
   468  between the output of each item, creating an effect similar to joining a slice of strings.
   469  
   470  
   471  ####Example
   472  
   473  ```
   474  {{g
   475    items := []string{"a", "b", "c"}
   476  }}
   477  {{join items,", "}}
   478  {{ {{_i}} = {{_j}} }}
   479  {{join}}
   480  ```
   481  
   482  
   483  ### Strict Text Block Tag
   484  
   485  From within most of the GoT tags, you can insert another GoT tag. GoT will be looking for these
   486  as it processes text. If you would like to turn off GoT's processing to output text 
   487  that is not processed by GoT, you can use:
   488  
   489      {{begin *endTag*}}   Starts a strict text block and turns off the GoT parser. 
   490      
   491  One thing this is useful for is to use GoT to generate GoT code.
   492  End the block with a `{{end *endTag*}}` tag, where `*endTag*` is whatever you specified in the begin tag. 
   493  There can be no space between the endTag and the final brackets
   494  The following example will output the entire second line of code with no changes, 
   495  including all brackets:
   496  
   497  ```
   498  {{begin mystrict}}
   499  {{! This is verbatim code }}
   500  {{< all included}}
   501  {{end mystrict}}
   502  ```
   503  
   504  ## Bigger Example
   505  
   506  In this example, we will combine multiple files. One, a traditional html template with a place to fill in
   507  some body text. Another, a go function declaration that we will use when we want to draw the template.
   508  The function will use a traditional web server io.Writer pattern, including the use of a context parameter.
   509  Finally, there is an example main.go illustrating how our template function would be called.
   510  
   511  ### index.html
   512  
   513  ```html
   514  <!DOCTYPE html>
   515  <html>
   516      <head>
   517          <meta charset="utf-8">
   518      </head>
   519  
   520      <body>
   521  {{# The tag below declares that we want to substitute a named 
   522      fragment that is declared elsewhere }}
   523  {{put body }}
   524      </body>
   525  </html>
   526  ```
   527  
   528  ### template.got
   529  
   530  ```
   531  package main
   532  
   533  import {
   534  	"context"
   535  	"bytes"
   536  }
   537  
   538  
   539  func writeTemplate(ctx context.Context, buf *bytes.Buffer) {
   540  
   541  {{# Define the body that will be inserted into the template }}
   542  {{< body }}
   543  <p>
   544  The caller is: {{=s ctx.Value("caller") }}
   545  </p>
   546  {{end body}}
   547  
   548  {{# include the html template. Since the template is html, 
   549      we need to enter static text mode first }}
   550  {{ 
   551  {{include "index.html"}}
   552  }}
   553  
   554  }
   555  ```
   556  
   557  ### main.go
   558  
   559  ```html
   560  type myHandler struct {}
   561  
   562  func (h myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)  {
   563  	ctx :=  context.WithValue(r.Context(), "caller", r.Referer())
   564  	writeTemplate(ctx, w)	// call the GoT template
   565  }
   566  
   567  
   568  func main() {
   569  	var r myHandler
   570  	var err error
   571  
   572  	*local = "0.0.0.0:8000"
   573  
   574  	err = http.ListenAndServe(*local, r)
   575  
   576  	if err != nil {
   577  		fmt.Println(err)
   578  	}
   579  }
   580  ```
   581  
   582  To compile the template:
   583  
   584  ```shell
   585  got template.got
   586  ```
   587  
   588  Build your application and go to `http://localhost:8000` in your browser, to see your results
   589  
   590  ## License
   591  GoT is licensed under the MIT License.
   592  
   593  ## Acknowldgements
   594  
   595  GoT was influenced by:
   596  
   597  - [hero](https://github.com/shiyanhui/hero)
   598  - [fasttemplate](https://github.com/valyala/fasttemplate)
   599  - [Rob Pike's Lexing/Parsing Talk](https://www.youtube.com/watch?v=HxaD_trXwRE)
   600  
   601  ## Syntax Changes
   602  
   603  ###v0.10.0
   604  This was a major rewrite with the following changes:
   605  - defined fragments end with {{end fragName}} tags, rather than {{end}} tags
   606  - {{else if ...}} is now {{elseif ...}}
   607  - {{join }} tag will join items with a string
   608  - The backup tag {{- has been removed
   609  - Reorganized the lexer and parser to be easier to debug
   610  - Added many more unit tests. Code coverage > 90%.
   611  - The output is sent to an io.Writer called _w. This allows more flexible use of the templates, and the ability to wrap them with middleware