Start converting to markdown

Jonathan Rudenberg
2011-10-15 23:27:55 -04:00
parent 3a9fa0cc28
commit 732d6ddc2b
11 changed files with 619 additions and 591 deletions
@@ -4,20 +4,22 @@ To start using liquid just extract it into vendor/plugins or better yet use the
You can now start using templates with the .liquid file type.
h3. Notes
### Notes
A note about helpers. The liquid rails plugin tries to use your helpers as Filters. Your helpers will always receive the piped in text as first parameter and any Filter parameters after this.
Helper:
<pre><code>module ApplicationHelper
```ruby
module ApplicationHelper
def truncate(input, length)
input[0..length] + '...'
end
end
</code></pre>
```
Liquid:
<pre><code> {{ 'This is a long section of text' | truncate: 3 }} #=> Thi...
</code></pre>
```liquid
{{ 'This is a long section of text' | truncate: 3 }} #=> Thi...
```
+59
@@ -0,0 +1,59 @@
Liquid is a template engine which was crafted for very specific requirements
* It has to have simple markup and beautiful results. Template engines which
don't produce good looking results are no fun to use.
* It needs to be non-evaling and secure. Liquid templates are made so that users
can edit them. You don't want to run code on your server which your users
wrote.
* It has to be stateless. The compile and render steps have to be separate, so
that the expensive parsing and compiling can be done once; later on, you can
just render it by passing in a hash with local variables and objects.
* It needs to be able to style emails as well as HTML.
## Stuff to read, watch, etc.
* [Class reference](http://rubydoc.info/gems/liquid)
* [[Liquid for Programmers]]
* [[Liquid for Designers]]
* [[Using Liquid without Rails]]
* [Liquid](http://railscasts.com/episodes/118-liquid (screencast))
## Who uses Liquid?
* [Shopify](http://www.shopify.com)
* [Mephisto](http://mephistoblog.com/)
* [Chameleon](http://chameleon.wikidot.com/)
* [Cashboard](http://www.getcashboard.com)
* [Edicy](http://www.edicy.com)
* [Workory](http://www.workory.com)
* [Zendesk](http://www.zendesk.com)
* [SandwichBoard](http://www.sandwichboard.com/)
* [YikeSite (CMS)](http://www.yikesite.com/)
* [Simplicant (Applicant Tracking System)](http://www.simplicant.com/)
* [3scale (API Management System)](http://www.3scale.net/)
* [Chaptercore](http://www.chaptercore.com)
* [ScreenSteps Live](http://bluemangolearning.com/screenstepslive)
* [PokerAffiliateSolutions](http://www.pokeraffiliatesolutions.com/)
* [Assistly](http://www.assistly.com)
* [Ronin](http://www.roninapp.com)
* [CrowdVine](http://www.crowdvine.com)
* [AboutOne](http://www.aboutone.com)
* [RightScale](http://support.rightscale.com/15-References/Liquid_Markup_with_RightScale_Widgets)
* [Menumill](http://www.menumill.com)
* [Moxie Software](http://www.moxiesoft.com/)
* [Rusic](http://rusic.com/)
* [Development Seed](http://developmentseed.org/blog/2011/09/09/jekyll-github-pages/)
* [peerTransfer](http://peertransfer.com)
* [NationBuilder](http://nationbuilder.com/)
* [Vendder](http://vendder.com/)
* ...Add yours :)
## Why should I use Liquid?
* You want to allow your users to edit the appearance of your application, but
don't want them to run insecure code on your server.
* You want to render templates directly from the database.
* You like Smarty-style template engines.
* You need a template engine which does HTML just as well as emails.
* You don't like the markup language of your current template engine.
-54
@@ -1,54 +0,0 @@
Liquid is a template engine which was crafted for very specific requirements
* It has to have simple markup and beautiful results. Template engines which don't produce good looking results are no fun to use.
* It needs to be non-evaling and secure. Liquid templates are made so that users can edit them. You don't want to run code on your server which your users wrote.
* It has to be stateless. The compile and render steps have to be separate, so that the expensive parsing and compiling can be done once; later on, you can just render it by passing in a hash with local variables and objects.
* It needs to be able to style emails as well as HTML.
h2. Stuff to read, watch, etc.
* "Class reference":http://rubydoc.info/gems/liquid
* [[Liquid for Programmers]]
* [[Liquid for Designers]]
* [[Using Liquid without Rails]]
* "Liquid":http://railscasts.com/episodes/118-liquid (screencast)
h2. Who uses Liquid?
* "Shopify":http://www.shopify.com
* "Mephisto":http://mephistoblog.com/
* "Chameleon":http://chameleon.wikidot.com/
* "Cashboard":http://www.getcashboard.com
* "Edicy":http://www.edicy.com
* "Workory":http://www.workory.com
* "Zendesk":http://www.zendesk.com
* "SandwichBoard":http://www.sandwichboard.com/
* "YikeSite (CMS)":http://www.yikesite.com/
* "Simplicant (Applicant Tracking System)":http://www.simplicant.com/
* "3scale (API Management System)":http://www.3scale.net/
* "Chaptercore":http://www.chaptercore.com
* "ScreenSteps Live":http://bluemangolearning.com/screenstepslive
* "PokerAffiliateSolutions":http://www.pokeraffiliatesolutions.com/
* "Assistly":http://www.assistly.com
* "Ronin":http://www.roninapp.com
* "CrowdVine":http://www.crowdvine.com
* "AboutOne":http://www.aboutone.com
* "RightScale":http://support.rightscale.com/15-References/Liquid_Markup_with_RightScale_Widgets
* "Menumill":http://www.menumill.com
* "Moxie Software":http://www.moxiesoft.com/
* "Rusic":http://rusic.com/
* "Development Seed":http://developmentseed.org/blog/2011/09/09/jekyll-github-pages/
* "peerTransfer":http://peertransfer.com
* "NationBuilder":http://nationbuilder.com/
* "Vendder":http://vendder.com/
* ...Add yours :)
h2. Why should I use Liquid?
* You want to allow your users to edit the appearance of your application, but don't want them to run insecure code on your server.
* You want to render templates directly from the database.
* You like Smarty-style template engines.
* You need a template engine which does HTML just as well as emails.
* You don't like the markup language of your current template engine.
+7
@@ -0,0 +1,7 @@
These links do a good job of explaining how you would use drops.
How do you create a drop for a certain model?
http://chameleon.wikidot.com/doc:themes:drops
http://chameleon.wikidot.com/doc:themes:commentdrop
-7
@@ -1,7 +0,0 @@
These links do a good job of explaining how you would use drops.
How do you create a drop for a certain model?
"http://chameleon.wikidot.com/doc:themes:drops":http://chameleon.wikidot.com/doc:themes:drops
"http://chameleon.wikidot.com/doc:themes:commentdrop":http://chameleon.wikidot.com/doc:themes:commentdrop
+330
@@ -0,0 +1,330 @@
There are two types of markup in Liquid: Output and Tag.
* Output markup (which may resolve to text) is surrounded by
```liquid
{{ matched pairs of curly brackets (ie, braces) }}
```
* Tag markup (which cannot resolve to text) is surrounded by
```liquid
{% matched pairs of curly brackets and percent signs %}
```
## Output
Here is a simple example of Output:
```liquid
Hello {{name}}
Hello {{user.name}}
Hello {{ 'tobi' }}
```
<a name="filters"></a>
### Advanced output: Filters
Output markup takes filters. Filters are simple methods. The first parameter
is always the output of the left side of the filter. The return value of the
filter will be the new left value when the next filter is run. When there are
no more filters, the template will receive the resulting string.
```liquid
Hello {{ 'tobi' | upcase }}
Hello tobi has {{ 'tobi' | size }} letters!
Hello {{ '*tobi*' | textilize | upcase }}
Hello {{ 'now' | date: "%Y %h" }}
```
### Standard Filters
* `date` - reformat a date [syntax reference](http://liquid.rubyforge.org/classes/Liquid/StandardFilters.html#M000012)
* `capitalize` - capitalize words in the input sentence
* `downcase` - convert an input string to lowercase
* `upcase` - convert an input string to uppercase
* `first` - get the first element of the passed in array
* `last` - get the last element of the passed in array
* `join` - join elements of the array with certain character between them
* `sort` - sort elements of the array
* `map` - map/collect an array on a given property
* `size` - return the size of an array or string
* `escape` - escape a string
* `escape_once` - returns an escaped version of html without affecting existing escaped entities
* `strip_html` - strip html from string
* `strip_newlines` - strip all newlines (\n) from string
* `newline_to_br` - replace each newline (\n) with html break
* `replace` - replace each occurrence *e.g.* `{{ 'foofoo' | replace:'foo','bar' }} #=> 'barbar'`
* `replace_first` - replace the first occurrence e.g. `{{ 'barbar' | replace_first:'bar','foo' }} #=> 'foobar'`
* `remove` - remove each occurrence `e.g. `{{ 'foobarfoobar' | remove:'foo' }} #=> 'barbar'`
* `remove_first` - remove the first occurrence *e.g.* `{{ 'barbar' | remove_first:'bar' }} #=> 'bar'`
* `truncate` - truncate a string down to x characters
* `truncatewords` - truncate a string down to x words
* `prepend` - prepend a string *e.g.* `{{ 'bar' | prepend:'foo' }} #=> 'foobar'`
* `append` - append a string *e.g.* `{{ 'foo' | append:'bar' }} #=> 'foobar'`
* `minus` - subtraction *e.g.* `{{ 4 | minus:2 }} #=> 2`
* `plus` - addition *e.g.* `{{ '1' | plus:'1' }} #=> '11'`, `{{ 1 | plus:1 }} #=> 2`
* `times` - multiplication *e.gw* `{{ 5 | times:4 }} #=> 20`
* `divided_by` - division *e.g.* `{{ 10 | divided_by:2 }} #=> 5`
* `split` - split a string on a matching pattern *e.g.* `{{ "a~b" | split:~ }} #=> ['a','b']`
## Tags
Tags are used for the logic in your template. New tags are very easy to code,
so I hope to get many contributions to the standard tag library after releasing
this code.
Here is a list of currently supported tags:
* **assign** - Assgins some value to a variable
* **capture** - Block tag that captures text into a variable
* **case** - Block tag, its the standard case...when block
* **comment** - Block tag, comments out the text in the block
* **cycle** - Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
* **for** - For loop
* **if** - Standard if/else block
* **include** - Includes another template, useful for partials
* **unless** - Mirror of if statement
### Comments
Comment is the simplest tag. It just swallows content.
```liquid
We made 1 million dollars {% comment %} in losses {% endcomment %} this year
```
### If / Else
`if / else` should be well known from any imaginable programming language.
Liquid allows you to write simple expressions in the `if` or `unless` (and
optionally, `elsif` and `else`) clause:
```liquid
{% if user %}
Hello {{ user.name }}
{% endif %}
{% if user.name == 'tobi' %}
Hello tobi
{% elsif user.name == 'bob' %}
Hello bob
{% endif %}
{% if user.name == 'tobi' or user.name == 'bob' %}
Hello tobi or bob
{% endif %}
{% if user.name == 'bob' and user.age > 45 %}
Hello old bob
{% endif %}
{% if user.name != 'tobi' %}
Hello non-tobi
{% endif %}
# Same as above
{% unless user.name == 'tobi' %}
Hello non-tobi
{% endunless %}
# Check if the user has a credit card
{% if user.creditcard != null %}
poor sob
{% endif %}
# Same as above
{% if user.creditcard %}
poor sob
{% endif %}
# Check for an empty array
{% if user.payments == empty %}
you never paid !
{% endif %}
{% if user.age > 18 %}
Login here
{% else %}
Sorry, you are too young
{% endif %}
# array = 1,2,3
{% if array contains 2 %}
array includes 2
{% endif %}
# string = 'hello world'
{% if string contains 'hello' %}
string includes 'hello'
{% endif %}
```
### Case Statement
If you need more conditions, you can use the `case` statement:
```liquid
{% case condition %}
{% when 1 %}
hit 1
{% when 2 or 3 %}
hit 2 or 3
{% else %}
... else ...
{% endcase %}
```
*Example:*
```liquid
{% case template %}
{% when 'label' %}
// {{ label.title }}
{% when 'product' %}
// {{ product.vendor | link_to_vendor }} / {{ product.title }}
{% else %}
// {{page_title}}
{% endcase %}
```
### Cycle
Often you have to alternate between different colors or similar tasks. Liquid
has built-in support for such operations, using the `cycle` tag.
```liquid
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
will result in
one
two
three
one
```
If no name is supplied for the cycle group, then it's assumed that multiple
calls with the same parameters are one group.
If you want to have total control over cycle groups, you can optionally specify
the name of the group. This can even be a variable.
```liquid
{% cycle 'group 1': 'one', 'two', 'three' %}
{% cycle 'group 1': 'one', 'two', 'three' %}
{% cycle 'group 2': 'one', 'two', 'three' %}
{% cycle 'group 2': 'one', 'two', 'three' %}
will result in
one
two
one
two
```
### For loops
Liquid allows `for` loops over collections:
```liquid
{% for item in array %}
{{ item }}
{% endfor %}
```
During every `for` loop, the following helper variables are available for extra
styling needs:
```liquid
forloop.length # => length of the entire for loop
forloop.index # => index of the current iteration
forloop.index0 # => index of the current iteration (zero based)
forloop.rindex # => how many items are still left?
forloop.rindex0 # => how many items are still left? (zero based)
forloop.first # => is this the first iteration?
forloop.last # => is this the last iternation?
```
There are several attributes you can use to influence which items you receive in
your loop
`limit:int` lets you restrict how many items you get.
`offset:int` lets you start the collection with the nth item.
```liquid
# array = [1,2,3,4,5,6]
{% for item in array limit:2 offset:2 %}
{{ item }}
{% endfor %}
# results in 3,4
```
Reversing the loop
```liquid
{% for item in collection reversed %} {{item}} {% endfor %}
```
Instead of looping over an existing collection, you can define a range of
numbers to loop through. The range can be defined by both literal and variable
numbers:
```liquid
# if item.quantity is 4...
{% for i in (1..item.quantity) %}
{{ i }}
{% endfor %}
# results in 1,2,3,4
```
### Variable Assignment
You can store data in your own variables, to be used in output or other tags as
desired. The simplest way to create a variable is with the `assign` tag, which
has a pretty straightforward syntax:
```liquid
{% assign name = 'freestyle' %}
{% for t in collections.tags %}{% if t == name %}
<p>Freestyle!</p>
{% endif %}{% endfor %}
```
Another way of doing this would be to assign `true / false` values to the
variable:
```liquid
{% assign freestyle = false %}
{% for t in collections.tags %}{% if t == 'freestyle' %}
{% assign freestyle = true %}
{% endif %}{% endfor %}
{% if freestyle %}
<p>Freestyle!</p>
{% endif %}
```
If you want to combine a number of strings into a single string and save it to
a variable, you can do that with the `capture` tag. This tag is a block which
"captures" whatever is rendered inside it, then assigns the captured value to
the given variable instead of rendering it to the screen.
```liquid
{% capture attribute_name %}{{ item.title | handleize }}-{{ i }}-color{% endcapture %}
<label for="{{ attribute_name }}">Color:</label>
<select name="attributes[{{ attribute_name }}]" id="{{ attribute_name }}">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
```
-323
@@ -1,323 +0,0 @@
There are two types of markup in Liquid: Output and Tag.
* Output markup (which may resolve to text) is surrounded by
<pre>
{{ matched pairs of curly brackets (ie, braces) }}
</pre>
* Tag markup (which cannot resolve to text) is surrounded by
<pre>
{% matched pairs of curly brackets and percent signs %}
</pre>
h1. Output
Here is a simple example of Output:
<pre>
Hello {{name}}
Hello {{user.name}}
Hello {{ 'tobi' }}
</pre>
<a name="filters"></a>
h2. Advanced output: Filters
Output markup takes filters.
Filters are simple methods.
The first parameter is always the output of the left side of the filter.
The return value of the filter will be the new left value when the next filter is run.
When there are no more filters, the template will receive the resulting string.
<pre>
Hello {{ 'tobi' | upcase }}
Hello tobi has {{ 'tobi' | size }} letters!
Hello {{ '*tobi*' | textilize | upcase }}
Hello {{ 'now' | date: "%Y %h" }}
</pre>
h3. Standard Filters
* **date** - reformat a date ("syntax reference":http://liquid.rubyforge.org/classes/Liquid/StandardFilters.html#M000012)
* **capitalize** - capitalize words in the input sentence
* **downcase** - convert an input string to lowercase
* **upcase** - convert an input string to uppercase
* **first** - get the first element of the passed in array
* **last** - get the last element of the passed in array
* **join** - join elements of the array with certain character between them
* **sort** - sort elements of the array
* **map** - map/collect an array on a given property
* **size** - return the size of an array or string
* **escape** - escape a string
* **escape_once** - returns an escaped version of html without affecting existing escaped entities
* **strip_html** - strip html from string
* **strip_newlines** - strip all newlines (\n) from string
* **newline_to_br** - replace each newline (\n) with html break
* **replace** - replace each occurrence **e.g.** {{ 'foofoo' | replace:'foo','bar' }} #=> 'barbar'
* **replace_first** - replace the first occurrence **e.g.** {{ 'barbar' | replace_first:'bar','foo' }} #=> 'foobar'
* **remove** - remove each occurrence **e.g.** {{ 'foobarfoobar' | remove:'foo' }} #=> 'barbar'
* **remove_first** - remove the first occurrence **e.g.** {{ 'barbar' | remove_first:'bar' }} #=> 'bar'
* **truncate** - truncate a string down to x characters
* **truncatewords** - truncate a string down to x words
* **prepend** - prepend a string **e.g.** {{ 'bar' | prepend:'foo' }} #=> 'foobar'
* **append** - append a string **e.g.** {{ 'foo' | append:'bar' }} #=> 'foobar'
* **minus** - subtraction **e.g** {{ 4 | minus:2 }} #=> 2
* **plus** - addition **e.g** {{ '1' | plus:'1' }} #=> '11', {{ 1 | plus:1 }} #=> 2
* **times** - multiplication **e.g** {{ 5 | times:4 }} #=> 20
* **divided_by** - division **e.g** {{ 10 | divided_by:2 }} #=> 5
* **split** - split a string on a matching pattern **e.g.** {{ "a~b" | split:~ }} #=> ['a','b']
h1. Tags
Tags are used for the logic in your template.
New tags are very easy to code, so I hope to get many contributions to the standard tag library after releasing this code.
Here is a list of currently supported tags:
* **assign** - Assgins some value to a variable
* **capture** - Block tag that captures text into a variable
* **case** - Block tag, its the standard case...when block
* **comment** - Block tag, comments out the text in the block
* **cycle** - Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
* **for** - For loop
* **if** - Standard if/else block
* **include** - Includes another template, useful for partials
* **unless** - Mirror of if statement
h2. Comments
Comment is the simplest tag.
It just swallows content.
<pre>
We made 1 million dollars {% comment %} in losses {% endcomment %} this year
</pre>
h2. If / Else
@if / else@ should be well known from any imaginable programming language.
Liquid allows you to write simple expressions in the @if@ or @unless@ (and optionally, @elsif@ and @else@) clause:
<pre>
{% if user %}
Hello {{ user.name }}
{% endif %}
{% if user.name == 'tobi' %}
Hello tobi
{% elsif user.name == 'bob' %}
Hello bob
{% endif %}
{% if user.name == 'tobi' or user.name == 'bob' %}
Hello tobi or bob
{% endif %}
{% if user.name == 'bob' and user.age > 45 %}
Hello old bob
{% endif %}
{% if user.name != 'tobi' %}
Hello non-tobi
{% endif %}
# Same as above
{% unless user.name == 'tobi' %}
Hello non-tobi
{% endunless %}
# Check if the user has a credit card
{% if user.creditcard != null %}
poor sob
{% endif %}
# Same as above
{% if user.creditcard %}
poor sob
{% endif %}
# Check for an empty array
{% if user.payments == empty %}
you never paid !
{% endif %}
{% if user.age > 18 %}
Login here
{% else %}
Sorry, you are too young
{% endif %}
# array = 1,2,3
{% if array contains 2 %}
array includes 2
{% endif %}
# string = 'hello world'
{% if string contains 'hello' %}
string includes 'hello'
{% endif %}
</pre>
h2. Case Statement
If you need more conditions, you can use the @case@ statement:
<pre>
{% case condition %}
{% when 1 %}
hit 1
{% when 2 or 3 %}
hit 2 or 3
{% else %}
... else ...
{% endcase %}
</pre>
*Example:*
<pre>
{% case template %}
{% when 'label' %}
// {{ label.title }}
{% when 'product' %}
// {{ product.vendor | link_to_vendor }} / {{ product.title }}
{% else %}
// {{page_title}}
{% endcase %}
</pre>
h2. Cycle
Often you have to alternate between different colors or similar tasks.
Liquid has built-in support for such operations, using the @cycle@ tag.
<pre>
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
{% cycle 'one', 'two', 'three' %}
will result in
one
two
three
one
</pre>
If no name is supplied for the cycle group,
then it's assumed that multiple calls with the same parameters are one group.
If you want to have total control over cycle groups, you can optionally specify the name of the group.
This can even be a variable.
<pre>
{% cycle 'group 1': 'one', 'two', 'three' %}
{% cycle 'group 1': 'one', 'two', 'three' %}
{% cycle 'group 2': 'one', 'two', 'three' %}
{% cycle 'group 2': 'one', 'two', 'three' %}
will result in
one
two
one
two
</pre>
h2. For loops
Liquid allows @for@ loops over collections:
<pre>
{% for item in array %}
{{ item }}
{% endfor %}
</pre>
During every @for@ loop, the following helper variables are available for extra styling needs:
<pre>
forloop.length # => length of the entire for loop
forloop.index # => index of the current iteration
forloop.index0 # => index of the current iteration (zero based)
forloop.rindex # => how many items are still left?
forloop.rindex0 # => how many items are still left? (zero based)
forloop.first # => is this the first iteration?
forloop.last # => is this the last iternation?
</pre>
There are several attributes you can use to influence which items you receive in your loop
*limit:int* lets you restrict how many items you get.
*offset:int* lets you start the collection with the nth item.
<pre>
# array = [1,2,3,4,5,6]
{% for item in array limit:2 offset:2 %}
{{ item }}
{% endfor %}
# results in 3,4
</pre>
Reversing the loop
<pre>
{% for item in collection reversed %} {{item}} {% endfor %}
</pre>
Instead of looping over an existing collection, you can define a range of numbers to loop through.
The range can be defined by both literal and variable numbers:
<pre>
# if item.quantity is 4...
{% for i in (1..item.quantity) %}
{{ i }}
{% endfor %}
# results in 1,2,3,4
</pre>
h2. Variable Assignment
You can store data in your own variables, to be used in output or other tags as desired.
The simplest way to create a variable is with the @assign@ tag, which has a pretty straightforward syntax:
<pre>
{% assign name = 'freestyle' %}
{% for t in collections.tags %}{% if t == name %}
<p>Freestyle!</p>
{% endif %}{% endfor %}
</pre>
Another way of doing this would be to assign @true / false@ values to the variable:
<pre>
{% assign freestyle = false %}
{% for t in collections.tags %}{% if t == 'freestyle' %}
{% assign freestyle = true %}
{% endif %}{% endfor %}
{% if freestyle %}
<p>Freestyle!</p>
{% endif %}
</pre>
If you want to combine a number of strings into a single string and save it to a variable, you can do that with the @capture@ tag. This tag is a block which "captures" whatever is rendered inside it, then assigns the captured value to the given variable instead of rendering it to the screen.
<pre>
{% capture attribute_name %}{{ item.title | handleize }}-{{ i }}-color{% endcapture %}
<label for="{{ attribute_name }}">Color:</label>
<select name="attributes[{{ attribute_name }}]" id="{{ attribute_name }}">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
</pre>
+118
@@ -0,0 +1,118 @@
## First steps
It's very simple to get started with Liquid. A Liquid template is rendered in
two steps: Parse and Render. For an overview of the Liquid syntax, please read
[[Liquid for Designers]].
```ruby
@template = Liquid::Template.parse("hi {{name}}") # Parses and compiles the template
@template.render( 'name' => 'tobi' ) # Renders the output => "hi tobi"
```
The `parse` step creates a fully compiled template which can be re-used as often
as you like. You can store it in memory or in a cache for faster rendering
later.
All parameters you want Liquid to work with have to be passed as parameters to
the `render` method. Liquid does not know about your Ruby local, instance, and
global variables.
## Extending Liquid
Extending Liquid is very easy. However, keep in mind that Liquid is a young
library and requires some outside help. If you create useful filters and tags,
please consider creating a patch and attaching it to a ticket here on this trac.
### Create your own filters
Creating filters is very easy. Basically, they are just methods which take one
parameter and return a modified string. You can use your own filters by passing
an array of modules to the render call like this: `@template.render(assigns,
[MyTextFilters, MyDateFilters])`.
```ruby
module TextFilter
def textilize(input)
RedCloth.new(input).to_html
end
end
```
```ruby
@template = Liquid::Template.parse(" {{ '*hi*' | textilize }} ")
@template.render({}, :filters => [TextFilter]) # => "<b>hi</b>"
```
Alternatively, you can register your filters globally:
```ruby
module TextFilter
def textilize(input)
RedCloth.new(input).to_html
end
end
Liquid::Template.register_filter(TextFilter)
```
Once the filter is globally registered, you can simply use it:
```ruby
@template = Liquid::Template.parse(" {{ '*hi*' | textilize }} ")
@template.render # => "<b>hi</b>"
```
### Create your own tags
To create a new tag, simply inherit from `Liquid::Tag` and register your block
with `Liquid::Template`.
```ruby
class Random < Liquid::Tag
def initialize(tag_name, max, tokens)
super
@max = max.to_i
end
def render(context)
rand(@max).to_s
end
end
Liquid::Template.register_tag('random', Random)
```
```ruby
@template = Liquid::Template.parse(" {% random 5 %}")
@template.render # => "3"
```
### Create your own tag blocks
All tag blocks are parsed by Liquid. To create a new block, you just have to
inherit from `Liquid::Block` and register your block with `Liquid::Template`.
```ruby
class Random < Liquid::Block
def initialize(tag_name, markup, tokens)
super
@rand = markup.to_i
end
def render(context)
if rand(@rand) == 0
super
else
''
end
end
end
Liquid::Template.register_tag('random', Random)
```
```ruby
text = " {% random 5 %} wanna hear a joke? {% endrandom %} "
@template = Liquid::Template.parse(text)
@template.render # => In 20% of the cases, this will output "wanna hear a joke?"
```
-116
@@ -1,116 +0,0 @@
h2. First steps
It's very simple to get started with Liquid.
A Liquid template is rendered in two steps: Parse and Render.
For an overview of the Liquid syntax, please read [[Liquid for Designers]].
<pre>
@template = Liquid::Template.parse("hi {{name}}") # Parses and compiles the template
@template.render( 'name' => 'tobi' ) # Renders the output => "hi tobi"
</pre>
The @parse@ step creates a fully compiled template which can be re-used as often as you like.
You can store it in memory or in a cache for faster rendering later.
All parameters you want Liquid to work with have to be passed as parameters to the @render@ method.
Liquid does not know about your Ruby local, instance, and global variables.
h2. Extending Liquid
Extending Liquid is very easy.
However, keep in mind that Liquid is a young library and requires some outside help.
If you create useful filters and tags, please consider creating a patch and attaching it to a ticket here on this trac.
h3. Create your own filters
Creating filters is very easy.
Basically, they are just methods which take one parameter and return a modified string.
You can use your own filters by passing an array of modules to the render call like this:
<code>@template.render(assigns, [MyTextFilters, MyDateFilters])</code>.
<pre>
module TextFilter
def textilize(input)
RedCloth.new(input).to_html
end
end
</pre>
<pre>
@template = Liquid::Template.parse(" {{ '*hi*' | textilize }} ")
@template.render({}, :filters => [TextFilter]) # => "<b>hi</b>"
</pre>
Alternatively, you can register your filters globally:
<pre>
module TextFilter
def textilize(input)
RedCloth.new(input).to_html
end
end
Liquid::Template.register_filter(TextFilter)
</pre>
Once the filter is globally registered, you can simply use it:
<pre>
@template = Liquid::Template.parse(" {{ '*hi*' | textilize }} ")
@template.render # => "<b>hi</b>"
</pre>
h3. Create your own tags
To create a new tag, simply inherit from @Liquid::Tag@ and register your block with @Liquid::Template@.
<pre>
class Random < Liquid::Tag
def initialize(tag_name, max, tokens)
super
@max = max.to_i
end
def render(context)
rand(@max).to_s
end
end
Liquid::Template.register_tag('random', Random)
</pre>
<pre>
@template = Liquid::Template.parse(" {% random 5 %}")
@template.render # => "3"
</pre>
h3. Create your own tag blocks
All tag blocks are parsed by Liquid.
To create a new block,
you just have to inherit from @Liquid::Block@ and register your block with @Liquid::Template@.
<pre>
class Random < Liquid::Block
def initialize(tag_name, markup, tokens)
super
@rand = markup.to_i
end
def render(context)
if rand(@rand) == 0
super
else
''
end
end
end
Liquid::Template.register_tag('random', Random)
</pre>
<pre>
text = " {% random 5 %} wanna hear a joke? {% endrandom %} "
@template = Liquid::Template.parse(text)
@template.render # => In 20% of the cases, this will output "wanna hear a joke?"
</pre>
+98
@@ -0,0 +1,98 @@
I've collected some 'drop classes' from Mephisto in the hope of understanding
how to stitch Liquid into a Rails App.
Perhaps someone can comment on what the different drops are doing and their
purpose.
Here are the 'drops'
```ruby
class UserDrop < BaseDrop
liquid_attributes << :login << :email
end
```
### Explanation of above code
Liquid accepts only a limited number of objects types i.e. Strings, Arrays,
Hashes, Numerics, and Booleans. If we want to pass our Active Record object to
liquid templates we have to define that logic explicitly(Liquid doesn't provide
that functionality). Basically there are three methods/ways to define that
logic.
[[Getting Liquid to Work in Rails]]
The above describe method will constructs a Liquid Drop with the methods you
included. After including the above said stuff you will be able to access user's
email and login in the liquid template ie {{ user.email }} and {{ user.login }}.
Only email and login will be available in the liquid template (all other methods
will not be accessible to liquid templates i.e. user.password ).
```ruby
class ArticleDrop < BaseDrop
include Mephisto::Liquid::UrlMethods
timezone_dates :published_at, :updated_at
liquid_attributes << :title << :permalink << :comments_count
def initialize(source, options = {})
super source
@options = options
@liquid.update \
'body' => @source.body_html,
'excerpt' => (@source.excerpt_html.nil? ||
@source.excerpt_html.empty? ? nil : @source.excerpt_html),
'accept_comments' => @source.accept_comments?,
'is_page_home' => (options[:page] == true)
end
def author
@author ||= liquify(@source.user).first
end
def comments
@comments ||= liquify(*@source.comments.reject(&:new_record?))
end
def sections
@sections ||= @source.sections.inject([]) { |all, s|
s.home? ? all : all << s.to_liquid } # your days are numbered, home section!
@sections ||= liquify(*@source.sections) { |s| s.home? ? nil : s.to_liquid }
end
def tags
@tags ||= liquify(*@source.tags)
end
def blog_sections
sections.select { |s| s.source.blog? }
end
def page_sections
sections.select { |s| s.source.paged? }
end
def content
@content ||= body_for_mode(@options[:mode] || :list)
end
def url
@url ||= absolute_url(@site.permalink_for(@source))
end
def comments_feed_url
@comments_feed_url ||= url + '/comments.xml'
end
def changes_feed_url
@changes_feed_url ||= url + '/changes.xml'
end
protected
def body_for_mode(mode)
contents = [before_method(:excerpt), before_method(:body)]
contents.reverse! if mode == :single
contents.detect { |content| !content.blank? }.to_s.strip
end
end
```
-86
@@ -1,86 +0,0 @@
I've collected some 'drop classes' from Mephisto in the hope of understanding how to stitch Liquid into a Rails App.
Perhaps someone can comment on what the different drops are doing and their purpose.
Here are the 'drops'
<pre><code>
class UserDrop < BaseDrop
liquid_attributes << :login << :email
end
</code></pre>
<b>Explanation of above code</b><br/>
Liquid accepts only a limited number of objects types i.e. Strings, Arrays, Hashes, Numerics, and Booleans. If we want to pass our Active Record object to liquid templates we have to define that logic explicitly(Liquid doesn't provide that functionality).
Basically there are three methods/ways to define that logic "http://wiki.github.com/Shopify/liquid/getting-liquid-to-work-in-rails.":https://github.com/Shopify/liquid/wiki/Getting-Liquid-to-Work-in-Rails
The above describe method will constructs a Liquid Drop with the methods you included. After including the above said stuff you will be able to access user's email and login in the liquid template ie {{ user.email }} and {{ user.login }}. Only email and login will be available in the liquid template (all other methods will not be accessible to liquid templates i.e. user.password ).
<pre><code>
class ArticleDrop < BaseDrop
include Mephisto::Liquid::UrlMethods
timezone_dates :published_at, :updated_at
liquid_attributes << :title << :permalink << :comments_count
def initialize(source, options = {})
super source
@options = options
@liquid.update \
'body' => @source.body_html,
'excerpt' => (@source.excerpt_html.nil? ||
@source.excerpt_html.empty? ? nil : @source.excerpt_html),
'accept_comments' => @source.accept_comments?,
'is_page_home' => (options[:page] == true)
end
def author
@author ||= liquify(@source.user).first
end
def comments
@comments ||= liquify(*@source.comments.reject(&:new_record?))
end
def sections
@sections ||= @source.sections.inject([]) { |all, s|
s.home? ? all : all << s.to_liquid } # your days are numbered, home section!
@sections ||= liquify(*@source.sections) { |s| s.home? ? nil : s.to_liquid }
end
def tags
@tags ||= liquify(*@source.tags)
end
def blog_sections
sections.select { |s| s.source.blog? }
end
def page_sections
sections.select { |s| s.source.paged? }
end
def content
@content ||= body_for_mode(@options[:mode] || :list)
end
def url
@url ||= absolute_url(@site.permalink_for(@source))
end
def comments_feed_url
@comments_feed_url ||= url + '/comments.xml'
end
def changes_feed_url
@changes_feed_url ||= url + '/changes.xml'
end
protected
def body_for_mode(mode)
contents = [before_method(:excerpt), before_method(:body)]
contents.reverse! if mode == :single
contents.detect { |content| !content.blank? }.to_s.strip
end
end</code></pre>