Extending DotLiquid

Extending DotLiquid is very easy. If you do create useful filters or tags, please consider creating a pull request.

Create your own filters

Creating filters is very easy. Filters are just methods which take one parameter and return a modified string. You can use your own filters by passing an array of filter types to the Render call like this:

template.Render(new RenderParameters(CultureInfo.CurrentCulture)
{
	Filters = new[] { typeof(MyTextFilters), typeof(MyDateFilters) }
});

Example:

public static class TextFilter
{
    public static string Textilize(string input)
    {
        return TextileFormatter.FormatString(input);
    }
}

Template template = Template.Parse(" {{ '*hi*' | textilize }} ");
template.Render(new RenderParameters(CultureInfo.CurrentCulture)
{
	Filters = new[] { typeof(TextFilter) }
});

Alternatively, you can register your filters globally:

public static class TextFilter
{
    public static string Textilize(string input)
    {
        return TextileFormatter.FormatString(input);
    }
}

Template.RegisterFilter(typeof(TextFilter));

Once the filter is globally registered, you can simply use it. Filter names in liquid markup are lower case.

Template template = Template.Parse(" {{ '*hi*' | textilize }} ");
template.Render(); // => "<b>*hi*</b>"

A filter can access the current context if you add a Context object as the first argument to your filter method. DotLiquid will automatically pass the current context to your filter:

public static String MyFilter(Context context, string input)
{
    //...
}

Filters also work from F#:

open DotLiquid

type TextFilter() =
    static member Textilize (input : string) =
        "<b>" + input + "</b>"

Template.RegisterFilter(TextFilter().GetType());
let template = Template.Parse(" {{ '*hi*' | textilize }} ");
printfn "%s" (template.Render()) // => "<b>*hi*</b>"

Create your own tags

To create a new tag, simply inherit from DotLiquid.Tag and register your tag with DotLiquid.Template.

public class Random : DotLiquid.Tag
{
    private int _max;

    public override void Initialize(string tagName, string markup, List<string> tokens)
    {
        base.Initialize(tagName, markup, tokens);
        _max = Convert.ToInt32(markup);
    }

    public override void Render(Context context, TextWriter result)
    {
        result.Write(new Random().Next(_max).ToString());
    }
}

Template.RegisterTag<Random>("random");

Template template = Template.Parse(" {% random 5 %}");
template.Render(); // => "3"

Create your own tag blocks

All tag blocks are parsed by DotLiquid. To create a new block, you just have to inherit from DotLiquid.Block and register your block with DotLiquid.Template.

public class Random : DotLiquid.Block
{
    private int _max;

    public override void Initialize(string tagName, string markup, List<string> tokens)
    {
        base.Initialize(tagName, markup, tokens);
        _max = Convert.ToInt32(markup);
    }

    public override void Render(Context context, StreamWriter result)
    {
        if (new System.Random().Next(_max) == 0)
        base.Render(context, result);
    }
}

Template.RegisterTag<Random>("random");

string text = " {% random 5 %} wanna hear a joke? {% endrandom %} ";
Template template = Template.Parse(text);
template.Render(); // => In 20% of the cases, this will output "wanna hear a joke?"

Adding custom operators

It is possible to add your own custom operators like this:

Condition.Operators["IsMultipleOf"] = (left, right) => (int)left % (int)right == 0;

And use it like this in ruby casing:

{% if 16 is_multiple_of 4 %} TRUE {% endif %}

Or like this in C# casing:

{% if 16 IsMultipleOf 4 %} TRUE {% endif %}