...

Text file src/github.com/noirbizarre/gonja/README.md

Documentation: github.com/noirbizarre/gonja

     1# Gonja
     2
     3[![GoDoc](https://godoc.org/github.com/noirbizarre/gonja?status.svg)](https://godoc.org/github.com/noirbizarre/gonja)
     4[![Build Status](https://travis-ci.org/noirbizarre/gonja.svg?branch=master)](https://travis-ci.org/noirbizarre/gonja)
     5[![Coverage Status](https://codecov.io/gh/noirbizarre/gonja/branch/master/graph/badge.svg)](https://codecov.io/gh/noirbizarre/gonja)
     6
     7`gonja` is [`pongo2`](https://github.com/flosch/pongo2) fork intended to be aligned on `Jinja` template syntax instead of the `Django` one.
     8
     9Install/update using `go get` (no dependencies required by `gonja`):
    10```
    11go get github.com/noirbizarre/gonja
    12```
    13
    14Please use the [issue tracker](https://github.com/noirbizarre/gonja/issues) if you're encountering any problems with gonja or if you need help with implementing tags or filters ([create a ticket!](https://github.com/noirbizarre/gonja/issues/new)).
    15
    16## First impression of a template
    17
    18```HTML+Django
    19<html><head><title>Our admins and users</title></head>
    20{# This is a short example to give you a quick overview of gonja's syntax. #}
    21
    22{% macro user_details(user, is_admin=false) %}
    23	<div class="user_item">
    24		<!-- Let's indicate a user's good karma -->
    25		<h2 {% if (user.karma >= 40) || (user.karma > calc_avg_karma(userlist)+5) %}
    26			class="karma-good"{% endif %}>
    27			
    28			<!-- This will call user.String() automatically if available: -->
    29			{{ user }}
    30		</h2>
    31
    32		<!-- Will print a human-readable time duration like "3 weeks ago" -->
    33		<p>This user registered {{ user.register_date|naturaltime }}.</p>
    34		
    35		<!-- Let's allow the users to write down their biography using markdown;
    36		     we will only show the first 15 words as a preview -->
    37		<p>The user's biography:</p>
    38		<p>{{ user.biography|markdown|truncatewords_html:15 }}
    39			<a href="/user/{{ user.id }}/">read more</a></p>
    40		
    41		{% if is_admin %}<p>This user is an admin!</p>{% endif %}
    42	</div>
    43{% endmacro %}
    44
    45<body>
    46	<!-- Make use of the macro defined above to avoid repetitive HTML code
    47	     since we want to use the same code for admins AND members -->
    48	
    49	<h1>Our admins</h1>
    50	{% for admin in adminlist %}
    51		{{ user_details(admin, true) }}
    52	{% endfor %}
    53	
    54	<h1>Our members</h1>
    55	{% for user in userlist %}
    56		{{ user_details(user) }}
    57	{% endfor %}
    58</body>
    59</html>
    60```
    61
    62## Features (and new in gonja)
    63
    64 * Entirely rewritten from the ground-up.
    65 * [Advanced C-like expressions](https://github.com/noirbizarre/gonja/blob/master/template_tests/expressions.tpl).
    66 * [Complex function calls within expressions](https://github.com/noirbizarre/gonja/blob/master/template_tests/function_calls_wrapper.tpl).
    67 * [Easy API to create new filters and tags](http://godoc.org/github.com/noirbizarre/gonja#RegisterFilter) ([including parsing arguments](http://godoc.org/github.com/noirbizarre/gonja#Parser))
    68 * Additional features:
    69    * Macros including importing macros from other files (see [template_tests/macro.tpl](https://github.com/noirbizarre/gonja/blob/master/template_tests/macro.tpl))
    70    * [Template sandboxing](https://godoc.org/github.com/noirbizarre/gonja#TemplateSet) ([directory patterns](http://golang.org/pkg/path/filepath/#Match), banned tags/filters)
    71
    72
    73## How you can help
    74
    75 * Write [filters](https://github.com/noirbizarre/gonja/blob/master/builtins/filters.go#L3) / [statements](https://github.com/noirbizarre/gonja/blob/master/builtins/statements.go#L4)
    76 * Write/improve code tests (use the following command to see what tests are missing: `go test -v -cover -covermode=count -coverprofile=cover.out && go tool cover -html=cover.out` or have a look on [gocover.io/github.com/noirbizarre/gonja](http://gocover.io/github.com/noirbizarre/gonja))
    77 * Write/improve template tests (see the `testData/` directory)
    78 * Write middleware, libraries and websites using gonja. :-)
    79
    80# Documentation
    81
    82For a documentation on how the templating language works you can [head over to the Jinja documentation](https://jinja.palletsprojects.com). gonja aims to be compatible with it.
    83
    84You can access gonja's API documentation on [godoc](https://godoc.org/github.com/noirbizarre/gonja).
    85
    86## Caveats 
    87
    88### Filters
    89
    90 * **format**: `format` does **not** take Python's string format syntax as a parameter, instead it takes Go's. Essentially `{{ 3.14|stringformat:"pi is %.2f" }}` is `fmt.Sprintf("pi is %.2f", 3.14)`.
    91 * **escape** / **force_escape**: Unlike Jinja's behaviour, the `escape`-filter is applied immediately. Therefore there is no need for a `force_escape`-filter yet.
    92
    93# API-usage examples
    94
    95Please see the documentation for a full list of provided API methods.
    96
    97## A tiny example (template string)
    98
    99```Go
   100// Compile the template first (i. e. creating the AST)
   101tpl, err := gonja.FromString("Hello {{ name|capfirst }}!")
   102if err != nil {
   103	panic(err)
   104}
   105// Now you can render the template with the given 
   106// gonja.Context how often you want to.
   107out, err := tpl.Execute(gonja.Context{"name": "axel"})
   108if err != nil {
   109	panic(err)
   110}
   111fmt.Println(out) // Output: Hello Axel!
   112```
   113
   114## Example server-usage (template file)
   115
   116```Go
   117package main
   118
   119import (
   120	"github.com/noirbizarre/gonja"
   121	"net/http"
   122)
   123
   124// Pre-compiling the templates at application startup using the
   125// little Must()-helper function (Must() will panic if FromFile()
   126// or FromString() will return with an error - that's it).
   127// It's faster to pre-compile it anywhere at startup and only
   128// execute the template later.
   129var tpl = gonja.Must(gonja.FromFile("example.html"))
   130
   131func examplePage(w http.ResponseWriter, r *http.Request) {
   132	// Execute the template per HTTP request
   133	out, err := tpl.Execute(gonja.Context{"query": r.FormValue("query")})
   134	if err != nil {
   135		http.Error(w, err.Error(), http.StatusInternalServerError)
   136	}
   137	w.WriteString(out)
   138}
   139
   140func main() {
   141	http.HandleFunc("/", examplePage)
   142	http.ListenAndServe(":8080", nil)
   143}
   144```
   145
   146# Benchmark
   147
   148The benchmarks have been run on the my machine (`Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz`) using the command:
   149
   150    go test -bench . -cpu 1,2,4,8
   151
   152All benchmarks are compiling (depends on the benchmark) and executing the `testData/complex.tpl` template.
   153
   154The results are:
   155
   156	BenchmarkFromCache             	   30000	     41259 ns/op
   157	BenchmarkFromCache-2           	   30000	     42776 ns/op
   158	BenchmarkFromCache-4           	   30000	     44432 ns/op
   159	BenchmarkFromFile              	    3000	    437755 ns/op
   160	BenchmarkFromFile-2            	    3000	    472828 ns/op
   161	BenchmarkFromFile-4            	    2000	    519758 ns/op
   162	BenchmarkExecute               	   30000	     41984 ns/op
   163	BenchmarkExecute-2             	   30000	     48546 ns/op
   164	BenchmarkExecute-4             	   20000	    104469 ns/op
   165	BenchmarkCompileAndExecute     	    3000	    428425 ns/op
   166	BenchmarkCompileAndExecute-2   	    3000	    459058 ns/op
   167	BenchmarkCompileAndExecute-4   	    3000	    488519 ns/op
   168	BenchmarkParallelExecute       	   30000	     45262 ns/op
   169	BenchmarkParallelExecute-2     	  100000	     23490 ns/op
   170	BenchmarkParallelExecute-4     	  100000	     24206 ns/op
   171
   172Benchmarked on August 18th 2019.

View as plain text