liquid 2.6.1 → 4.0.3
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.
- checksums.yaml +5 -5
- data/History.md +194 -29
- data/{MIT-LICENSE → LICENSE} +0 -0
- data/README.md +60 -2
- data/lib/liquid.rb +25 -14
- data/lib/liquid/block.rb +47 -96
- data/lib/liquid/block_body.rb +143 -0
- data/lib/liquid/condition.rb +70 -39
- data/lib/liquid/context.rb +116 -157
- data/lib/liquid/document.rb +19 -9
- data/lib/liquid/drop.rb +31 -14
- data/lib/liquid/errors.rb +54 -10
- data/lib/liquid/expression.rb +49 -0
- data/lib/liquid/extensions.rb +19 -7
- data/lib/liquid/file_system.rb +25 -14
- data/lib/liquid/forloop_drop.rb +42 -0
- data/lib/liquid/i18n.rb +39 -0
- data/lib/liquid/interrupts.rb +2 -3
- data/lib/liquid/lexer.rb +55 -0
- data/lib/liquid/locales/en.yml +26 -0
- data/lib/liquid/parse_context.rb +38 -0
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser.rb +90 -0
- data/lib/liquid/parser_switching.rb +31 -0
- data/lib/liquid/profiler.rb +158 -0
- data/lib/liquid/profiler/hooks.rb +23 -0
- data/lib/liquid/range_lookup.rb +37 -0
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +311 -77
- data/lib/liquid/strainer.rb +39 -26
- data/lib/liquid/tablerowloop_drop.rb +62 -0
- data/lib/liquid/tag.rb +28 -11
- data/lib/liquid/tags/assign.rb +34 -10
- data/lib/liquid/tags/break.rb +1 -4
- data/lib/liquid/tags/capture.rb +11 -9
- data/lib/liquid/tags/case.rb +37 -22
- data/lib/liquid/tags/comment.rb +10 -3
- data/lib/liquid/tags/continue.rb +1 -4
- data/lib/liquid/tags/cycle.rb +20 -14
- data/lib/liquid/tags/decrement.rb +4 -8
- data/lib/liquid/tags/for.rb +121 -60
- data/lib/liquid/tags/if.rb +73 -30
- data/lib/liquid/tags/ifchanged.rb +3 -5
- data/lib/liquid/tags/include.rb +77 -46
- data/lib/liquid/tags/increment.rb +4 -8
- data/lib/liquid/tags/raw.rb +35 -10
- data/lib/liquid/tags/table_row.rb +62 -0
- data/lib/liquid/tags/unless.rb +6 -9
- data/lib/liquid/template.rb +130 -32
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/truffle.rb +5 -0
- data/lib/liquid/utils.rb +57 -4
- data/lib/liquid/variable.rb +121 -30
- data/lib/liquid/variable_lookup.rb +88 -0
- data/lib/liquid/version.rb +2 -1
- data/test/fixtures/en_locale.yml +9 -0
- data/test/integration/assign_test.rb +48 -0
- data/test/integration/blank_test.rb +106 -0
- data/test/integration/block_test.rb +12 -0
- data/test/{liquid → integration}/capture_test.rb +13 -3
- data/test/integration/context_test.rb +32 -0
- data/test/integration/document_test.rb +19 -0
- data/test/integration/drop_test.rb +273 -0
- data/test/integration/error_handling_test.rb +260 -0
- data/test/integration/filter_test.rb +178 -0
- data/test/integration/hash_ordering_test.rb +23 -0
- data/test/integration/output_test.rb +123 -0
- data/test/integration/parse_tree_visitor_test.rb +247 -0
- data/test/integration/parsing_quirks_test.rb +122 -0
- data/test/integration/render_profiling_test.rb +154 -0
- data/test/integration/security_test.rb +80 -0
- data/test/integration/standard_filter_test.rb +776 -0
- data/test/{liquid → integration}/tags/break_tag_test.rb +2 -3
- data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -2
- data/test/integration/tags/for_tag_test.rb +410 -0
- data/test/integration/tags/if_else_tag_test.rb +188 -0
- data/test/integration/tags/include_tag_test.rb +253 -0
- data/test/integration/tags/increment_tag_test.rb +23 -0
- data/test/{liquid → integration}/tags/raw_tag_test.rb +9 -2
- data/test/integration/tags/standard_tag_test.rb +296 -0
- data/test/integration/tags/statements_test.rb +111 -0
- data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +25 -24
- data/test/integration/tags/unless_else_tag_test.rb +26 -0
- data/test/integration/template_test.rb +332 -0
- data/test/integration/trim_mode_test.rb +529 -0
- data/test/integration/variable_test.rb +96 -0
- data/test/test_helper.rb +106 -19
- data/test/truffle/truffle_test.rb +9 -0
- data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +9 -9
- data/test/unit/condition_unit_test.rb +166 -0
- data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +85 -74
- data/test/unit/file_system_unit_test.rb +35 -0
- data/test/unit/i18n_unit_test.rb +37 -0
- data/test/unit/lexer_unit_test.rb +51 -0
- data/test/unit/parser_unit_test.rb +82 -0
- data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +4 -4
- data/test/unit/strainer_unit_test.rb +164 -0
- data/test/unit/tag_unit_test.rb +21 -0
- data/test/unit/tags/case_tag_unit_test.rb +10 -0
- data/test/unit/tags/for_tag_unit_test.rb +13 -0
- data/test/unit/tags/if_tag_unit_test.rb +8 -0
- data/test/unit/template_unit_test.rb +78 -0
- data/test/unit/tokenizer_unit_test.rb +55 -0
- data/test/unit/variable_unit_test.rb +162 -0
- metadata +157 -77
- data/lib/extras/liquid_view.rb +0 -51
- data/lib/liquid/htmltags.rb +0 -74
- data/lib/liquid/module_ex.rb +0 -62
- data/test/liquid/assign_test.rb +0 -21
- data/test/liquid/condition_test.rb +0 -127
- data/test/liquid/drop_test.rb +0 -180
- data/test/liquid/error_handling_test.rb +0 -81
- data/test/liquid/file_system_test.rb +0 -29
- data/test/liquid/filter_test.rb +0 -125
- data/test/liquid/hash_ordering_test.rb +0 -25
- data/test/liquid/module_ex_test.rb +0 -87
- data/test/liquid/output_test.rb +0 -116
- data/test/liquid/parsing_quirks_test.rb +0 -52
- data/test/liquid/security_test.rb +0 -64
- data/test/liquid/standard_filter_test.rb +0 -251
- data/test/liquid/strainer_test.rb +0 -52
- data/test/liquid/tags/for_tag_test.rb +0 -297
- data/test/liquid/tags/if_else_tag_test.rb +0 -166
- data/test/liquid/tags/include_tag_test.rb +0 -166
- data/test/liquid/tags/increment_tag_test.rb +0 -24
- data/test/liquid/tags/standard_tag_test.rb +0 -295
- data/test/liquid/tags/statements_test.rb +0 -134
- data/test/liquid/tags/unless_else_tag_test.rb +0 -26
- data/test/liquid/template_test.rb +0 -146
- data/test/liquid/variable_test.rb +0 -186
data/lib/liquid/tags/comment.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
module Liquid
|
2
2
|
class Comment < Block
|
3
|
-
def render(
|
4
|
-
''
|
3
|
+
def render(_context)
|
4
|
+
''.freeze
|
5
|
+
end
|
6
|
+
|
7
|
+
def unknown_tag(_tag, _markup, _tokens)
|
8
|
+
end
|
9
|
+
|
10
|
+
def blank?
|
11
|
+
true
|
5
12
|
end
|
6
13
|
end
|
7
14
|
|
8
|
-
Template.register_tag('comment', Comment)
|
15
|
+
Template.register_tag('comment'.freeze, Comment)
|
9
16
|
end
|
data/lib/liquid/tags/continue.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Liquid
|
2
|
-
|
3
2
|
# Continue tag to be used to break out of a for loop.
|
4
3
|
#
|
5
4
|
# == Basic Usage:
|
@@ -10,12 +9,10 @@ module Liquid
|
|
10
9
|
# {% endfor %}
|
11
10
|
#
|
12
11
|
class Continue < Tag
|
13
|
-
|
14
12
|
def interrupt
|
15
13
|
ContinueInterrupt.new
|
16
14
|
end
|
17
|
-
|
18
15
|
end
|
19
16
|
|
20
|
-
Template.register_tag('continue', Continue)
|
17
|
+
Template.register_tag('continue'.freeze, Continue)
|
21
18
|
end
|
data/lib/liquid/tags/cycle.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Liquid
|
2
|
-
|
3
2
|
# Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
|
4
3
|
#
|
5
4
|
# {% for item in items %}
|
@@ -13,32 +12,34 @@ module Liquid
|
|
13
12
|
# <div class="green"> Item five</div>
|
14
13
|
#
|
15
14
|
class Cycle < Tag
|
16
|
-
SimpleSyntax =
|
17
|
-
NamedSyntax =
|
15
|
+
SimpleSyntax = /\A#{QuotedFragment}+/o
|
16
|
+
NamedSyntax = /\A(#{QuotedFragment})\s*\:\s*(.*)/om
|
17
|
+
|
18
|
+
attr_reader :variables
|
18
19
|
|
19
|
-
def initialize(tag_name, markup,
|
20
|
+
def initialize(tag_name, markup, options)
|
21
|
+
super
|
20
22
|
case markup
|
21
23
|
when NamedSyntax
|
22
24
|
@variables = variables_from_string($2)
|
23
|
-
@name = $1
|
25
|
+
@name = Expression.parse($1)
|
24
26
|
when SimpleSyntax
|
25
27
|
@variables = variables_from_string(markup)
|
26
|
-
@name =
|
28
|
+
@name = @variables.to_s
|
27
29
|
else
|
28
|
-
raise SyntaxError.new(
|
30
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.cycle".freeze))
|
29
31
|
end
|
30
|
-
super
|
31
32
|
end
|
32
33
|
|
33
34
|
def render(context)
|
34
|
-
context.registers[:cycle] ||=
|
35
|
+
context.registers[:cycle] ||= {}
|
35
36
|
|
36
37
|
context.stack do
|
37
|
-
key = context
|
38
|
-
iteration = context.registers[:cycle][key]
|
39
|
-
result = context
|
38
|
+
key = context.evaluate(@name)
|
39
|
+
iteration = context.registers[:cycle][key].to_i
|
40
|
+
result = context.evaluate(@variables[iteration])
|
40
41
|
iteration += 1
|
41
|
-
iteration = 0
|
42
|
+
iteration = 0 if iteration >= @variables.size
|
42
43
|
context.registers[:cycle][key] = iteration
|
43
44
|
result
|
44
45
|
end
|
@@ -49,10 +50,15 @@ module Liquid
|
|
49
50
|
def variables_from_string(markup)
|
50
51
|
markup.split(',').collect do |var|
|
51
52
|
var =~ /\s*(#{QuotedFragment})\s*/o
|
52
|
-
$1 ? $1 : nil
|
53
|
+
$1 ? Expression.parse($1) : nil
|
53
54
|
end.compact
|
54
55
|
end
|
55
56
|
|
57
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
58
|
+
def children
|
59
|
+
Array(@node.variables)
|
60
|
+
end
|
61
|
+
end
|
56
62
|
end
|
57
63
|
|
58
64
|
Template.register_tag('cycle', Cycle)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Liquid
|
2
|
-
|
3
2
|
# decrement is used in a place where one needs to insert a counter
|
4
3
|
# into a template, and needs the counter to survive across
|
5
4
|
# multiple instantiations of the template.
|
@@ -19,21 +18,18 @@ module Liquid
|
|
19
18
|
# Hello: -3
|
20
19
|
#
|
21
20
|
class Decrement < Tag
|
22
|
-
def initialize(tag_name, markup,
|
23
|
-
@variable = markup.strip
|
24
|
-
|
21
|
+
def initialize(tag_name, markup, options)
|
25
22
|
super
|
23
|
+
@variable = markup.strip
|
26
24
|
end
|
27
25
|
|
28
26
|
def render(context)
|
29
27
|
value = context.environments.first[@variable] ||= 0
|
30
|
-
value
|
28
|
+
value -= 1
|
31
29
|
context.environments.first[@variable] = value
|
32
30
|
value.to_s
|
33
31
|
end
|
34
|
-
|
35
|
-
private
|
36
32
|
end
|
37
33
|
|
38
|
-
Template.register_tag('decrement', Decrement)
|
34
|
+
Template.register_tag('decrement'.freeze, Decrement)
|
39
35
|
end
|
data/lib/liquid/tags/for.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Liquid
|
2
|
-
|
3
2
|
# "For" iterates over an array or collection.
|
4
3
|
# Several useful variables are available to you within the loop.
|
5
4
|
#
|
@@ -24,7 +23,7 @@ module Liquid
|
|
24
23
|
# {{ item.name }}
|
25
24
|
# {% end %}
|
26
25
|
#
|
27
|
-
# To reverse the for loop simply use {% for item in collection reversed %}
|
26
|
+
# To reverse the for loop simply use {% for item in collection reversed %} (note that the flag's spelling is different to the filter `reverse`)
|
28
27
|
#
|
29
28
|
# == Available variables:
|
30
29
|
#
|
@@ -42,101 +41,163 @@ module Liquid
|
|
42
41
|
# where 0 is the last item.
|
43
42
|
# forloop.first:: Returns true if the item is the first item.
|
44
43
|
# forloop.last:: Returns true if the item is the last item.
|
44
|
+
# forloop.parentloop:: Provides access to the parent loop, if present.
|
45
45
|
#
|
46
46
|
class For < Block
|
47
|
-
Syntax = /\A(
|
47
|
+
Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
48
48
|
|
49
|
-
|
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
|
49
|
+
attr_reader :collection_name, :variable_name, :limit, :from
|
62
50
|
|
63
|
-
|
51
|
+
def initialize(tag_name, markup, options)
|
64
52
|
super
|
53
|
+
@from = @limit = nil
|
54
|
+
parse_with_selected_parser(markup)
|
55
|
+
@for_block = BlockBody.new
|
56
|
+
@else_block = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse(tokens)
|
60
|
+
return unless parse_body(@for_block, tokens)
|
61
|
+
parse_body(@else_block, tokens)
|
62
|
+
end
|
63
|
+
|
64
|
+
def nodelist
|
65
|
+
@else_block ? [@for_block, @else_block] : [@for_block]
|
65
66
|
end
|
66
67
|
|
67
68
|
def unknown_tag(tag, markup, tokens)
|
68
|
-
return super unless tag == 'else'
|
69
|
-
@
|
69
|
+
return super unless tag == 'else'.freeze
|
70
|
+
@else_block = BlockBody.new
|
70
71
|
end
|
71
72
|
|
72
73
|
def render(context)
|
73
|
-
|
74
|
+
segment = collection_segment(context)
|
74
75
|
|
75
|
-
|
76
|
-
|
76
|
+
if segment.empty?
|
77
|
+
render_else(context)
|
78
|
+
else
|
79
|
+
render_segment(context, segment)
|
80
|
+
end
|
81
|
+
end
|
77
82
|
|
78
|
-
|
79
|
-
return render_else(context) unless iterable?(collection)
|
83
|
+
protected
|
80
84
|
|
81
|
-
|
82
|
-
|
85
|
+
def lax_parse(markup)
|
86
|
+
if markup =~ Syntax
|
87
|
+
@variable_name = $1
|
88
|
+
collection_name = $2
|
89
|
+
@reversed = !!$3
|
90
|
+
@name = "#{@variable_name}-#{collection_name}"
|
91
|
+
@collection_name = Expression.parse(collection_name)
|
92
|
+
markup.scan(TagAttributes) do |key, value|
|
93
|
+
set_attribute(key, value)
|
94
|
+
end
|
83
95
|
else
|
84
|
-
|
96
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
|
85
97
|
end
|
98
|
+
end
|
86
99
|
|
87
|
-
|
88
|
-
|
100
|
+
def strict_parse(markup)
|
101
|
+
p = Parser.new(markup)
|
102
|
+
@variable_name = p.consume(:id)
|
103
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
|
104
|
+
collection_name = p.expression
|
105
|
+
@name = "#{@variable_name}-#{collection_name}"
|
106
|
+
@collection_name = Expression.parse(collection_name)
|
107
|
+
@reversed = p.id?('reversed'.freeze)
|
108
|
+
|
109
|
+
while p.look(:id) && p.look(:colon, 1)
|
110
|
+
unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
|
111
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
|
112
|
+
end
|
113
|
+
p.consume
|
114
|
+
set_attribute(attribute, p.expression)
|
115
|
+
end
|
116
|
+
p.consume(:end_of_string)
|
117
|
+
end
|
89
118
|
|
119
|
+
private
|
120
|
+
|
121
|
+
def collection_segment(context)
|
122
|
+
offsets = context.registers[:for] ||= {}
|
123
|
+
|
124
|
+
from = if @from == :continue
|
125
|
+
offsets[@name].to_i
|
126
|
+
else
|
127
|
+
context.evaluate(@from).to_i
|
128
|
+
end
|
90
129
|
|
91
|
-
|
130
|
+
collection = context.evaluate(@collection_name)
|
131
|
+
collection = collection.to_a if collection.is_a?(Range)
|
92
132
|
|
93
|
-
|
133
|
+
limit = context.evaluate(@limit)
|
134
|
+
to = limit ? limit.to_i + from : nil
|
94
135
|
|
136
|
+
segment = Utils.slice_collection(collection, from, to)
|
95
137
|
segment.reverse! if @reversed
|
96
138
|
|
97
|
-
|
139
|
+
offsets[@name] = from + segment.length
|
140
|
+
|
141
|
+
segment
|
142
|
+
end
|
98
143
|
|
144
|
+
def render_segment(context, segment)
|
145
|
+
for_stack = context.registers[:for_stack] ||= []
|
99
146
|
length = segment.length
|
100
147
|
|
101
|
-
|
102
|
-
context.registers[:for][@name] = from + segment.length
|
148
|
+
result = ''
|
103
149
|
|
104
150
|
context.stack do
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
next if interrupt.is_a? ContinueInterrupt
|
151
|
+
loop_vars = Liquid::ForloopDrop.new(@name, length, for_stack[-1])
|
152
|
+
|
153
|
+
for_stack.push(loop_vars)
|
154
|
+
|
155
|
+
begin
|
156
|
+
context['forloop'.freeze] = loop_vars
|
157
|
+
|
158
|
+
segment.each do |item|
|
159
|
+
context[@variable_name] = item
|
160
|
+
result << @for_block.render(context)
|
161
|
+
loop_vars.send(:increment!)
|
162
|
+
|
163
|
+
# Handle any interrupts if they exist.
|
164
|
+
if context.interrupt?
|
165
|
+
interrupt = context.pop_interrupt
|
166
|
+
break if interrupt.is_a? BreakInterrupt
|
167
|
+
next if interrupt.is_a? ContinueInterrupt
|
168
|
+
end
|
124
169
|
end
|
170
|
+
ensure
|
171
|
+
for_stack.pop
|
125
172
|
end
|
126
173
|
end
|
174
|
+
|
127
175
|
result
|
128
176
|
end
|
129
177
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
178
|
+
def set_attribute(key, expr)
|
179
|
+
case key
|
180
|
+
when 'offset'.freeze
|
181
|
+
@from = if expr == 'continue'.freeze
|
182
|
+
:continue
|
183
|
+
else
|
184
|
+
Expression.parse(expr)
|
185
|
+
end
|
186
|
+
when 'limit'.freeze
|
187
|
+
@limit = Expression.parse(expr)
|
134
188
|
end
|
189
|
+
end
|
135
190
|
|
136
|
-
|
137
|
-
|
191
|
+
def render_else(context)
|
192
|
+
@else_block ? @else_block.render(context) : ''.freeze
|
193
|
+
end
|
194
|
+
|
195
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
196
|
+
def children
|
197
|
+
(super + [@node.limit, @node.from, @node.collection_name]).compact
|
138
198
|
end
|
199
|
+
end
|
139
200
|
end
|
140
201
|
|
141
|
-
Template.register_tag('for', For)
|
202
|
+
Template.register_tag('for'.freeze, For)
|
142
203
|
end
|
data/lib/liquid/tags/if.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Liquid
|
2
|
-
|
3
2
|
# If is the conditional block
|
4
3
|
#
|
5
4
|
# {% if user.admin %}
|
@@ -10,23 +9,30 @@ module Liquid
|
|
10
9
|
#
|
11
10
|
# There are {% if count < 5 %} less {% else %} more {% endif %} items than you need.
|
12
11
|
#
|
13
|
-
#
|
14
12
|
class If < Block
|
15
|
-
SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
|
16
13
|
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
17
14
|
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
18
|
-
BOOLEAN_OPERATORS = %w(and or)
|
15
|
+
BOOLEAN_OPERATORS = %w(and or).freeze
|
19
16
|
|
20
|
-
|
17
|
+
attr_reader :blocks
|
18
|
+
|
19
|
+
def initialize(tag_name, markup, options)
|
20
|
+
super
|
21
21
|
@blocks = []
|
22
|
+
push_block('if'.freeze, markup)
|
23
|
+
end
|
22
24
|
|
23
|
-
|
25
|
+
def nodelist
|
26
|
+
@blocks.map(&:attachment)
|
27
|
+
end
|
24
28
|
|
25
|
-
|
29
|
+
def parse(tokens)
|
30
|
+
while parse_body(@blocks.last.attachment, tokens)
|
31
|
+
end
|
26
32
|
end
|
27
33
|
|
28
34
|
def unknown_tag(tag, markup, tokens)
|
29
|
-
if ['elsif', 'else'].include?(tag)
|
35
|
+
if ['elsif'.freeze, 'else'.freeze].include?(tag)
|
30
36
|
push_block(tag, markup)
|
31
37
|
else
|
32
38
|
super
|
@@ -37,43 +43,80 @@ module Liquid
|
|
37
43
|
context.stack do
|
38
44
|
@blocks.each do |block|
|
39
45
|
if block.evaluate(context)
|
40
|
-
return
|
46
|
+
return block.attachment.render(context)
|
41
47
|
end
|
42
48
|
end
|
43
|
-
''
|
49
|
+
''.freeze
|
44
50
|
end
|
45
51
|
end
|
46
52
|
|
47
53
|
private
|
48
54
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
def push_block(tag, markup)
|
56
|
+
block = if tag == 'else'.freeze
|
57
|
+
ElseCondition.new
|
58
|
+
else
|
59
|
+
parse_with_selected_parser(markup)
|
60
|
+
end
|
53
61
|
|
54
|
-
|
55
|
-
|
62
|
+
@blocks.push(block)
|
63
|
+
block.attach(BlockBody.new)
|
64
|
+
end
|
56
65
|
|
57
|
-
|
66
|
+
def lax_parse(markup)
|
67
|
+
expressions = markup.scan(ExpressionsAndOperators)
|
68
|
+
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
|
58
69
|
|
59
|
-
|
60
|
-
operator = (expressions.shift).to_s.strip
|
70
|
+
condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
61
71
|
|
62
|
-
|
72
|
+
until expressions.empty?
|
73
|
+
operator = expressions.pop.to_s.strip
|
63
74
|
|
64
|
-
|
65
|
-
raise SyntaxError, "invalid boolean operator" unless BOOLEAN_OPERATORS.include?(operator)
|
66
|
-
new_condition.send(operator, condition)
|
67
|
-
condition = new_condition
|
68
|
-
end
|
75
|
+
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
|
69
76
|
|
70
|
-
|
71
|
-
|
77
|
+
new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
78
|
+
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
|
79
|
+
new_condition.send(operator, condition)
|
80
|
+
condition = new_condition
|
81
|
+
end
|
82
|
+
|
83
|
+
condition
|
84
|
+
end
|
72
85
|
|
73
|
-
|
74
|
-
|
86
|
+
def strict_parse(markup)
|
87
|
+
p = Parser.new(markup)
|
88
|
+
condition = parse_binary_comparisons(p)
|
89
|
+
p.consume(:end_of_string)
|
90
|
+
condition
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_binary_comparisons(p)
|
94
|
+
condition = parse_comparison(p)
|
95
|
+
first_condition = condition
|
96
|
+
while op = (p.id?('and'.freeze) || p.id?('or'.freeze))
|
97
|
+
child_condition = parse_comparison(p)
|
98
|
+
condition.send(op, child_condition)
|
99
|
+
condition = child_condition
|
75
100
|
end
|
101
|
+
first_condition
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_comparison(p)
|
105
|
+
a = Expression.parse(p.expression)
|
106
|
+
if op = p.consume?(:comparison)
|
107
|
+
b = Expression.parse(p.expression)
|
108
|
+
Condition.new(a, op, b)
|
109
|
+
else
|
110
|
+
Condition.new(a)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class ParseTreeVisitor < Liquid::ParseTreeVisitor
|
115
|
+
def children
|
116
|
+
@node.blocks
|
117
|
+
end
|
118
|
+
end
|
76
119
|
end
|
77
120
|
|
78
|
-
Template.register_tag('if', If)
|
121
|
+
Template.register_tag('if'.freeze, If)
|
79
122
|
end
|