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.
go get gopkg.in/osteele/liquid.v1
# latest snapshot
go get -u github.com/osteele/liquid
# development version
engine := liquid.NewEngine()
template := `<h1>{{ page.title }}</h1>`
bindings := map[string]any{
"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>
See the API documentation for additional examples.
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!
These features of Shopify Liquid aren't implemented:
{{ image | img_url: '580x', scale: 2 }}
. [Issue #42]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() any
, 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.
Render
and friends take a Bindings
parameter. This is a map of string
to
any
, 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
and
, or
, {% if %}
, {% elsif %}
, and {% case %}
.array[1]
; array[n]
, where
array
has an array value and n
has an integer value.{% for item in (1..5) %}
, {% for item in (start..end) %}
where start
and end
have
integer values.1 == 1.0
evaluates to true
. Similarly, int8(1)
, int16(1)
, uint8(1)
etc.
are all ==
.<
, >
, <=
,
>=
. Integers and floats can be usefully compared with each other. Strings
can be usefully compared with each other, but not with other values. Any
other comparison, e.g. 1 < "one"
, 1 > "one"
, is always false.array[1]
; array[n]
where n
has an integer value.first
, last
, and size
properties: array.first == array[0]
, array[array.size-1] == array.last
(where array.size > 0
)hash["key"]
; hash[s]
where s
has a
string valuehash.key
size
property, that returns the size of the map.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.]value.FieldName
, value["fieldName"]
.liquid:βnameβ
is accessed as value.name
instead.value.Func
, value["Func"]
.value.size
property.[]byte
[]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
yaml.MapSlice
acts as a map. It implements m.key
,
m[key]
, and m.size
.Bug reports, test cases, and code contributions are more than welcome. Please refer to the contribution guidelines.
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
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.
See Shopify's ports of Liquid to other environments.
MIT License