mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-12 23:40:45 -07:00
Start converting to markdown
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
```
|
||||
@@ -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>
|
||||
@@ -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?"
|
||||
```
|
||||
@@ -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>
|
||||
@@ -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
|
||||
```
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user