-
Notifications
You must be signed in to change notification settings - Fork 300
DotLiquid for Developers
Getting started with DotLiquid is very easy. A DotLiquid template is rendered in two steps: Parse and Render. For an overview of the DotLiquid syntax, please read DotLiquid for Designers.
Template template = Template.Parse("hi {{name}}"); // Parses and compiles the template
template.Render(Hash.FromAnonymousObject(new { name = "tobi" })); // Renders the output => "hi tobi"
The Parse
step creates a fully compiled template which can be re-used.
You can store it in memory or in a cache for faster rendering later.
All parameters you want to use in your DotLiquid templates have to be passed as parameters to the Render
method.
DotLiquid does not know about your C# (or VB.NET) local or instance variables.
Property | Default | Description |
---|---|---|
Liquid.UseRubyDateFormat |
false | Toggles between the DotLiquid default (.NET) and the Liquid default (Ruby) date formats for template rendering. |
Template.DefaultSyntaxCompatibilityLevel |
DotLiquid20 | Applies default syntax compatibility for template rendering. See DotLiquid Syntax Compatibility |
Template.FileSystem |
BlankFileSystem | Enables a file system location to be provided for storage of included templates |
Template.NamingConvention |
RubyNamingConvention | Naming convention used for template parsing (CSharp or Ruby). See DotLiquid Syntax Compatibility#naming-convention |
Template.RegexTimeOut |
10 | TimeOut used for all Regex in DotLiquid |
Main Article: DotLiquid Syntax Compatibility
Due to practical and historical considerations, there are differences between the .NET implementation and the official Ruby implementation. Since many of these differences can be dictated by development, it is important to properly configure your environment with your preferences and communicate those with designers.
Objects that you pass to Template.Render
must satisfy one of the following conditions:
- Type is an integral type (int, string, decimal, etc.), list or array of integral types, or anonymous type
- Class inherits from
Drop
(more info) - Class implements
ILiquidizable
- Class is decorated with
[LiquidType]
attribute.- Note that you must specify the allowed member names. For example:
[LiquidType("AllowedMember1", "AllowedMember2")]
. - All members are allowed if class is decorated with
[LiquidType("*")]
. Partial matches are not supported (e.g. *Name)
- Note that you must specify the allowed member names. For example:
- Type is registered with
Template.RegisterSafeType(Type type, string[] allowedMembers)
- Type is registered with
Template.RegisterSafeType(Type type, Func<object, object> func)
Note: Nested objects do not inherit their parent's rules in any case. Refer to above list to expose the child's properties.
Extending DotLiquid is very easy. If you do create useful filters or tags, please consider creating a pull request to this repository. Refer to our Contributing Guidelines for more information.
Main Article: Additional Filters
There are additional filters available in DotLiquid over and above those specified by the Liquid syntax, take a look at the main article for details.
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) }) });
public static class TextFilter
{
public static string Textilize(string input)
{
return TextileFormatter.FormatString(input);
}
public static string RegexReplace(string input, string pattern, string replacement)
{
return Regex.Replace(input, pattern, replacement);
}
}
Template template = Template.Parse(" {{ '*hi*' | textilize }} ");
template.Render(new RenderParameters(CultureInfo.CurrentCulture)
{
Filters = new System.Type[] { typeof(TextFilter) }
}); // => "<b>*hi*</b>"
template = Template.Parse(" {{ 'red is green' | regex_replace pattern: '(red|green)' replacement: 'blue' }}");
template.Render(new RenderParameters(CultureInfo.CurrentCulture)
{
Filters = new System.Type[] { typeof(TextFilter) }
}); // => "blue is blue"
Alternatively, you can register your filters globally:
public static class TextFilter
{
public static string Textilize(string input)
{
return TextileFormatter.FormatString(input);
}
public static string RegexReplace(string input, string pattern, string replacement)
{
return Regex.Replace(input, pattern, replacement);
}
}
Template.RegisterFilter(typeof(TextFilter));
Once the filter is globally registered, you can simply use it. By default, filter names in liquid markup are snake_case.
Template template = Template.Parse(" {{ '*hi*' | textilize }} ");
template.Render(); // => "<b>*hi*</b>"
template = Template.Parse(" {{ 'red is green' | regex_replace pattern: '(red|green)' replacement: 'blue' }} ");
template.Render(); // => "blue is blue"
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>"
Please note that currently method overloading is not supported with filters. A workaround is to use different names for your methods.
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"
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?"