1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-30 07:18:58 +01:00
Go to file
Oliver Steele 9234f55cd9
Merge pull request #29 from nsf/master
Properly handle variadic functions.
2018-05-30 15:50:03 -04:00
.github Update guidelines to refer to issues board 2017-07-09 19:33:09 -04:00
cmd/liquid Coverage 2017-07-19 10:03:11 -04:00
evaluator Package docs 2017-08-08 16:42:32 -04:00
expressions Package docs 2017-08-08 16:42:32 -04:00
filters Match Ruby string split semantics 2017-09-04 17:51:51 -04:00
parser Follow go style guide re declaring empty slices 2017-09-03 12:13:20 -04:00
render Default time format is compatible w/ Liquid 2017-08-18 10:43:31 -04:00
scripts CLI script to run shopify liquid for cf. 2017-07-16 13:42:09 -04:00
tags Define IterationKeyedMap 2017-08-15 18:49:29 -04:00
values Properly handle variadic functions. 2018-05-30 19:44:29 +05:00
.appveyor.yml Appveyor: remove mingw 2017-08-08 14:54:47 -04:00
.gitignore gitgnore *.test 2017-07-22 08:20:41 -04:00
.travis.yml Travis: add go 1.10; drop 1.8 2018-03-02 11:41:48 -05:00
CONTRIBUTING.md Remove obsolete note re Awesome Go 2017-07-21 11:36:35 -04:00
drops_test.go More drop examples 2017-08-08 16:25:23 -04:00
drops.go Add FromDrop func 2017-07-11 13:35:12 -04:00
engine_examples_test.go More drop examples 2017-08-08 16:25:23 -04:00
engine_test.go Tests 2017-07-26 10:12:25 -04:00
engine.go Merge pull request #26 from Proximaio/feature/customise_delimiters 2017-07-27 18:09:33 -04:00
LICENSE Create LICENSE 2017-06-26 15:36:29 -04:00
liquid_test.go Define IterationKeyedMap 2017-08-15 18:49:29 -04:00
liquid.go Define IterationKeyedMap 2017-08-15 18:49:29 -04:00
Makefile make lint includes tests 2017-07-26 10:12:25 -04:00
README.md More drop examples 2017-08-08 16:25:23 -04:00
template_test.go Benchmarks 2017-07-22 08:04:09 -04:00
template.go Source location is an initialization parameter 2017-07-14 10:38:30 -04:00

Liquid Template Parser

liquid is a pure Go implementation of Shopify Liquid templates. It was developed for use in the Gojekyll port of the Jekyll static site generator.

Compatibility

These features of Shopify Liquid aren't implemented:

  • Warn and lax error modes.
  • Non-strict filters. An undefined filter is currently an error.
  • Strict variables. An undefined variable is not an error.

Drops have a different design from the Shopify (Ruby) implementation. A Ruby drop sets liquid_attributes to a list of attributes that are exposed to Liquid. A Go drop implements ToLiquid() interface{}, that returns a proxy object. Conventionally, the proxy is a map or struct that defines the exposed properties. See http://godoc.org/github.com/osteele/liquid#Drop for additional information.

Stability

This library is at an early stage of development. It has been mostly used by its author.

Only the liquid package itself, and the sub-package types that are used in that top-level package, are guaranteed stable. For example, render.Context is documented as the parameter type for tag definitions; it therefore won't change incompatibly, if ever, until at least version 2 (at which point gopkg.in/osteele/liquid.v1 will continue to pin to the v1 implementation).

Install

go get gopkg.in/osteele/liquid.v1 # latest snapshot

go get -u github.com/osteele/liquid # development version

Usage

engine := liquid.NewEngine()
template := `<h1>{{ page.title }}</h1>`
bindings := map[string]interface{}{
    "page": map[string]string{
        "title": "Introduction",
    },
}
out, err := engine.ParseAndRenderString(template, bindings)
if err != nil { log.Fatalln(err) }
fmt.Println(out)
// Output: <h1>Introduction</h1>

Command-Line tool

go install gopkg.in/osteele/liquid.v0/cmd/liquid installs a command-line liquid executable. This is intended to make it easier to create test cases for bug reports.

$ liquid --help
usage: liquid [FILE]
$ echo '{{ "Hello World" | downcase | split: " " | first | append: "!"}}' | liquid
hello!

Values

Render and friends take a Bindings parameter. This is a map of string to interface{}, that associates template variable names with Go values.

Any Go value can be used as a variable value. These values have special meaning:

  • false and nil
    • These, and no other values, are recognized as false by and, or, {% if %}, {% elsif %}, and {% case %}`.
  • Integers
    • (Only) integers can be used as array indices: array[1]; array[n], where array has an array value and n has an integer value.
    • (Only) integers can be used as the endpoints of a range: {% for item in (1..5) %}, {% for item in (start..end) %} where start and end have integer values.
  • Integers and floats
    • Integers and floats are converted to their join type for comparison: 1 == 1.0 evaluates to true. Similarly, int8(1), int16(1), uint8(1) etc. are all ==.
    • [There is currently no special treatment of complex numbers.]
  • Integers, floats, and strings
    • Integers, floats, and strings can be used in comparisons <, >, <=, >=. Integers and floats can be meaningfully compared with each other. Strings can be meaningfully compared with each other but not with other values. Any other comparison, e.g. 1 < "one", 1 > "one", will always be false.
  • Arrays (and slices)
    • An array can be indexed by integer array[1]; array[n] where n has an integer value.
    • Arrays have first, last, and size properties: array.first == array[0], array[array.size-1] == array.last (where array.size > 0)
  • Maps
    • A map can be indexed by a string: hash[“key”]; hash[s] where s has a string value
    • A map can be accessed using property syntax hash.key
    • Maps have a special size property, that returns the size of the map.
  • Drops
    • A value value of a type that implements the Drop interface acts as the value value.ToLiquid(). There is no guarantee about how many times ToLiquid will be called. [This is in contrast to Shopify Liquid, which both uses a different interface for drops, and makes stronger guarantees.]
  • Structs
    • A public field of a struct can be accessed by its name: value.FieldName, value[“fieldName”].
      • A field tagged e.g. liquid:”name” is accessed as value.name instead.
      • If the value of the field is a function that takes no arguments and returns either one or two arguments, accessing it invokes the function, and the value of the property is its first return value.
      • If the second return value is non-nil, accessing the field panics instead.
    • A function defined on a struct can be accessed by function name e.g. value.Func, value[“Func”].
      • The same rules apply as to accessing a func-valued public field.
    • Note that despite being array- and map-like, structs do not have a special value.size property.
  • []byte
    • A value of type []byte is rendered as the corresponding string, and presented as a string to filters that expect one. A []byte is not (currently) equivalent to a string for all uses; for example, a < b, a contains b, hash[b] will not behave as expected where a or b is a []byte.
  • MapSlice
    • An instance of yaml.MapSlice acts as a map. It implements m.key, m[key], and m.size.

Contributing

Bug reports, test cases, and code contributions are more than welcome. Please refer to the contribution guidelines.

References

Attribution

Package Author Description License
Ragel Adrian Thurston scanning expressions MIT
gopkg.in/yaml.v2 Canonical MapSlice Apache License 2.0

Michael Hamrah's Lexing with Ragel and Parsing with Yacc using Go was essential to understanding go yacc.

The original Liquid engine, of course, for the design and documentation of the Liquid template language. Many of the tag and filter test cases are taken directly from the Liquid documentation.

Other Implementations

Go

Other Languages

See Shopify's ports of Liquid to other environments.

License

MIT License