pongo2 is a Django-syntax like templating-language

Overview

pongo2

PkgGoDev Build Status

pongo2 is a Django-syntax like templating-language (official website).

Install/update using go get (no dependencies required by pongo2):

go get -u github.com/flosch/pongo2/v4

Please use the issue tracker if you're encountering any problems with pongo2 or if you need help with implementing tags or filters (create a ticket!).

First impression of a template

<html>
  <head>
    <title>Our admins and userstitle>
  head>
  {# This is a short example to give you a quick overview of pongo2's syntax. #}
  {% macro user_details(user, is_admin=false) %}
  <div class="user_item">
    
    <h2 {% if (user.karma>
      = 40) || (user.karma > calc_avg_karma(userlist)+5) %} class="karma-good"{%
      endif %}>

      
      {{ user }}
    h2>

    
    <p>This user registered {{ user.register_date|naturaltime }}.p>

    
    <p>The user's biography:p>
    <p>
      {{ user.biography|markdown|truncatewords_html:15 }}
      <a href="/user/{{ user.id }}/">read morea>
    p>

    {% if is_admin %}
    <p>This user is an admin!p>
    {% endif %}
  div>
  {% endmacro %}

  <body>
    

    <h1>Our adminsh1>
    {% for admin in adminlist %} {{ user_details(admin, true) }} {% endfor %}

    <h1>Our membersh1>
    {% for user in userlist %} {{ user_details(user) }} {% endfor %}
  body>
html>

Features

Caveats

Filters

  • date / time: The date and time filter are taking the Golang specific time- and date-format (not Django's one) currently. Take a look on the format here.
  • stringformat: stringformat 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).
  • escape / force_escape: Unlike Django's behaviour, the escape-filter is applied immediately. Therefore there is no need for a force_escape-filter yet.

Tags

  • for: All the forloop fields (like forloop.counter) are written with a capital letter at the beginning. For example, the counter can be accessed by forloop.Counter and the parentloop by forloop.Parentloop.
  • now: takes Go's time format (see date and time-filter).

Misc

  • not in-operator: You can check whether a map/struct/string contains a key/field/substring by using the in-operator (or the negation of it): {% if key in map %}Key is in map{% else %}Key not in map{% endif %} or {% if !(key in map) %}Key is NOT in map{% else %}Key is in map{% endif %}.

Add-ons, libraries and helpers

Official

  • pongo2-addons - Official additional filters/tags for pongo2 (for example a markdown-filter). They are in their own repository because they're relying on 3rd-party-libraries.

3rd-party

Please add your project to this list and send me a pull request when you've developed something nice for pongo2.

Who's using pongo2

I'm compiling a list of pongo2 users. Add your project or company!

API-usage examples

Please see the documentation for a full list of provided API methods.

A tiny example (template string)

// Compile the template first (i. e. creating the AST)
tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
if err != nil {
    panic(err)
}
// Now you can render the template with the given
// pongo2.Context how often you want to.
out, err := tpl.Execute(pongo2.Context{"name": "florian"})
if err != nil {
    panic(err)
}
fmt.Println(out) // Output: Hello Florian!

Example server-usage (template file)

package main

import (
    "github.com/flosch/pongo2/v4"
    "net/http"
)

// Pre-compiling the templates at application startup using the
// little Must()-helper function (Must() will panic if FromFile()
// or FromString() will return with an error - that's it).
// It's faster to pre-compile it anywhere at startup and only
// execute the template later.
var tplExample = pongo2.Must(pongo2.FromFile("example.html"))

func examplePage(w http.ResponseWriter, r *http.Request) {
    // Execute the template per HTTP request
    err := tplExample.ExecuteWriter(pongo2.Context{"query": r.FormValue("query")}, w)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

func main() {
    http.HandleFunc("/", examplePage)
    http.ListenAndServe(":8080", nil)
}
Comments
  • Implement caching

    Implement caching

    Would it make sense to have a built-in template cache which is enabled in production only (non debug)?. I can see you're currently doing this in https://github.com/macaron-contrib/pongo2/blob/master/pongo2.go where you're integrating pongo2 with a web framework. I think it would make sense to have the template cache in pongo2. Otherwise this work has to be redone when integrating with multiple frameworks which is a hassle.

    Could be as simple as if the template is in cache and we're not in debug, load it from cache, otherwise reparse it.

    enhancement 
    opened by ahall 26
  • Reusable macros

    Reusable macros

    in jinja2 you can do something like this:

    {% from "helpers/macros.html" import my_reusable_macro, my_reusable_macro2 %}
    
    {{ my_reusable_macro() }}
    

    Would it make sense to implement so macros can be imported and reused instead of them having to be in the same template file as they're used in?

    enhancement 
    opened by ahall 23
  • The truncatewords tag does not support Chinese

    The truncatewords tag does not support Chinese

    case 1: {{ "中文字符"|truncatewords:1|safe }} The expected output a character (中), but in fact, if there is no space, then is unable to determine, so lead to dividing Chinese characters. Because the Chinese character do not need to rely on a space character segmentation.

    case 2: {{ "中文 字符"|truncatewords:1|safe }} Expected output a character (中), but in fact the output two characters(中文).

    bug 
    opened by insionng 12
  • Base directory

    Base directory

    I usually have my templates in a separate directory e.g. structures something like:

    templates/base.html
    templates/user/index.html
    

    In user.html I'd like to do something like:

    {% extends "base.html" %}
    

    Currently having to reference it like {% extends "../base.html" %}. I'd prefer if I could specify a template root and then reference it like a sandbox. It would also let me render "user/index" within the sandbox instead of specifying the full path. Does this make sense? Thanks for a great project, it's looking very useful.

    enhancement 
    opened by ahall 11
  • Unimplemented filter usage gives not clear panic message

    Unimplemented filter usage gives not clear panic message

    I got panic message while template execution:

    2014/07/22 04:07:25 PANIC: runtime error: invalid memory address or nil pointer dereference
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/panic.c:552 (0x10d2d)
        panicstring: runtime·panic(err);
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/os_darwin.c:454 (0xf9ce)
        sigpanic: runtime·panicstring("invalid memory address or nil pointer dereference");
    /Users/vgarvardt/Sites/blogo/.godeps/src/github.com/flosch/pongo2/template.go:66 (0x126080)
        (*Template).execute: panic(string(tpl.size))
    /Users/vgarvardt/Sites/blogo/.godeps/src/github.com/flosch/pongo2/template.go:133 (0x126474)
        (*Template).Execute: buffer, err := tpl.execute(context)
    ...
    

    I found that panic occurs when I used join filter that is not implemented yet. It would be much easier to debug templates when panic can give more informative messages, e.g. "unknown filter found 'join'".

    PS: btw, thanks for the project - even without lots of filters and tags implemented it makes my life much easier =)

    invalid 
    opened by vgarvardt 11
  • Can't use map[string]struct in template

    Can't use map[string]struct in template

    I have a data with this type:

    type Data struct{
    ...
    }
    var datas := make(map[string]Data,0)
    ...
    

    and in the template,i want to access the data through it's id:

    {{datas["somename"]}}
    

    and got an error:

    Handler crashed with error [Error (where: lexer) in views/sample.cfg | Line 36 Col 44] Unknown character: '[' (91)
    2015/01/26 12:43:13 [router.go:883] [C] /usr/src/go/src/runtime/asm_amd64.s:402
    2015/01/26 12:43:13 [router.go:883] [C] /usr/src/go/src/runtime/panic.go:387
    2015/01/26 12:43:13 [router.go:883] [C] /go/src/github.com/flosch/pongo2/pongo2.go:11
    
    opened by magicshui 10
  • Make Execute()*-methods return their own error object

    Make Execute()*-methods return their own error object

    with seperated (machine-readable) fields for

    • filename (string)
    • line (int)
    • column (int)
    • error message (string)
    • affected raw template line (a string)

    instead of one complete error message as a string.

    enhancement 
    opened by flosch 10
  • Error message missing file path(#2)

    Error message missing file path(#2)

    panic: open templates\header: The system cannot find the file specified.
    

    Now I found another mistake information missing file path problem. I know this error is due to the lack of HTML suffix caused. But, I don't know who is calling this a line of code, I need to know who is calling.

    invalid 
    opened by insionng 10
  • feature: add loader for embed.FS

    feature: add loader for embed.FS

    Support loading template from Go embed.FS

    To support embed.FS we need to upgrade the go module version to at least v1.16

    There are also some limitations for the filename, please check:

    • https://pkg.go.dev/embed#hdr-Directives
    • https://github.com/golang/go/issues/43854
    opened by fahmifan 9
  • Eat my newline

    Eat my newline

    It would be great to have the same "eat my newline" as Jinja has "-%}" and "{%-".

    This is very usefull when using Pongo for non-web development templating or if you're a neat freak.

    Input:

    hosts: [ "stinky", "grumpy", "whoops" ]
    

    Template:

    {% for host in hosts %}
    {{ host }}
    {% endfor %}
    

    Yields:

    
    stinky
    
    grumpy
    
    whoops
    
    

    What would be nice:

    Template:

    {% for host in hosts -%}
    {{ host }}
    {% endfor -%}
    

    Yields:

    stinky
    grumpy
    whoops
    

    --- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/25909091-eat-my-newline?utm_campaign=plugin&utm_content=tracker%2F3654947&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F3654947&utm_medium=issues&utm_source=github). enhancement needs evaluation 
    opened by ake-persson 9
  • Struct's method calling not working

    Struct's method calling not working

    When we have to print the result of a strutc's method it doesn't show anything.

    Ex.:

    type Test struct {
        Child string
    }
    
    func (t *Test) MyFunc() string {
        return "My Func Result"
    }
    
    func main() {
        tpl, err := pongo2.FromString("Child: {{ Test.Child }} | MyFunc: {{ Test.MyFunc() }}")
        if err != nil {
            panic(err)
        }
        out, err := tpl.Execute(pongo2.Context{"Test":  &Test{ Child: "Test Child"} })
        if err != nil {
            panic(err)
        }
        fmt.Println(out) // Child: TestChild | MyFunc: 
    }
    

    What I could figure out is that when parsing Pongo2 knows that a function should be called, but when resolving, the function is not called and only the struct's properties is printed.

    opened by phcostabh 9
  • Context key invalid

    Context key invalid

    I use the context key like this: portfolio.name and value is long But has this error: [Error (where: checkForValidIdentifiers)] context-key 'portfolio.name' (value: 'long') is not a valid identifier

    question 
    opened by dolong2110 0
  • Cannot using template.Fromfile

    Cannot using template.Fromfile

    this file base.pconf

    {%- set intraday_regions = ["useu", "cnhkusadr"] -%}
    
    {% if ny5 is defined and ny5 -%}
    global.ny5 = true
    {% else -%}
    global.ny5 = false
    {% endif -%}
    
    {% if inject_exmodules_common is defined and inject_exmodules_common -%}
    {% if ny5 is defined and ny5 -%}
    use("cfg-template/pulse_configrc/inject_exmodules_common_ny5.pconf")
    {% else -%}
    use("cfg-template/pulse_configrc/inject_exmodules_common.pconf")
    {% endif -%}
    {% else -%}
    {% if bundle_alphatype != "pulse_s" and bundle_alphatype != "s" -%}
    {% if ny5 is defined and ny5 -%}
    use("cfg-template/pulse_configrc/inject_exmodules_common_ny5.pconf")
    {% else -%}
    use("cfg-template/pulse_configrc/inject_exmodules_common.pconf")
    {% endif -%}
    {% endif -%}
    {% endif -%}
    
    {%- if user is defined and user != "" %}
    {%- if ny5 is defined and ny5 -%}
    user_exmodules = "exmodules_trd_oper/pulse_users/{{user}}.exmodules_ny5.pconf"
    {% else -%}
    user_exmodules = "exmodules_trd_oper/pulse_users/{{user}}.exmodules.pconf"
    {% endif -%}
    use(user_exmodules) if File.exists?(user_exmodules)
    {% endif -%}
    
    {% block region_config -%}
    {% if region_config is defined -%}
    use("{{ region_config }}")
    {% else -%}
    use("cfg-template/pulse_configrc/{{ bundle_region }}.pconf")
    {% endif -%}
    
    {% endblock region_config -%}
    
    {%- block global %}
    
    # GLOBAL CONFIGS
    
    global.cache_home = "{{ cache_home | default("/path/to/cache_home")}}"
    global.bundle_region = "{{ bundle_region }}"
    global.bundle_alphatype = "{{ bundle_alphatype }}"
    global.portf_nm = "{{ portf_nm }}"
    global.beam_alpha = {{ beam_alpha | default(false) | tojson }}
    {% if dataroot is defined -%}
    global.dataroot = "{{ dataroot }}"
    {%- endif -%}
    
    {%- if global_dict is defined %}
    
    # additional variables
    {%- for key, value in global_dict.items() %}
    global.{{key}} = {{value | tojson }}
    {%- endfor -%}
    {%- endif -%}
    {% endblock global -%}
    
    {%- block env %}
    
    # ENV CONFIGS
    
    {% if ny5 is defined and ny5 -%}
    use "cfg-template/pulse_configrc/ny5.pconf"
    {% endif -%}
    
    {% if environment is defined and environment == "test" %}
    {% endif -%}
    
    {% if bundle_alphatype != "pulse_s" and bundle_alphatype != "s" -%}
    use "modules/beam/beam.pconf" if global.beam_alpha
    
    {% endif -%}
    
    env.data_dir = "{{ data_dir | default("$(cache_home)/$(bundle_alphatype)/$(bundle_region)/$(portf_nm)/cache") }}"
    {% if output_dir is defined -%}
    env.output_dir = "{{ output_dir }}"
    {% endif -%}
    
    {% if alpha_dump_dir is defined and alpha_dump_dir -%}
    env.alpha_dump_dir = "{{ alpha_dump_dir }}"
    {% endif -%}
    env.alpha_dump_max_tmp_files = 100
    
    env.live = {{ live | default(true) | tojson }}
    env.production = {{ production | default(true) | tojson }}
    {% if fixed_num_refreshes is defined -%}
    env.fixed_num_refreshes = {{ fixed_num_refreshes }}
    {% endif -%}
    
    {% if simulated_now is defined and simulated_now -%}
    env.simulated_now = {{ simulated_now }}
    {% endif -%}
    
    # Should not be true in production
    printer.force_print = {{ force_print | default(false) | tojson }}
    
    {% if upd_univ is defined and upd_univ -%}
    
    # change all alpha universe to UNIVSTORE
    preprocess do |mods|
      if mods.map { |m| m.name }.include?("UNIVSTORE")
        mods.each do |a|
          if a.is_a?(Alpha)
            a.conf[:universe_id] = "UNIVSTORE"
          end
        end
      end
    end
    {% endif -%}
    {% endblock env -%}
    
    {% block pf %}
    
    # PORTFOLIO CONFIGS
    
    portfolio.name = "{{portf_nm}}"
    
    {% if bundle_booksize != "no-change" -%}
    portfolio.scale[:booksize] = {{ bundle_booksize }}
    {% endif -%}
    
    {% if univ_start_date is defined and univ_start_date -%}
    env.univ_start_date = {{ univ_start_date }}
    {% endif -%}
    
    {% if sim_start_date is defined and sim_start_date -%}
    env.sim_start_date = {{ sim_start_date }}
    {% endif -%}
    
    {% if univ_end_date is defined and univ_end_date -%}
    env.univ_end_date = {{ univ_end_date }}
    {% endif -%}
    
    {% if sim_end_date is defined and sim_end_date -%}
    env.sim_end_date = {{ sim_end_date }}
    {% endif -%}
    
    env.refresh_days = {{ refresh_days | default(2) }}
    
    # always set the univ_end_date_exclude_days = env.refresh_days (which is 2 by default).
    # so that after running hist, universe data is only be built until
    # univ_end_date - exclude_days, and be able to run live mode with refresh_days > 0.
    env.univ_end_date_exclude_days = env.refresh_days
    
    {%- if alpha_dump is defined and alpha_dump -%}
    {%-block alpha_dump %}
    
    # dump alpha
    mod("dump_alpha", factory: "DumpAlpha")
    {% endblock alpha_dump -%}
    global.alpha_dump_max_level = {{alpha_dump_max_level | default (1000)}}
    use("cfg-template/pulse_configrc/alpha_dump_helper.pconf")
    {%- endif -%}
    
    {%- if pos_dump is defined and pos_dump -%}
    {%- block pos_dump %}
    
    # dump position
    {% if (intraday_regions is defined and bundle_region in intraday_regions) or ("itd_" in bundle_region) -%}
    factory("IntradayLegacyPosDump", lang: "cpp", path: "modules/intraday/libintraday_legacy_pos_dump.so")
    {% else -%}
    factory("LegacyPosDump", lang: "cpp")
    {% endif -%}
    
    {%- if (intraday_regions is defined and bundle_region in intraday_regions) or ("itd_" in bundle_region) -%}
    portfolio.trade.operation(
      "IntradayLegacyPosDump",
      dump_mode: "daily",
      dump_dir: "pos",
    {%- else -%}
    portfolio.trade.operation(
      "LegacyPosDump",
      dump_dir: "pos",
    {%- endif -%}
    
    {%- if bundle_region in ["eu", "ea_eu", "za", "lamr", "tw", "au", "useu"]%}
      use_sedol: true,
    {%- else %}
      use_sedol: false,
    {%- endif %}
    )
    {% endblock pos_dump -%}
    {%- endif -%}
    
    {%- if future_pos_dump is defined and future_pos_dump -%}
    {%- block future_pos_dump %}
    # dump future position
    portfolio.trade.operation("FutureLegacyPosDump", dump_dir: "pos")
    {% endblock future_pos_dump -%}
    {%- endif -%}
    
    {%- if pos_push is defined and pos_push -%}
    {%- block pos_push  %}
    
    # position push to OMS
    {% if bundle_region in ["itd_fx_usd", "itd_fx_usd_utc"] -%}
    portfolio.trade.operation(
      "IntradayFxPosPush",
      addr: "{pos_push_addr_map['fx']}",
      strategy: "{{ portf_nm }}",
      country: "FX",
      dump_dir: "pos_push",
      timeout: 5,
      end_time: 163000,
      replace: true,
    )
    {% else -%}
    {%- if (intraday_regions is defined and bundle_region in intraday_regions) or ("itd_" in bundle_region) -%}
    portfolio.trade.operation(
      "IntradayPosPush",
      addr: "{{pos_push_addr_map[bundle_region]}}",
      strategy: "{{ portf_nm }}",
      dump_dir: "pos_push",
      timeout: 5,
    )
    {% else -%}
    portfolio.trade.operation(
      "PosPush",
      addr: "{{pos_push_addr_map[bundle_region]}}",
      strategy: "{{ portf_nm }}",
      dump_dir: "pos_push",
      timeout: 5,
    )
    {% endif -%}
    {% endif -%}
    {%- endblock pos_push -%}
    {%- endif -%}
    
    {%- if is_fict_pf is defined and is_fict_pf %}
    
    global.user_alpha_ids = {{ user_alpha_ids }}
    use "cfg-template/pulse_configrc/fict_pf.pconf"
    {% endif -%}
    
    {% if group_stats_names is defined %}
    factory("GroupStatsSimple", lang: "cpp")
    {% for name in group_stats_names %}
    {% if (intraday_regions is defined and bundle_region in intraday_regions) or ("itd_" in bundle_region)  %}
    portfolio.stats_list << global.intraday_stock_group_stats[:{{name}}]
    {% else -%}
    portfolio.stats_list << global.stock_group_stats[:{{name}}]
    {% endif -%}
    {%- endfor -%}
    {% endif -%}
    {% endblock pf -%}
    
    {%- block external %}
    
    # EXTERNAL SERVICES
    
    {% block alpha_store -%}
    
    {% if alpha_store is defined and alpha_store -%}
    env.alpha_store = {
    {% for key, value in alpha_store.items() %}  {{key}}: {{value | tojson }},
    {% endfor -%}
    }
    {% endif -%}
    {% endblock alpha_store -%}
    
    {% if alpha_store_sender is defined and alpha_store_sender -%}
    env.alpha_store_sender = {
    {% for key, value in alpha_store_sender.items() %}  {{key}}: {{ value | tojson }},
    {% endfor -%}}
    {% endif -%}
    
    {% if alpha_store_hosts is defined and alpha_store_hosts -%}
    if env.to_h.has_key?(:alpha_store)
      env.alpha_store[:hosts] = {{ alpha_store_hosts | tojson }}
    end
    {% endif -%}
    
    {% if alpha_store_auth_token is defined and alpha_store_auth_token -%}
    if env.to_h.has_key?(:alpha_store)
      env.alpha_store[:auth_token] = {{ alpha_store_auth_token | tojson }}
    end
    {% endif -%}
    
    {% block price_server_map %}
    {% if price_server_map is defined and price_server_map -%}
    if defined?(basedata)
    basedata.delete_field(:price_server)
    basedata.price_server_map = {
    {% for key, value in price_server_map.items() %}  {{key}}: {{ value | tojson }},
    {% endfor -%}}
    end
    {%- endif -%}
    {% endblock price_server_map %}
    
    {% block future_price_server_map -%}
    {% if future_price_server_map is defined and future_price_server_map -%}
    if defined?(contract_basedata)
    contract_basedata.delete_field(:price_server)
    contract_basedata.price_server_map = {
    {% for key, value in future_price_server_map.items() %}  {{key}}: {{ value | tojson }},
    {% endfor -%}}
    end
    {%- endif -%}
    {% endblock future_price_server_map %}
    
    {%- if monitor is defined %}
    
    env.monitor = {
    {% for key, value in monitor.items() %}  {{key}}: {{value | tojson }},
    {% endfor -%}}
    {% endif -%}
    {% endblock external -%}
    
    {%- if extra_pconf_lines is defined %}
    
    # Extra pconfs
    {%- for line in extra_pconf_lines %}
    {{line}}
    {%- endfor -%}
    {% endif -%}
    
    {%- if ny5 is defined and ny5 -%}
    
    {%- if ny5_extra_pconf_lines is defined %}
    
    # Extra pconfs (only applicable on ny5)
    {%- for line in ny5_extra_pconf_lines %}
    {{line}}
    {%- endfor -%}
    {% endif -%}
    
    {%- else -%}
    
    {%- if gr_extra_pconf_lines is defined %}
    
    # Extra pconfs (only applicable for GR)
    {%- for line in gr_extra_pconf_lines %}
    {{line}}
    {%- endfor -%}
    {% endif -%}
    
    {% endif -%}
    
    

    Always see this [Error (where: parser) in base.pconf | Line 1 Col 28 near '['] Expected either a number, string, keyword or identifier.

    question feature request 
    opened by dolong2110 1
  • TemplateSet.FromCache would get error result when use multi loaders

    TemplateSet.FromCache would get error result when use multi loaders

    I have two loaders, first is NewLocalFileSystemLoader and second is NewFSLoader with embed.FS, when I use FromFile, I could get right result, but FromCache always got error. From source code https://github.com/flosch/pongo2/blob/master/template_sets.go#L140, I add a debg print

      name = set.resolveFilenameForLoader(loader, tpl, path)
      fd, err = loader.Get(name)
    + fmt.Println(path)
    

    FromFile got abspath and relpath, but FromCache always got abspath, the problem is at https://github.com/flosch/pongo2/blob/master/template_sets.go#L175, why use cleanedFilename with first loader instead of filename?

    bug needs evaluation 
    opened by honmaple 0
  • Make Autoescape a template parameter

    Make Autoescape a template parameter

    Currently the only way to set autoescape is either via a template directive, or globally via pongo2.SetAutoescape. There's no way to set it for individual template sets or before template execution via Options.

    The request here is to expand the Options object to allow controlling the Autoescape parameter's default value prior to template execution.

    feature request 
    opened by wrouesnel 0
  • add the ability to set variables through inline definitions

    add the ability to set variables through inline definitions

    this PR is an attempt to add support for inline variables into pongo2, allowing templates to be used for cases where there's a predefined set of values to be looped through.

    this is the first time I am touching a parser, so I am not sure if this is the right way to go with it, I'd be interested in getting feedback or I'd be okay if someone would like to take over to finish it.

    opened by karakanb 5
  • exec tag added to enable treating evaluated string as a part of the t…

    exec tag added to enable treating evaluated string as a part of the t…

    Description of the change

    Idea is to provide users a functionality so that by using {% exec %} templatetag, they can evaluate a string-based template (say passed as an argument) as a part of the original template.

    For example, user can define a macro in a string and use that in the same execution flow.

    Our use case was that the user can define macros in yaml and then call it from the yaml itself and we should be able to treat the macro as one of the predefined macros. Earlier we were doing two step evaluation but that limited the capability of the system.

    We could not define this templateTag from outside as it has to use few variables private to the package.

    func test() {
    	tpl, err := pongo2.FromFile("some_file.template")
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	c1 := `{% macro double(arg) %}{{2*arg}}{% endmacro %}`
    	c2 := "{{ double(10) }}"
    	res, err := tpl.Execute(pongo2.Context{"c1": c1, "c2": c2})
    	if err != nil {
    		log.Fatal(err)
    	}
    
    }
    

    some_file.template

    {% exec %}{{c1}}{% endexec %}
    {% exec %}{{c2}}{% endexec %}
    

    so effectively this file will be evaluated as

    {% macro double(arg) %}{{2*arg}}{% endmacro %}
    {{ double(10) }}
    

    and the result will be

    
    20
    
    opened by sprksh 2
Releases(v6.0.0)
  • v6.0.0(Jun 24, 2022)

    v6.0.0

    • Go 1.18 is now the minimum required Go version.
    • Improved block performance (#293).
    • Support for variable subscript syntax (for maps/arrays/slices), such as mymap["foo"] or myarray[0] (#281).
    • Backwards-incompatible change: block.Super won't be escaped anymore by default (#301).
    • nil is now supported in function calls (#277).

    Thanks to all contributors.

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Sep 13, 2020)

    Changes in this long awaited release:

    Library

    • First semver version with Go modules compatibility
    • Several bug fixes
    • Improved error handling
    • Several refactorings to speed up execution and reduce allocations, including support for io.Writerin Execute() functions and short-circuit evaluations in expressions
    • Add TemplateSet.FromBytes
    • Add RenderTemplateBytes
    • Add Template.ExecuteWriterUnbuffered
    • Add TemplateLoader interface and according functions for virtual filesystem support (incl. support for multiple loaders)
    • Add pongo2.SetAutoescape for a global behavior change
    • Add whitespace control for tags and blocks, supporting {%- and -%} for tags and pongo2.Options for blocks
    • Add pongo2.CleanCache to remove files from the template cache
    • Add support for template functions that return an error as the second return value
    • Add Template.ExecuteBlocks to render supplied list of blocks only

    See https://github.com/flosch/pongo2/compare/v3.0...v4.0.0 for a full list of changes. Thanks to all contributors!

    Template Language

    • Add support for single quotes in variables, functions and tags
    • Add support for if_exists-flag in include-tag
    • Add support for sorted-flag in for-tag with support for maps and arrays/slices
    • Add block.Super support
    • Add split filter
    Source code(tar.gz)
    Source code(zip)
  • v3.0(Oct 28, 2014)

  • v2.1(Oct 28, 2014)

  • v2(Oct 4, 2014)

    I'm happy to release the first major update for pongo2: v2. It got a lot of new features and bug fixes. Thanks to all reporters and contributors.

    This release is backwards-incompatible to v1 which means chances are you have to adapt your codebase (slightly) in order to use v2. The pongo2 playground already uses pongo v2 (including the new features like sandboxing) and now got the official pongo2-addons package enabled for testing and playing with pongo2. pongo2-addons is already ready to use with pongo v2.

    To install v2 and get backwards-compatible changes and bugfixes for later versions of the v2 series, use this import path:

    gopkg.in/flosch/pongo2.v2 (documentation)

    Use this import path to stick with the latest development version of pongo2:

    github.com/flosch/pongo2 (documentation)

    New major features

    • Template sets: pongo2 allows to group similar kind of templates using a technique called template sets (for example web vs. email templates). Users can apply different configurations and sandbox restrictions (see below) on a specific template set. A default template set is created when pongo2 is imported (this is the one all pongo2-global API functions like From* are working on); see the DefaultSet here. Features of the template sets include:
      • Debugging: If Debug is set to true, logging of specific errors occur to stdout (you can print out errors as well using the new ExecutionContext.Logf function which will only print out your logging information when Debug is true). Debug has implications on the new template caching function as well (see below).
      • Globals: It is now possible to provide a global context (in addition to a per-template context) for a template set. It's always possible to override global variables through a per-template context.
      • Base directory: The previous behavior of a filename lookup (inside templates, for example when using the include, extends or ssi-tag, or outside templates when calling the From*()-functions) was, in case of a relative path, to lookup the filename relative to the application's directory or, in case of an absolute path, to take this absolute one. It's now possible to change the base lookup directory (for relative paths) by using the new template set functions SetBaseDirectory() and BaseDirectory().
      • Sandboxing: To provide more security, pongo2 introduces a per-template-set sandbox. It can prohibit the usage of filters and tags or restrict file accesses (within templates when using a file-sensitive tag/filter like include or outside of templates when using a function like From*()). Use the attribute SandboxDirectories to provide path patterns supported by http://golang.org/pkg/path/filepath/#Match in order to restrict the access to specifc files or directories. You can limit the tag/filter access by using the two new template set functions BanFilter and BanTag.
    • Template caching: pongo2 introduces a new API function FromCache which behaves like FromFile, but includes caching: FromCache only compiles a template once per template (even if called multiple times) and can be called from multiple Goroutines (it's thread-safe). When debugging is activated (see above), FromCache will re-compile the given template on any request (simplifies development to see live changes).
    • Macro imports/exports: pongo2 supports now importing and exporting of macros. Exporting is done by appending the export keyword to your macro declaration (like this: {% macro my_exported_macro(args1, args2="default string") export %}). You can import exported macros by using the new import tag: {% import "my_file_with_macros.html" my_exported_macro, another_exported_macro as renamed_macro %}. Macros import macros (chaining macros) is supported.
    • New pongo2-specific tag set: Sets a variable to a given expression like this: {% set my_variable = 5 + 10 / another_var_number %}

    New minor features

    • Added support for the reversed argument for the for-tag
    • elif-tag added (to support multiple cases when using the if-tag)
    • It's now possible to replace the behavior of already registered tags and filters through 2 new API-functions: ReplaceTag and ReplaceFilter.
    • It's now possible to mark a pongo2.Value as safe (so the escape filter won't get applied when outputting the value) using the new API-function AsSafeValue. This reduces the necessary to apply the safe filter manually, for example when using the markdown filter from the pongo2-addons package.
    • New Error type which returns detailed machine-readable information (including the affected raw template line) about the error occurred and is now much more specific in some cases on which error occurred

    Bugfixes and other improvements

    • Better UTF-8 handling of filters and tags
    • Performance of template execution improved
    • Bugfix in handling of the parsed argument of the ssi-tag
    • Bugfix related to the operator associativity
    • Better documentation (but still not perfect)

    Notable backward-incompatible API-changes (v1 <-> v2):

    • The interface type INodeEvavluator got replaced by IEvaluator
    • Function signature for tag and filter parsing/execution changed (error return type changed to *Error).

    See the whole changelog here: https://github.com/flosch/pongo2/compare/v1...v2

    As always, I'm happy about any feedback!

    Source code(tar.gz)
    Source code(zip)
  • v1.0(Aug 8, 2014)

    I'm happy to announce pongo2 v1.0, the first stable release.

    pongo2 aims to be compatible with Django 1.7 with regards to syntax, filters and tags. In combination with my official package pongo2-addons pongo2 offers even more filters/tags including humanization and markup features.

    All version 1.x releases will remain backwards compatible (only API improvements are possible, but no changes to any existing API functions/symbols). You can use the special import path

    gopkg.in/flosch/pongo2.v1

    to stick with version 1.x releases in your projects.

    List of TODOs which could effect users of version 1.0:

    • tag verbatim does not take a parameter yet
    • block.super not supported yet
    • Value.Iterate() over strings is not utf-8 compatible yet (probably rarely used by users)

    Please also have a look on the caveats and on the development status hints when using pongo2.

    pongo2 got a playground; feel free to play with it and to try pongo2 out.

    I'm always glad about any feedback. I hope you enjoy this release!

    Source code(tar.gz)
    Source code(zip)
  • v1.0-rc1(Jul 29, 2014)

Owner
Florian Schlachter
Computer scientist with interests in compilers/programming languages, security & privacy, hardware architectures, networking and web development.
Florian Schlachter
An ERB-style templating language for Go.

Ego Ego is an ERb style templating language for Go. It works by transpiling templates into pure Go and including them at compile time. These templates

Ben Johnson 538 Nov 23, 2022
A strongly typed HTML templating language that compiles to Go code, and has great developer tooling.

A language, command line tool and set of IDE extensions that makes it easier to write HTML user interfaces and websites using Go.

Adrian Hesketh 147 Nov 27, 2022
Templating system for HTML and other text documents - go implementation

FAQ What is Kasia.go? Kasia.go is a Go implementation of the Kasia templating system. Kasia is primarily designed for HTML, but you can use it for any

Michał Derkacz 74 Mar 15, 2022
A sweet velvety templating package

Velvet Velvet is a templating package for Go. It bears a striking resemblance to "handlebars" based templates, there are a few small changes/tweaks, t

Buffalo - The Go Web Eco-System 73 Apr 14, 2022
Toothpaste is a simple templating engine for Go web applications, inspired by Blade/Twig

A simple HTML templating engine in Go inspired by Twig. Currently supports Variables, Escaping, If statements, Templating and Functional variables.

Mats 4 Nov 7, 2022
Article spinning and spintax/spinning syntax engine written in Go, useful for A/B, testing pieces of text/articles and creating more natural conversations

GoSpin Article spinning and spintax/spinning syntax engine written in Go, useful for A/B, testing pieces of text/articles and creating more natural co

Miles Croxford 41 Nov 17, 2022
The mustache template language in Go

Overview mustache.go is an implementation of the mustache template language in Go. It is better suited for website templates than Go's native pkg/temp

Michael Hoisie 1.1k Nov 24, 2022
Django style fixtures for Golang's excellent built-in database/sql library.

go-fixtures Django style fixtures for Golang's excellent built-in database/sql library. Currently only YAML fixtures are supported. There are two rese

Richard Knop 29 Sep 26, 2022
Validate Django auth session in Golang

GoDjangoSession Valid for django 3.0.5 Usage: package main import ( "encoding/base64" "fmt" "session/auth" "github.com/Kuzyashin/GoDjangoSession"

Alexey Kuzyashin 27 Aug 23, 2022
Amber is an elegant templating engine for Go Programming Language, inspired from HAML and Jade

amber Notice While Amber is perfectly fine and stable to use, I've been working on a direct Pug.js port for Go. It is somewhat hacky at the moment but

Ekin Koc 895 Nov 13, 2022
An ERB-style templating language for Go.

Ego Ego is an ERb style templating language for Go. It works by transpiling templates into pure Go and including them at compile time. These templates

Ben Johnson 538 Nov 23, 2022
A strongly typed HTML templating language that compiles to Go code, and has great developer tooling.

A language, command line tool and set of IDE extensions that makes it easier to write HTML user interfaces and websites using Go.

Adrian Hesketh 147 Nov 27, 2022
Assembly syntax that makes you feel like you're writing code in a high-level language.

shasm Assembly syntax that makes you feel like you're writing code in a high-level language. Shasm is not an Assembler. Shasm simply compiles Shasm sy

Shoyaaa 14 Jun 5, 2021
Templating system for HTML and other text documents - go implementation

FAQ What is Kasia.go? Kasia.go is a Go implementation of the Kasia templating system. Kasia is primarily designed for HTML, but you can use it for any

Michał Derkacz 74 Mar 15, 2022
A sweet velvety templating package

Velvet Velvet is a templating package for Go. It bears a striking resemblance to "handlebars" based templates, there are a few small changes/tweaks, t

Buffalo - The Go Web Eco-System 73 Apr 14, 2022
Templating system for HTML and other text documents - go implementation

FAQ What is Kasia.go? Kasia.go is a Go implementation of the Kasia templating system. Kasia is primarily designed for HTML, but you can use it for any

Michał Derkacz 74 Mar 15, 2022
Nomad Pack is a templating and packaging tool used with HashiCorp Nomad.

Nomad Pack is a templating and packaging tool used with HashiCorp Nomad.

HashiCorp 284 Nov 16, 2022
A project templating CLI tool.

Clonr Project Templating CLI About Installation Homebrew Go install npm Quick start for developers Configuring a project. Basic Example Example With G

null 3 Nov 21, 2022
Toothpaste is a simple templating engine for Go web applications, inspired by Blade/Twig

A simple HTML templating engine in Go inspired by Twig. Currently supports Variables, Escaping, If statements, Templating and Functional variables.

Mats 4 Nov 7, 2022
Generic templating tool with support of JSON, YAML and TOML data

gotempl Small binary used to generate files from Go Templates and data files. The following formats are supported: JSON YAML TOML Usage usage: gotempl

Link Society 7 Jun 15, 2022