xslate

package module
v0.0.0-...-6a6eb0f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 21, 2018 License: MIT Imports: 15 Imported by: 0

README

xslate

Attempt to port Perl5's Text::Xslate to Go

Build Status

GoDoc

Play with it!

Go-Xslate Playground is a little toy that allows you to try out Xslate template rendering. Note that for obvious reasons you cannot use directives that use external templates, such as WRAPPEr and INCLUDE

If you find templates that you think should work but doesn't, please file an issue using this service. You need to first "share" the current template that you're using, and then copy that new generated URL to file the issue.

Description

This is an attempt to port Text::Xslate from Perl5 to Go.

Xslate is an extremely powerful virtual machine based template engine.

Why Would I Choose xslate over text/template?

I believe there are at least two reasons you would choose Xslate over the basic text/template or html/template packages:

Template flexibility

IMHO, the default TTerse syntax is much more expressive and flexible. With WRAPPERs and INCLUDEs, it is possible to write a very module set of templates. YMMV

Dynamic/Automatic Reloading

By default Xslate expects that your template live in the file system -- i.e. outside of your go code. While text/template expects that you manage loading of templates yourself. Xslate handles all this for you. It searches for templates in the specified path, does the compilation, and handles caching, both on memory and on file system.

Xslate is also designed to allow you to customize this behavior: It should be easy to create a template loader that loads from databases and cache into memcached and the like.

Current Status

Currently:

  • I'm aiming for port of most of TTerse syntax
  • See VM Progress for what the this xslate virtual machine can handle
  • VM TODO: cleanup, optimization
  • Parser is about 90% finished.
  • Compiler is about 90% finished.
  • Pluggable syntax isn't implemented at all.
  • Need to come up with ways to register functions.

For simple templates, you can already do:

package main

import (
  "log"
  "github.com/lestrrat-go/xslate"
)

func main() {
  xt, err := xslate.New()
  if err != nil { // xslate.New may barf because it by default tries to
                  // initialize stuff that may want to access the filesystem
    log.Fatalf("Failed to create xslate: %s", err)
  }

  // This uses RenderString() -- which is fine in itself and as an example,
  // but the real use case for Xslate is loading templates from other
  // locations, such as the filesystem. For this case yo uprobably
  // want to use RenderInto() or Render()
  template := `Hello World, [% name %]!`
  output, err := xt.RenderString(template, xslate.Vars { "name": "Bob" })
  if err != nil {
    log.Fatalf("Failed to render template: %s", err)
  }
  log.Printf(output)
}

See Supported Syntax (TTerse) for what's currently available

Debugging

Currently the error reporting is a bit weak. What you can do when you debug or send me bug reports is to give me a stack trace, and also while you're at it, run your templates with XSLATE_DEBUG=1 environment variable. This will print out the AST and ByteCode structure that is being executed.

Caveats

Functions

In Go, functions that are not part of current package namespace must be qualified with a package name, e.g.:

time.Now()

This works fine because you can specify this at compile time, but you can't resolve this at runtime... which is a problem for templates. The way to solve this is to register these functions as variables:

template = `
  [% now() %]
`
tx.RenderString(template, xslate.Vars { "now": time.Now })

But this forces you to register these functions every time, as well as having to take the extra care to make names globally unique.

tx := xslate.New(
  functions: map[string]FuncDepot {
    // TODO: create pre-built "bundle" of these FuncDepot's
    "time": FuncDepot { "Now": time.Now }
  }
)
template := `
  [% time.Now() %]
`
tx.RenderString(template, ...)

Comparison Operators

The original xslate, written for Perl5, has comparison operators for both numeric and string ("eq" vs "==", "ne" vs "!=", etc). In go-xslate, there's no distinction. Both are translated to the same opcode (XXX "we plan to", that is)

So these are the same:

[% IF x == 1 %]...[% END %]
[% IF x eq 1 %]...[% END %]

Accessing Fields

Only public struc fields are accessible from templates. This is a limitation of the Go language itself. However, in order to allow smooth(er) migration from p5-Text-Xslate to go-xslate, go-xslate automatically changes the field name's first character to uppercase.

So given a struct like this:

  x struct { Value int }

