Liquid Templating Guide
Liquid 4++ templating methods for DocOps Lab projects.
DocOps Lab’s Liquid 4 environment is invoked through a special bootstrapping procedure. It introduces numerous custom Liquid tags and filters.
Throughout DocOps Lab applications, Jekyll’s extended and modified version of Liquid 4 is standard.
This means all Jekyll’s filters and its special include tag are available within and outside Jekyll sites.
Custom Tags
Not all custom tags are always available, but the following are generally available in DocOps Lab projects:
| Tag Name | Source Gem | Usage Notes |
|---|---|---|
|
Jekyll |
Transcludes the content of another file, with optional variable arguments going in but no transcendent affect on the context. |
|
AsciiSourcerer |
Transcludes another file, with full pass-through of variables (no arguments needed) with full write access to the context (can add/change variables permanently). |
Liquid Filters
A canonical listing of custom filters is available in the AsciiSourcerer gem at lib/specs/data/liquid-filters.yml.
The full compendium includes all filters available in Liquid 5 and Jekyll 4, even though officially Jekyll and AsciiSourcerer standardize on Liquid 4. Shopify’s novel Liquid 5 filters are hard-coded in AsciiSourcerer.
| All other Shopify-sourced filters are conveyed directly from their Liquid 4.0.4 versions. |
Where official Jekyll filters override their Liquid 4 counterparts, the Jekyll versions are used. Where an AsciiSourcerer filter overrides either upstream counterpart, the AsciiSourcerer version is used.
Custom Filters
- Slugify (
slugify) -
Convert a string into a lowercase URL "slug".
This is not the Jekyll version. Category String Conversion
- Examples
-
Input
{{ "The _config.yml file" | slugify }}Outputthe-config-yml-fileInput{{ "The _config.yml file" | slugify: "_" }}Outputthe_config_yml_file
- Inspect (
inspect) -
Convert an object into its String representation for debugging. Overrides Jekyll’s
inspectfilter, adding an optionalformatargument:html(default) reproduces Jekyll’s own behavior exactly (an HTML-escapedObject#inspectstring, quotes become");yamlandjsonrender the object in those formats instead.Category Object Analysis
- Examples
-
Example 1. Default (html) format, matches Jekyll’s inspectInput
{{ tags_array | inspect }}Output["foo", "bar", "baz"]Example 2. YAML formatInput{{ tags_array | inspect: "yaml" }}Output--- - foo - bar - bazExample 3. JSON formatInput{{ tags_array | inspect: "json" }}Output["foo","bar","baz"]
- Sum (
sum) -
Sums a numeric array, or an array of Hashes at the given property.
(This filter duplicates Shopify’s
sumfilter.)Category Math Operations
- Examples
-
Input
{{ data.members | sum: "grad_year" }}Output6040
- Remove Last (
remove_last) -
Removes the last instance of a substring from a string.
(This filter duplicates Shopify’s
remove_lastfilter.)Category String Conversion
- Examples
-
Input
{{ "Ground control to Major Tom." | remove_last: "o" }}OutputGround control to Major Tm.
- Replace Last (
replace_last) -
Replaces the last instance of a substring in a string with a replacement.
(This filter duplicates Shopify’s
replace_lastfilter.)Category String Conversion
- Examples
-
Input
{{ "Ground control to Major Tom." | replace_last: "o", "0" }}OutputGround control to Major T0m.
- Squish (
squish) -
Strips leading and trailing whitespace and collapses interior runs of whitespace to a single space.
(This filter duplicates Liquid 5’s
squishfilter.)Category String Conversion
- Examples
-
Input
{{ " A string that is obviously longer than 25 characters " | squish }}OutputA string that is obviously longer than 25 characters
- Wrap (
wrap) -
Category String Conversion
- Examples
-
Input
{{ "A string that is obviously longer than 25 characters" | wrap: 25 }}OutputA string that is obviously longer than 25 characters
- Comment Wrap (
commentwrap) -
Category String Conversion
- Examples
-
Input
{{ comment_text | commentwrap: 25, "// " }}Output// A string that is // obviously longer than 25 // charactersInput{{ comment_text | commentwrap: 25, "xml" }}Output<!-- A string that is obviously longer than 25 characters -->Input{{ comment_text | commentwrap: 25, "/*|*/" }}Output/* A string that is obviously longer than 25 characters */
- Convert to CLI Arguments (
to_cli_args) -
Transform a Hash into a string of CLI-formatted arguments. Accepts an optional template name to format the output. See
parameterssection for all available templates and their output formats. When no template is specified, defaults tolong_spaceformat. Arguments are joined with a space by default; can be customized via delimiter parameter.Category Object Conversion
- Examples
-
Example 4. Default (long_space) formatInput
{{ my_flat_hash | to_cli_args }}Output--key1 valuu_one --key2 val_two --key3 third valueExample 5. Long equals formatInput{{ my_flat_hash | to_cli_args: "long_equals" }}Output--key1=valuu_one --key2=val_two --key3=third valueExample 6. Single-letter flags with valuesInput{{ cli_flags_hash | to_cli_args: "short_space" }}Output-k valuu_one -v val_two -o third valueExample 7. Positional arguments onlyInput{{ my_flat_hash | to_cli_args: "positional" }}Outputvaluu_one val_two third valueExample 8. Environment variable format (uppercase keys)Input{{ my_flat_hash | to_cli_args: "env_arg" }}OutputKEY1=valuu_one KEY2=val_two KEY3=third valueExample 9. Key=value formatInput{{ my_flat_hash | to_cli_args: "keyval" }}Outputkey1=valuu_one key2=val_two key3=third value
- Data objects to YAML (
to_yaml) -
Turn any parameter or data object into YAML format.
Category Object Conversion
- Examples
-
Input
{{ my_flat_hash | to_yaml }}Output--- key1: valuu_one key2: val_two key3: third valueInput{{ my_flat_hash | to_yaml: "flow" }}Output{key1: "valuu_one", key2: "val_two", key3: "third value"}Input{{ page.tags | to_yaml }}Output--- - Seattle - Tacoma - SpokaneInput{{ page.tags | to_yaml: "flow" }}Output["Seattle", "Tacoma", "Spokane"]Input{{ page.tags | to_yaml: "flow", "quotes" }}Output["Seattle", "Tacoma", "Spokane"]
- Data objects to JSON (
to_json) -
Turn any parameter or data object into JSON format.
Category Object Conversion
- Examples
-
Input
{{ my_flat_hash | to_json }}Output{"key1":"valuu_one","key2":"val_two","key3":"third value"}Input{{ page.tags | to_json }}Output["Seattle","Tacoma","Spokane"]Input{{ odd_keys_hash | to_json }}Output{"key 1":"valuu_one","$key2":"val_two","key:3":"third value"}
- Regular Expression Replace (
replace_regex) -
Use regular expressions to match and replace text patterns.
Category String Management
- Examples
-
Input
{{ "hello world" | replace_regex: "world", "there" }}Outputhello thereInput{{ "one,two,three" | replace_regex: ",", "-" }}Outputone-two-three
- Pattern Match (
match) -
Returns of string or number matches pattern.
Category String Analysis
- Examples
-
Input
{% assign matched = "testword" | match: "^.*word$" %} {% if matched %}It matched!{% endif %}OutputIt matched!
- Holds Liquid (
holds_liquid) -
Returns true if a snippet of text contains Liquid markup tags.
Category Object Analysis
- Examples
-
Input
{{ liquidy_text | holds_liquid }}OutputtrueInput{{ "This is just text." | holds_liquid }}Outputfalse
- Metastore list concat (
store_list_concat) -
Concatenates each Array-formatted value of the same-named property across all nodes in an Array of Hashes (Metastore). Accepts an Array of Hashes and the keyname of a property to collect from.
Category Array Management
- Examples
-
Input
{{ data.metastore | store_list_concat: "children" | jsonify }}Output["child1","child2","child3","child4","child5","child6"]
- Metastore list duplicates (
store_list_dupes) -
Returns a list of duplicate items among multiple Arrays across multiple same-named properties in an Array of Hashes (Metastore). Accepts an Array of Hashes and the keyname of a Scalar property to check; returns the names of duplicate properties.
Category Array Management
- Examples
-
Input
{{ data.metastore | store_list_dupes: "children" | jsonify }}Output["child1"]
Liquid Syntax Styles
DocOps Lab contributions should standardize around certain Liquid syntax conventions, namely around indentation and integration with various markup languages we generate from templates.
HTML Rendering Style
HTML is by far the most common output target for Liquid templates, but DocOps Lab house style prefers a certain form of indentation.
Our preference is to indent the Liquid tags in cadence with the surrounding HTML tags, so that the Liquid tags are visually aligned with the HTML they are generating.
{% for item in items %}
<div class="item">
<h2>{{ item.title }}</h2>
<p>
{{ item.description }}
{% if item.link %}
<hr>
<a href="{{ item.link }}">Read more</a>
{% endif %}
</p>
</div>
{% endfor %}
AsciiDoc Rendering Style
Because AsciiDoc does not involve much indentation, Liquid syntax meant to render AsciiDoc output is a little awkward.
Maintain left-flush, un-indented Liquid tags, but indent the tag internals to match the intended AsciiDoc output.
{%- for item in items %}
{{ item.title }};;
{{ item.description }}
{%- if item.link %}
Link:;;; {{ item.link }}
{%- endif %}
{% endfor %}
Use left-side whitespace control ({%-) to avoid extra blank lines in the output, but skip it on typical {% endfor %} tags to ensure a blank line between iterations where it matters.
YAML Rendering Style
YAML pre-processing with Liquid can be fairly straightforward. YAML is a great target for Liquid, even though indentation and whitespace control matter more than for HTML or AsciiDoc.
Intertwine Liquid on its own indentation scale and it should map to the YAML fairly well.
{%- for item in items %}
- title: {{ item.title }}
description: {{ item.description }}
{%- if item.link %}
link: {{ item.link }}
{%- endif %}
{% endfor %}
Means of Invocation
If you are developing a Ruby gem or app in the DocOps Lab ecosystem, the basic Jekyll/Liquid engine is invoked via the asciisourcerer gem.
require 'asciisourcerer'
Sourcerer::Rendering.render_outputs([
{
template: 'templates/release-notes.liquid',
data: 'data/release.yml',
out: 'build/docs/release-notes.md',
key: 'release',
attrs: 'README.adoc',
engine: 'liquid'
},
{
converter: 'MyProject::JsonRenderer',
data: 'data/release.yml',
out: 'build/api/release.json'
}
])
Direct invocation of Liquid rendering is also possible, but the above method is recommended for most use cases in DocOps Lab projects, as it provides a consistent user experience in terms of availability and behavior of tags and filters.