wordify_liquid 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.md +75 -0
- data/MIT-LICENSE +20 -0
- data/README.md +44 -0
- data/lib/extras/liquid_view.rb +51 -0
- data/lib/liquid.rb +68 -0
- data/lib/liquid/block.rb +115 -0
- data/lib/liquid/condition.rb +120 -0
- data/lib/liquid/context.rb +259 -0
- data/lib/liquid/document.rb +17 -0
- data/lib/liquid/drop.rb +61 -0
- data/lib/liquid/errors.rb +11 -0
- data/lib/liquid/extensions.rb +62 -0
- data/lib/liquid/file_system.rb +62 -0
- data/lib/liquid/htmltags.rb +74 -0
- data/lib/liquid/interrupts.rb +17 -0
- data/lib/liquid/module_ex.rb +62 -0
- data/lib/liquid/standardfilters.rb +245 -0
- data/lib/liquid/strainer.rb +53 -0
- data/lib/liquid/tag.rb +26 -0
- data/lib/liquid/tags/assign.rb +33 -0
- data/lib/liquid/tags/break.rb +21 -0
- data/lib/liquid/tags/capture.rb +35 -0
- data/lib/liquid/tags/case.rb +79 -0
- data/lib/liquid/tags/comment.rb +9 -0
- data/lib/liquid/tags/continue.rb +21 -0
- data/lib/liquid/tags/cycle.rb +59 -0
- data/lib/liquid/tags/decrement.rb +39 -0
- data/lib/liquid/tags/for.rb +142 -0
- data/lib/liquid/tags/if.rb +79 -0
- data/lib/liquid/tags/ifchanged.rb +20 -0
- data/lib/liquid/tags/include.rb +65 -0
- data/lib/liquid/tags/increment.rb +35 -0
- data/lib/liquid/tags/raw.rb +21 -0
- data/lib/liquid/tags/unless.rb +33 -0
- data/lib/liquid/template.rb +150 -0
- data/lib/liquid/utils.rb +31 -0
- data/lib/liquid/variable.rb +57 -0
- data/lib/wordify_liquid.rb +1 -0
- data/test/liquid/assign_test.rb +21 -0
- data/test/liquid/block_test.rb +58 -0
- data/test/liquid/capture_test.rb +40 -0
- data/test/liquid/condition_test.rb +127 -0
- data/test/liquid/context_test.rb +478 -0
- data/test/liquid/drop_test.rb +169 -0
- data/test/liquid/error_handling_test.rb +81 -0
- data/test/liquid/file_system_test.rb +29 -0
- data/test/liquid/filter_test.rb +125 -0
- data/test/liquid/module_ex_test.rb +87 -0
- data/test/liquid/output_test.rb +116 -0
- data/test/liquid/parsing_quirks_test.rb +52 -0
- data/test/liquid/regexp_test.rb +44 -0
- data/test/liquid/security_test.rb +64 -0
- data/test/liquid/standard_filter_test.rb +195 -0
- data/test/liquid/strainer_test.rb +52 -0
- data/test/liquid/tags/break_tag_test.rb +16 -0
- data/test/liquid/tags/continue_tag_test.rb +16 -0
- data/test/liquid/tags/for_tag_test.rb +284 -0
- data/test/liquid/tags/html_tag_test.rb +63 -0
- data/test/liquid/tags/if_else_tag_test.rb +160 -0
- data/test/liquid/tags/include_tag_test.rb +139 -0
- data/test/liquid/tags/increment_tag_test.rb +24 -0
- data/test/liquid/tags/raw_tag_test.rb +15 -0
- data/test/liquid/tags/standard_tag_test.rb +295 -0
- data/test/liquid/tags/statements_test.rb +134 -0
- data/test/liquid/tags/unless_else_tag_test.rb +26 -0
- data/test/liquid/template_test.rb +74 -0
- data/test/liquid/variable_test.rb +180 -0
- data/test/test_helper.rb +29 -0
- metadata +145 -0
data/lib/liquid/tag.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
class Tag
|
4
|
+
|
5
|
+
attr_accessor :nodelist
|
6
|
+
|
7
|
+
def initialize(tag_name, markup, tokens)
|
8
|
+
@tag_name = tag_name
|
9
|
+
@markup = markup
|
10
|
+
parse(tokens)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(tokens)
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
self.class.name.downcase
|
18
|
+
end
|
19
|
+
|
20
|
+
def render(context)
|
21
|
+
''
|
22
|
+
end
|
23
|
+
|
24
|
+
end # Tag
|
25
|
+
|
26
|
+
end # Tag
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
# Assign sets a variable in your template.
|
4
|
+
#
|
5
|
+
# {% assign foo = 'monkey' %}
|
6
|
+
#
|
7
|
+
# You can then use the variable later in the page.
|
8
|
+
#
|
9
|
+
# {{ foo }}
|
10
|
+
#
|
11
|
+
class Assign < Tag
|
12
|
+
Syntax = /(#{VariableSignature}+)\s*=\s*(.*)\s*/o
|
13
|
+
|
14
|
+
def initialize(tag_name, markup, tokens)
|
15
|
+
if markup =~ Syntax
|
16
|
+
@to = $1
|
17
|
+
@from = Variable.new($2)
|
18
|
+
else
|
19
|
+
raise SyntaxError.new("Syntax Error in 'assign' - Valid syntax: assign [var] = [source]")
|
20
|
+
end
|
21
|
+
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def render(context)
|
26
|
+
context.scopes.last[@to] = @from.render(context)
|
27
|
+
''
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
Template.register_tag('assign', Assign)
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
# Break tag to be used to break out of a for loop.
|
4
|
+
#
|
5
|
+
# == Basic Usage:
|
6
|
+
# {% for item in collection %}
|
7
|
+
# {% if item.condition %}
|
8
|
+
# {% break %}
|
9
|
+
# {% endif %}
|
10
|
+
# {% endfor %}
|
11
|
+
#
|
12
|
+
class Break < Tag
|
13
|
+
|
14
|
+
def interrupt
|
15
|
+
BreakInterrupt.new
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
Template.register_tag('break', Break)
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
# Capture stores the result of a block into a variable without rendering it inplace.
|
4
|
+
#
|
5
|
+
# {% capture heading %}
|
6
|
+
# Monkeys!
|
7
|
+
# {% endcapture %}
|
8
|
+
# ...
|
9
|
+
# <h1>{{ heading }}</h1>
|
10
|
+
#
|
11
|
+
# Capture is useful for saving content for use later in your template, such as
|
12
|
+
# in a sidebar or footer.
|
13
|
+
#
|
14
|
+
class Capture < Block
|
15
|
+
Syntax = /(\w+)/
|
16
|
+
|
17
|
+
def initialize(tag_name, markup, tokens)
|
18
|
+
if markup =~ Syntax
|
19
|
+
@to = $1
|
20
|
+
else
|
21
|
+
raise SyntaxError.new("Syntax Error in 'capture' - Valid syntax: capture [var]")
|
22
|
+
end
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def render(context)
|
28
|
+
output = super
|
29
|
+
context.scopes.last[@to] = output
|
30
|
+
''
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Template.register_tag('capture', Capture)
|
35
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Liquid
|
2
|
+
class Case < Block
|
3
|
+
Syntax = /(#{QuotedFragment})/o
|
4
|
+
WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/o
|
5
|
+
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
@blocks = []
|
8
|
+
|
9
|
+
if markup =~ Syntax
|
10
|
+
@left = $1
|
11
|
+
else
|
12
|
+
raise SyntaxError.new("Syntax Error in tag 'case' - Valid syntax: case [condition]")
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def unknown_tag(tag, markup, tokens)
|
19
|
+
@nodelist = []
|
20
|
+
case tag
|
21
|
+
when 'when'
|
22
|
+
record_when_condition(markup)
|
23
|
+
when 'else'
|
24
|
+
record_else_condition(markup)
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def render(context)
|
31
|
+
context.stack do
|
32
|
+
execute_else_block = true
|
33
|
+
|
34
|
+
output = ''
|
35
|
+
@blocks.each do |block|
|
36
|
+
if block.else?
|
37
|
+
return render_all(block.attachment, context) if execute_else_block
|
38
|
+
elsif block.evaluate(context)
|
39
|
+
execute_else_block = false
|
40
|
+
output << render_all(block.attachment, context)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
output
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def record_when_condition(markup)
|
50
|
+
while markup
|
51
|
+
# Create a new nodelist and assign it to the new block
|
52
|
+
if not markup =~ WhenSyntax
|
53
|
+
raise SyntaxError.new("Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %} ")
|
54
|
+
end
|
55
|
+
|
56
|
+
markup = $2
|
57
|
+
|
58
|
+
block = Condition.new(@left, '==', $1)
|
59
|
+
block.attach(@nodelist)
|
60
|
+
@blocks.push(block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def record_else_condition(markup)
|
65
|
+
|
66
|
+
if not markup.strip.empty?
|
67
|
+
raise SyntaxError.new("Syntax Error in tag 'case' - Valid else condition: {% else %} (no parameters) ")
|
68
|
+
end
|
69
|
+
|
70
|
+
block = ElseCondition.new
|
71
|
+
block.attach(@nodelist)
|
72
|
+
@blocks << block
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
Template.register_tag('case', Case)
|
79
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
# Continue tag to be used to break out of a for loop.
|
4
|
+
#
|
5
|
+
# == Basic Usage:
|
6
|
+
# {% for item in collection %}
|
7
|
+
# {% if item.condition %}
|
8
|
+
# {% continue %}
|
9
|
+
# {% endif %}
|
10
|
+
# {% endfor %}
|
11
|
+
#
|
12
|
+
class Continue < Tag
|
13
|
+
|
14
|
+
def interrupt
|
15
|
+
ContinueInterrupt.new
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
Template.register_tag('continue', Continue)
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
# Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
|
4
|
+
#
|
5
|
+
# {% for item in items %}
|
6
|
+
# <div class="{% cycle 'red', 'green', 'blue' %}"> {{ item }} </div>
|
7
|
+
# {% end %}
|
8
|
+
#
|
9
|
+
# <div class="red"> Item one </div>
|
10
|
+
# <div class="green"> Item two </div>
|
11
|
+
# <div class="blue"> Item three </div>
|
12
|
+
# <div class="red"> Item four </div>
|
13
|
+
# <div class="green"> Item five</div>
|
14
|
+
#
|
15
|
+
class Cycle < Tag
|
16
|
+
SimpleSyntax = /^#{QuotedFragment}+/o
|
17
|
+
NamedSyntax = /^(#{QuotedFragment})\s*\:\s*(.*)/o
|
18
|
+
|
19
|
+
def initialize(tag_name, markup, tokens)
|
20
|
+
case markup
|
21
|
+
when NamedSyntax
|
22
|
+
@variables = variables_from_string($2)
|
23
|
+
@name = $1
|
24
|
+
when SimpleSyntax
|
25
|
+
@variables = variables_from_string(markup)
|
26
|
+
@name = "'#{@variables.to_s}'"
|
27
|
+
else
|
28
|
+
raise SyntaxError.new("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]")
|
29
|
+
end
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def render(context)
|
34
|
+
context.registers[:cycle] ||= Hash.new(0)
|
35
|
+
|
36
|
+
context.stack do
|
37
|
+
key = context[@name]
|
38
|
+
iteration = context.registers[:cycle][key]
|
39
|
+
result = context[@variables[iteration]]
|
40
|
+
iteration += 1
|
41
|
+
iteration = 0 if iteration >= @variables.size
|
42
|
+
context.registers[:cycle][key] = iteration
|
43
|
+
result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def variables_from_string(markup)
|
50
|
+
markup.split(',').collect do |var|
|
51
|
+
var =~ /\s*(#{QuotedFragment})\s*/o
|
52
|
+
$1 ? $1 : nil
|
53
|
+
end.compact
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
Template.register_tag('cycle', Cycle)
|
59
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
# decrement is used in a place where one needs to insert a counter
|
4
|
+
# into a template, and needs the counter to survive across
|
5
|
+
# multiple instantiations of the template.
|
6
|
+
# NOTE: decrement is a pre-decrement, --i,
|
7
|
+
# while increment is post: i++.
|
8
|
+
#
|
9
|
+
# (To achieve the survival, the application must keep the context)
|
10
|
+
#
|
11
|
+
# if the variable does not exist, it is created with value 0.
|
12
|
+
|
13
|
+
# Hello: {% decrement variable %}
|
14
|
+
#
|
15
|
+
# gives you:
|
16
|
+
#
|
17
|
+
# Hello: -1
|
18
|
+
# Hello: -2
|
19
|
+
# Hello: -3
|
20
|
+
#
|
21
|
+
class Decrement < Tag
|
22
|
+
def initialize(tag_name, markup, tokens)
|
23
|
+
@variable = markup.strip
|
24
|
+
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(context)
|
29
|
+
value = context.environments.first[@variable] ||= 0
|
30
|
+
value = value - 1
|
31
|
+
context.environments.first[@variable] = value
|
32
|
+
value.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
end
|
37
|
+
|
38
|
+
Template.register_tag('decrement', Decrement)
|
39
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
# "For" iterates over an array or collection.
|
4
|
+
# Several useful variables are available to you within the loop.
|
5
|
+
#
|
6
|
+
# == Basic usage:
|
7
|
+
# {% for item in collection %}
|
8
|
+
# {{ forloop.index }}: {{ item.name }}
|
9
|
+
# {% endfor %}
|
10
|
+
#
|
11
|
+
# == Advanced usage:
|
12
|
+
# {% for item in collection %}
|
13
|
+
# <div {% if forloop.first %}class="first"{% endif %}>
|
14
|
+
# Item {{ forloop.index }}: {{ item.name }}
|
15
|
+
# </div>
|
16
|
+
# {% else %}
|
17
|
+
# There is nothing in the collection.
|
18
|
+
# {% endfor %}
|
19
|
+
#
|
20
|
+
# You can also define a limit and offset much like SQL. Remember
|
21
|
+
# that offset starts at 0 for the first item.
|
22
|
+
#
|
23
|
+
# {% for item in collection limit:5 offset:10 %}
|
24
|
+
# {{ item.name }}
|
25
|
+
# {% end %}
|
26
|
+
#
|
27
|
+
# To reverse the for loop simply use {% for item in collection reversed %}
|
28
|
+
#
|
29
|
+
# == Available variables:
|
30
|
+
#
|
31
|
+
# forloop.name:: 'item-collection'
|
32
|
+
# forloop.length:: Length of the loop
|
33
|
+
# forloop.index:: The current item's position in the collection;
|
34
|
+
# forloop.index starts at 1.
|
35
|
+
# This is helpful for non-programmers who start believe
|
36
|
+
# the first item in an array is 1, not 0.
|
37
|
+
# forloop.index0:: The current item's position in the collection
|
38
|
+
# where the first item is 0
|
39
|
+
# forloop.rindex:: Number of items remaining in the loop
|
40
|
+
# (length - index) where 1 is the last item.
|
41
|
+
# forloop.rindex0:: Number of items remaining in the loop
|
42
|
+
# where 0 is the last item.
|
43
|
+
# forloop.first:: Returns true if the item is the first item.
|
44
|
+
# forloop.last:: Returns true if the item is the last item.
|
45
|
+
#
|
46
|
+
class For < Block
|
47
|
+
Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
48
|
+
|
49
|
+
def initialize(tag_name, markup, tokens)
|
50
|
+
if markup =~ Syntax
|
51
|
+
@variable_name = $1
|
52
|
+
@collection_name = $2
|
53
|
+
@name = "#{$1}-#{$2}"
|
54
|
+
@reversed = $3
|
55
|
+
@attributes = {}
|
56
|
+
markup.scan(TagAttributes) do |key, value|
|
57
|
+
@attributes[key] = value
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise SyntaxError.new("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]")
|
61
|
+
end
|
62
|
+
|
63
|
+
@nodelist = @for_block = []
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
def unknown_tag(tag, markup, tokens)
|
68
|
+
return super unless tag == 'else'
|
69
|
+
@nodelist = @else_block = []
|
70
|
+
end
|
71
|
+
|
72
|
+
def render(context)
|
73
|
+
context.registers[:for] ||= Hash.new(0)
|
74
|
+
|
75
|
+
collection = context[@collection_name]
|
76
|
+
collection = collection.to_a if collection.is_a?(Range)
|
77
|
+
|
78
|
+
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
79
|
+
return render_else(context) unless iterable?(collection)
|
80
|
+
|
81
|
+
from = if @attributes['offset'] == 'continue'
|
82
|
+
context.registers[:for][@name].to_i
|
83
|
+
else
|
84
|
+
context[@attributes['offset']].to_i
|
85
|
+
end
|
86
|
+
|
87
|
+
limit = context[@attributes['limit']]
|
88
|
+
to = limit ? limit.to_i + from : nil
|
89
|
+
|
90
|
+
|
91
|
+
segment = Utils.slice_collection_using_each(collection, from, to)
|
92
|
+
|
93
|
+
return render_else(context) if segment.empty?
|
94
|
+
|
95
|
+
segment.reverse! if @reversed
|
96
|
+
|
97
|
+
result = ''
|
98
|
+
|
99
|
+
length = segment.length
|
100
|
+
|
101
|
+
# Store our progress through the collection for the continue flag
|
102
|
+
context.registers[:for][@name] = from + segment.length
|
103
|
+
|
104
|
+
context.stack do
|
105
|
+
segment.each_with_index do |item, index|
|
106
|
+
context[@variable_name] = item
|
107
|
+
context['forloop'] = {
|
108
|
+
'name' => @name,
|
109
|
+
'length' => length,
|
110
|
+
'index' => index + 1,
|
111
|
+
'index0' => index,
|
112
|
+
'rindex' => length - index,
|
113
|
+
'rindex0' => length - index - 1,
|
114
|
+
'first' => (index == 0),
|
115
|
+
'last' => (index == length - 1) }
|
116
|
+
|
117
|
+
result << render_all(@for_block, context)
|
118
|
+
|
119
|
+
# Handle any interrupts if they exist.
|
120
|
+
if context.has_interrupt?
|
121
|
+
interrupt = context.pop_interrupt
|
122
|
+
break if interrupt.is_a? BreakInterrupt
|
123
|
+
next if interrupt.is_a? ContinueInterrupt
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
result
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def render_else(context)
|
133
|
+
return @else_block ? [render_all(@else_block, context)] : ''
|
134
|
+
end
|
135
|
+
|
136
|
+
def iterable?(collection)
|
137
|
+
collection.respond_to?(:each) || Utils.non_blank_string?(collection)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
Template.register_tag('for', For)
|
142
|
+
end
|