You can access Value via value, which is common in p5-Text-Xslate

  [% x.value # same as x.Value %]

Documentation

Overview

Package xslate is the main interface to the Go version of Xslate.

Xslate is an extremely powerful template engine, based on Perl5's Text::Xslate module (http://xslate.org/). Xslate uses a virtual machine to execute pre-compiled template bytecode, which gives its flexibility while maitaining a very fast execution speed.

You may be thinking "What? Go already has text/template and html/template!". You are right in that this is another added complexity, but the major difference is that Xslate assumes that your template data resides outside of your go application (e.g. on the file system), and properly handles updates to those templates -- you don't have to recompile your application or write freshness checks yourselve to get the updates reflected automatically.

Xslate does all that, and also tries its best to keep things fast by creating memory caches and file-based caches.

It also supports a template syntax known as TTerse, which is a simplified version of the famous Template-Toolkit (http://www.template-toolkit.org) syntax, which is a full-blown language on its own that allows you to create flexible, rich templates.

The simplest way to use Xslate is to prepare a directory with Xslate templates (say, "/path/to/tempalte"), and do something like the following:

tx, _ := xslate.New(xslate.Args {
  "Loader": xslate.Args {
    "LoadPaths": []string { "/path/to/templates" },
  },
})
output, _ := tx.Render("main.tx", xslate.Vars { ... })
fmt.Println(output)

By default Xslate loads templates from the filesystem AND caches the generated compiled bytecode into a temporary location so that the second time the same template is called, no parsing is required.

Note that RenderString() DOES NOT CACHE THE GENERATED BYTECODE. This has significant effect on performance if you repeatedly call the same template. It is strongly recommended that you use the caching layer to boost performance.

Index

Examples

Constants

This section is empty.

Variables

View Source
var Debug = false

Debug enables debug output. This can be toggled by setting XSLATE_DEBUG environment variable.

Functions

func DefaultCompiler

func DefaultCompiler(tx *Xslate, args Args) error

DefaultCompiler sets up and assigns the default compiler to be used by Xslate. Given an unconfigured Xslate instance and arguments, sets up the compiler of said Xslate instance. Current implementation just uses compiler.New()

func DefaultLoader

func DefaultLoader(tx *Xslate, args Args) error

DefaultLoader sets up and assigns the default loader to be used by Xslate.

func DefaultParser

func DefaultParser(tx *Xslate, args Args) error

DefaultParser sets up and assigns the default parser to be used by Xslate.

func DefaultVM

func DefaultVM(tx *Xslate, args Args) error

DefaultVM sets up and assigns the default VM to be used by Xslate

Types

type Args

type Args map[string]interface{}

Args is the concret type that implements `ConfigureArgs`. Normally this is all you need to pass to `New()`

func (Args) Get

func (args Args) Get(key string) (interface{}, bool)

Get retrieves the value assigned to `key`

type ConfigureArgs

type ConfigureArgs interface {
	Get(string) (interface{}, bool)
}

ConfigureArgs is the interface to be passed to `Configure()` method. It just needs to be able to access fields by name like a map

type Vars

type Vars vm.Vars

Vars is an alias to vm.Vars, declared so that you (the end user) does not have to import two packages just to use Xslate

type Xslate

type Xslate struct {
	Flags    int32
	VM       *vm.VM
	Compiler compiler.Compiler
	Parser   parser.Parser
	Loader   loader.ByteCodeLoader
}

Xslate is the main package containing all the goodies to execute and render an Xslate template

Example
tx, err := New(Args{
	"Parser": Args{
		"Syntax": "TTerse",
	},
	"Loader": Args{
		"LoadPaths": []string{"/path/to/templates"},
	},
})
if err != nil {
	log.Fatalf("Failed to create Xslate: %s", err)
}
output, err := tx.Render("foo.tx", nil)
if err != nil {
	log.Fatalf("Failed to render template: %s", err)
}
fmt.Fprintf(os.Stdout, output)
Output:

func New

func New(args ...Args) (*Xslate, error)

New creates a new Xslate instance. If called without any arguments, creates a new Xslate instance using all default settings.

To pass parameters, use `xslate.Vars`

Possible Options:

  • ConfigureLoader: Callback to setup the Loader. See DefaultLoader
  • ConfigureParser: Callback to setup the Parser. See DefaultParser
  • ConfigureCompiler: Callback to setup the Compiler. See DefaultCompiler
  • ConfigureVM: Callback to setup the Virtual Machine. See DefaultVM
  • Parser: Arbitrary arguments passed to ConfigureParser function
  • Loader: Arbitrary arguments passed to ConfigureLoader function
  • Compiler: Arbitrary arguments passed to ConfigureCompiler function
  • VM: Arbitrary arguments passed to ConfigureVM function

func (*Xslate) Configure

func (tx *Xslate) Configure(args ConfigureArgs) error

Configure is called automatically from `New()` to configure the xslate instance from arguments

func (*Xslate) DumpAST

func (tx *Xslate) DumpAST(b bool)

DumpAST sets the flag to dump the abstract syntax tree after parsing the template. Use of this method is only really useful if you know the internal repreentation of the templates

func (*Xslate) DumpByteCode

func (tx *Xslate) DumpByteCode(b bool)

DumpByteCode sets the flag to dump the bytecode after compiling the template. Use of this method is only really useful if you know the internal repreentation of the templates

func (Xslate) Render

func (tx Xslate) Render(name string, vars Vars) (string, error)

Render loads the template specified by the given name string. By default Xslate looks for files in the local file system, and caches the generated bytecode too.

If you wish to, for example, load the templates from a database, you can change the generated loader object by providing a `ConfigureLoader` parameter in the xslate.New() function:

xslate.New(Args {
  "ConfigureLoader": func(tx *Xslate, args Args) {
    tx.Loader = .... // your custom loader
  },
})

`Render()` returns the resulting text from processing the template. `err` is nil on success, otherwise it contains an `error` value.

func (*Xslate) RenderInto

func (tx *Xslate) RenderInto(w io.Writer, template string, vars Vars) error

RenderInto combines Render() and writing its results into an io.Writer. This is a convenience method for frameworks providing a Writer interface, such as net/http's ServeHTTP()

func (*Xslate) RenderString

func (tx *Xslate) RenderString(template string, vars Vars) (string, error)

RenderString takes a string argument and treats it as the template content. Like `Render()`, this template is parsed and compiled. Because there's no way to establish template "freshness", the resulting bytecode from `RenderString()` is not cached for reuse.

If you *really* want to change this behavior, it's not impossible to bend Xslate's Loader mechanism to cache strings as well, but the main Xslate library will probably not adopt this feature.

Directories

Path Synopsis
cli
internal
Package loader abstracts the top-level xslate package from the job of loading the bytecode from a key value.
Package loader abstracts the top-level xslate package from the job of loading the bytecode from a key value.
Package vm implements the virtual machine used to run the bytecode generated by http://github.com/lestrrat-go/xslate/compiler The virtual machine is an extremely simple one: each opcode in the bytecode sequence returns the next opcode to execute.
Package vm implements the virtual machine used to run the bytecode generated by http://github.com/lestrrat-go/xslate/compiler The virtual machine is an extremely simple one: each opcode in the bytecode sequence returns the next opcode to execute.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL