Liquid Filters

mdsh now has a new feature, inspired by Liquid filters.

The Liquid templating system was created by Shopify and is used in the templating system of Jekyll.

Here's a description of "liquid filters" from the liquid filters documentation:

Filters are simple methods that modify the output of numbers, strings, variables and objects. They are placed within an output tag {{ }} and are denoted by a pipe character |.

As mdsh is written in shell, and uses mo as its Mustache library, I've implemented a rip-off version of liquid filters.

You can use the filters in your .mustache templates files, and in your .mdsh source files. You pass the variables through a filter using the pipe symbol |.

Usage and examples:

1. Template usage

Filtering basic page data (strings):

<h2>{{page_name | uppercase}}</h2>

^ this will output the page title in upper case.

Here is a more advanced example:

<h2>{{page_name | truncate_words 6 ".." | strip_newlines}}</h2>

^ this will truncate to 6 words, and append `..` if truncated, and strip new lines.

These filters also can also be applied to whole sections (if you must!):

{{page_header | strip_html}}

Filtering arrays:

In your templates various places use arrays to iterate over lists, such as recent posts. These lists can also be "filtered", in much the same way as the page data variables described above.

In your templates, normal `arrays` work as iterators, that can also take filters.

For example:

{{#someArray | sort_array desc | limit 3}}
  {{. | titlecase}}
{{/someArray}}

Associative arrays also work nicely with the `foreach` iterator:

{{#foreach item in someAssocArray | sort_by "age" "asc" | limit 3}}
  Hi {{item.name | titlecase}},
  at {{item.address | uppercase | newline_to_br}}
{{/foreach}}

2. Markdown usage

You can even use them in the sub-shells of your `*.mdsh` source files:

< ?bash echo "$something" | replace_all foo bar ;? >

Available filters:

Here is a list of all the filters available:

String filters

Here is the general usage:

{{someString | <filter> [options]}}
uppercase

Make text upper case:

{{someString | uppercase}}
lowercase

Make text lower case

{{someString | lowercase}}
titlecase

Make text title case

{{someString | titlecase}}
capitalise

Capitalise first-letter of string, lower case the rest

{{someString | capitalise}}
slugify

Convert string to slug

{{someString | slugify}}
camelcase_to_slug

Convert camel case string to a slug

{{someString | camelcase_to_slug}}
slug_to_camelcase

Convert a slug to camel case

{{someString | slug_to_camelcase}}
lstrip

Remove leading whitepace from (left of string)

{{someString | lstrip}}
rstrip

Remove trailing whitepace from (right of string)

{{someString | rstrip}}
strip

Remove leading and trailing whitespace

{{someString | strip}}
strip_html

Remove all HTML tags, keeping the inner content

{{someString | strip_html}}
strip_newlines

Strip newline characters from string

{{someString | strip_newlines}}
escape_html

Replace `<p>` with `&lt;p&gt;`

{{someString | escape_html}}
unescape_html

Replace `&lt;p&gt;` with `<p>`

{{someString | unescape_html}}
newline_to_br

Replace newline characters with `<br>` tags

{{someString | newline_to_br}}
br_to_newline

Replace `<br>` tags with newline characters

{{someString | br_to_newline}}
reverse

Reverse a string

{{someString | reverse}}
replace_first

Replace first occurance of $1 with $2

{{someString | replace_first 'old' 'new'}}
replace_last

Replace last occurance of $1 with $2

{{someString | replace_last 'old' 'new'}}
replace_all

Replace all occurances of $1 with $2

{{someString | replace_all 'old' 'new'}}
prepend

Prepend a string with another string

{{someString | prepend 'some other string'}}
append

Append a string with another string

{{someString | append 'some other string'}}
truncate

Truncate string to the given number of characters

{{someString | truncate 20}}
truncate_words

Truncate string to the given number of words.

Optionally pass a string as the second parameter, which will be appended if text was indeed truncated.

{{someString | truncate_words 20 '...'}}
time_to_read

Intelligently guesses the time to read the given string in "Mins"

Optionally, override the default units by giving the desired units name as the second parameter.

{{someString | time_to_read "Minutes"}}
urlencode

Encode string to URL friendly format

{{someString | urlencode}}
urldecode

Decode string from URL friendly format

{{someString | urldecode}}
rgb2hex

Convert colour values `255 0 0` into `#ff0000`

{{someString | rgb2hex}}
hex2rgb

Convert colour values `#ff0000` into `255 0 0`

{{someString | hex2rgb}}
md5

Replace string with its md5 checksum

{{someString | md5}}
sha1

Replace string with its sha1 checksum

{{someString | sha1}}
sha256

Replace string with its sha256 checksum

{{someString | sha256}}
sha512

Replace string with its sha512 checksum

{{someString | sha512}}

Data filters

markdown_to_html

Convert the given markdown to HTML

{{someString | markdown_to_html}}
csv_to_markdown

Convert the given csv to a markdown table

{{someString | csv_to_markdown}}
csv_to_html

Convert the given csv to an HTML table

{{someString | csv_to_html}}
csv_to_json

Convert the given csv to JSON

{{someString | csv_to_json}}
csv_to_array

Convert the given csv to a single, flat, indexed array

{{someString | csv_to_array}}
csv_to_arrays

Convert csv data into an array of associative arrays. The CSV headers become the arrays keys. It can be used to iterate over and filter CSV data in your templates (see Array filters below).

{{someString | csv_to_arrays}}

Number filters

at_least

Sets a minimum value for returned numbers

{{someNumber | at_least 10}}
at_most

Sets a maximum value for returned numbers

{{someNumber | at_most 10}}
decimal_places

Limit number to the given number of decimal places

{{someNumber | decimal_places 2}}
divided_by

Divide input by the given number

{{someNumber | divided_by 2}}
minus

Subtract the given number from the input number

{{someNumber | minus 2}}
plus

Add the given number to the input number

{{someNumber | plus 2}}
modulo

Find remainder after division of input and given number

{{someNumber | modulo 3}}
ordinal

Return the given number in ordinal form (112 => 112th)

{{someNumber | ordinal}}
to_int

Convert a float to an int

{{someNumber | to_int}}
floor

Round float down to the nearest integer

{{someNumber | floor}}
ceil

Round float up to the nearest integer

{{someNumber | ceil}}
pluralize

Append a singular (first param) or plural (second param) to a number

{{someNumber | pluralize 'ox' 'oxen'}}
convert

Perform unit conversions. Supported conversions: inches/feet, miles/km, kgs/stones, kgs/lbs, gallons/quarts

{{someNumber | convert miles to km}}

Money filters

money

Converts number to money format, with currency symbol (locale aware).

Optional: give the currency symbol to override the locale default.

{{someNumber | money £}}

If input is `10`, it will output:

£10.00
money_with_currency

Converts number to money format, with currency symbol and name (locale aware)

Optional:

  • Give a currency symbol as the first parameter to override locale defaults.
  • Give a currency name as the second parameter to override locale defaults.
{{someNumber | money_with_currency £ GBP}}

If input is `10`, it will output:

£10.00 GBP
money_without_currency

Converts number to money format, without currency symbol or name.

{{someNumber | money_without_currency}}
without_trailing_zeros

Remove ".0*" from end of numbers (and strings).

{{someNumber | without_trailing_zeros}}

Date filters

These filters can be used with the variables `page_created` and `page_modified`, or any others which hold dates in this format: 2019-07-13T23:56:01Z

date_format

Re-format a date, where `format` is a named format, GNU date format or 'now':

  • `basic` => 09/31/2019
  • `basic_uk` => 31/09/2019
  • `iso8601` => 2019-90-31
  • `to_string` => 09 Nov 2019
  • `to_long_string` => 09 November 2019
  • `rfc822` => Mon, 09 Nov 2019 13:07:54 -0800
  • `"%Y %m %d"` => 2019 09 31
  • `"%d %B %Y"` => 31 November 2009
{{page_created | date_format 'basic_uk'}}
or
{{page_created | date_format "%d %B %Y"}}

Note that `rfc822` has these easier aliases:

  • `rss`
  • `email`

You can also use `now` to get the current date/time when the page is built:

{{now | date_format rss}}

HTML filters

absolute_url

Return the absolute URL to the given file, starting with http://${blog_domain}${blog_url}.

{{someURL | absolute_url}}
relative_url

Return a relative URL to the given string, starting with "${blog_url}" (top dir of blog).

{{someURL | relative_url}}
asset_url

Return a relative path to the given file, appended with a timestamp as a query string, for cache busting purposes. Uses `find` to locate the path to the file (if it exists), else it uses the given string.

{{someURL | asset_url}}
link_tag

Return a `<a href="..">..</a>` tag, linking to the given string.

Works well with these other filters: `asset_url`, `absolute_url`, `relative_url`.

{{someURL | absolute_url | link_tag "My link title"}}
time_tag

Return a `<time>` tag, with `datetime` attribute. $1 is required and formats the printed (visible) date. $2 is optional, and formats the `datetime` attribute.

Supports the same options as the `date_format` filter: `basic`, `basic_uk`, `to_string`, `email`, and GNU date format strings like `%d %M %Y %H:%M`.

{{someDate | time_tag basic iso8601}}

Outputs:

<time datetime="2019-07-13">13 July, 2019</time>
script_tag

Return the given content wrapped inside a <script> tag.

{{someString | script_tag}}
stylesheet_tag

Return the given content wrapped inside a <stylesheet> tag.

{{someString | stylesheet_tag}}
img_tag

Return the given URL wrapped inside an <img> tag.

Optionally set the alt text using the first parameter.

Works well with `asset_url`.

{{someURL | asset_url | img_tag "My alt text."}}

Array filters

concat

Concatenate two arrays (append one to another).

{{#someArray | concat 'otherArrayName'}}
  ...
{{/someArray}}
compact

Remove empty items from array.

{{#someArray | compact}}
  ...
{{/someArray}}
unique

Remove duplicate items from array.

{{#someArray | unique}}
  ...
{{/someArray}}
limit

Limit total items returned to the given number.

{{#someArray | limit 5}}
  ...
{{/someArray}}
exclude

Exclude all items containing the given string.

{{#someArray | exclude 'foo'}}
  ...
{{/someArray}}
exclude_first

Exclude the first item containing the given string.

{{#someArray | exclude_first 'foo'}}
  ...
{{/someArray}}
exclude_last

Exclude the last item containing the given string.

{{#someArray | exclude_last 'foo'}}
  ...
{{/someArray}}
exclude_exact

Exclude all items matching the given string exactly.

{{#someArray | exclude_exact 'foo'}}
  ...
{{/someArray}}
join_by

Convert an array into a string delimeted by the given string.

{{#someArray | join_by ','}}
  {{.}}
{{/someArray}}
sort_array

Sort the array 'asc' or 'desc'.

{{#someArray | sort_array 'asc'}}
  ...
{{/someArray}}
sort_by

Sort an array by the given key, either ascending or descending.

{{#foreach item in someAssocArray | sort_by someKey desc}}
  ...
{{/foreach}}
where

Keep only the array items matching the given string/expression.

Usage of `where`, with associative arrays (hashes):

{{#foreach item in someAssocArray | where someKey '!=' 'foo'}}
  ...
{{/foreach}}

{{#foreach item in someAssocArray | where someKey 'contains' 'foo'}}
  ...
{{/foreach}}

{{#foreach item in someAssocArray | where someKey '!=' 'foo'}}
  ...
{{/foreach}}

{{#foreach item in someAssocArray | where someKey '=' 'foo'}}
  ...
{{/foreach}}

{{#foreach item in someAssocArray | where someKey '>=' 20}}
  ...
{{/foreach}}

{{#foreach item in someAssocArray | where someKey '<' 60}}
  ...
{{/foreach}}

Usage of `where` With simple (indexed) arrays:

{{#someIndexedArray | where contains "Smith" }}
  {{.}}
{{/someIndexedArray}}

{{#someIndexedArray | where ">" 20 }}
  {{.}}
{{/someIndexedArray}}

Conclusion

Using these filters, you can do even more with your templates - transform date formats on the page, sanitize names, exclude specific items, re-order content and more.

But be aware that using lots of filters will slow down your pages build times.