locomotivecms-liquid 2.6.0 → 4.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +62 -5
- data/README.md +4 -4
- data/lib/liquid.rb +16 -12
- data/lib/liquid/block.rb +37 -118
- data/lib/liquid/block_body.rb +131 -0
- data/lib/liquid/condition.rb +28 -17
- data/lib/liquid/context.rb +94 -146
- data/lib/liquid/document.rb +16 -10
- data/lib/liquid/drop.rb +8 -5
- data/lib/liquid/drops/inherited_block_drop.rb +24 -0
- data/lib/liquid/errors.rb +44 -5
- data/lib/liquid/expression.rb +33 -0
- data/lib/liquid/file_system.rb +17 -6
- data/lib/liquid/i18n.rb +2 -2
- data/lib/liquid/interrupts.rb +1 -1
- data/lib/liquid/lexer.rb +11 -9
- data/lib/liquid/locales/en.yml +2 -4
- data/lib/liquid/parser.rb +2 -1
- data/lib/liquid/parser_switching.rb +31 -0
- data/lib/liquid/profiler.rb +162 -0
- data/lib/liquid/profiler/hooks.rb +23 -0
- data/lib/liquid/range_lookup.rb +22 -0
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +142 -67
- data/lib/liquid/strainer.rb +14 -4
- data/lib/liquid/tag.rb +22 -41
- data/lib/liquid/tags/assign.rb +15 -10
- data/lib/liquid/tags/break.rb +1 -1
- data/lib/liquid/tags/capture.rb +7 -9
- data/lib/liquid/tags/case.rb +28 -19
- data/lib/liquid/tags/comment.rb +2 -2
- data/lib/liquid/tags/continue.rb +1 -4
- data/lib/liquid/tags/cycle.rb +10 -14
- data/lib/liquid/tags/decrement.rb +3 -4
- data/lib/liquid/tags/extends.rb +28 -44
- data/lib/liquid/tags/for.rb +64 -42
- data/lib/liquid/tags/if.rb +30 -19
- data/lib/liquid/tags/ifchanged.rb +4 -4
- data/lib/liquid/tags/include.rb +30 -20
- data/lib/liquid/tags/increment.rb +3 -8
- data/lib/liquid/tags/inherited_block.rb +54 -56
- data/lib/liquid/tags/raw.rb +18 -10
- data/lib/liquid/tags/table_row.rb +72 -0
- data/lib/liquid/tags/unless.rb +5 -7
- data/lib/liquid/template.rb +113 -53
- data/lib/liquid/token.rb +18 -0
- data/lib/liquid/utils.rb +13 -4
- data/lib/liquid/variable.rb +68 -50
- data/lib/liquid/variable_lookup.rb +78 -0
- data/lib/liquid/version.rb +1 -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/capture_test.rb +50 -0
- data/test/integration/context_test.rb +32 -0
- data/test/integration/document_test.rb +19 -0
- data/test/integration/drop_test.rb +271 -0
- data/test/integration/error_handling_test.rb +207 -0
- data/test/integration/filter_test.rb +125 -0
- data/test/integration/hash_ordering_test.rb +23 -0
- data/test/integration/output_test.rb +116 -0
- data/test/integration/parsing_quirks_test.rb +119 -0
- data/test/integration/render_profiling_test.rb +154 -0
- data/test/integration/security_test.rb +64 -0
- data/test/integration/standard_filter_test.rb +379 -0
- data/test/integration/tags/break_tag_test.rb +16 -0
- data/test/integration/tags/continue_tag_test.rb +16 -0
- data/test/integration/tags/extends_tag_test.rb +104 -0
- data/test/integration/tags/for_tag_test.rb +375 -0
- data/test/integration/tags/if_else_tag_test.rb +169 -0
- data/test/integration/tags/include_tag_test.rb +234 -0
- data/test/integration/tags/increment_tag_test.rb +24 -0
- data/test/integration/tags/raw_tag_test.rb +25 -0
- data/test/integration/tags/standard_tag_test.rb +297 -0
- data/test/integration/tags/statements_test.rb +113 -0
- data/test/integration/tags/table_row_test.rb +63 -0
- data/test/integration/tags/unless_else_tag_test.rb +26 -0
- data/test/integration/template_test.rb +216 -0
- data/test/integration/variable_test.rb +82 -0
- data/test/test_helper.rb +83 -0
- data/test/unit/block_unit_test.rb +55 -0
- data/test/unit/condition_unit_test.rb +149 -0
- data/test/unit/context_unit_test.rb +482 -0
- 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/module_ex_unit_test.rb +87 -0
- data/test/unit/parser_unit_test.rb +82 -0
- data/test/unit/regexp_unit_test.rb +44 -0
- data/test/unit/strainer_unit_test.rb +71 -0
- data/test/unit/tag_unit_test.rb +16 -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 +70 -0
- data/test/unit/tokenizer_unit_test.rb +38 -0
- data/test/unit/variable_unit_test.rb +150 -0
- metadata +144 -15
- data/lib/extras/liquid_view.rb +0 -51
- data/lib/liquid/htmltags.rb +0 -74
- data/lib/liquid/tags/default_content.rb +0 -21
- data/lib/locomotivecms-liquid.rb +0 -1
data/lib/liquid/tags/for.rb
CHANGED
@@ -46,37 +46,46 @@ module Liquid
|
|
46
46
|
class For < Block
|
47
47
|
Syntax = /\A(#{VariableSegment}+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
|
48
48
|
|
49
|
-
def initialize(tag_name, markup,
|
50
|
-
parse_with_selected_parser(markup)
|
51
|
-
@nodelist = @for_block = []
|
49
|
+
def initialize(tag_name, markup, options)
|
52
50
|
super
|
51
|
+
parse_with_selected_parser(markup)
|
52
|
+
@for_block = BlockBody.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse(tokens)
|
56
|
+
if more = parse_body(@for_block, tokens)
|
57
|
+
parse_body(@else_block, tokens)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def nodelist
|
62
|
+
@else_block ? [@for_block, @else_block] : [@for_block]
|
53
63
|
end
|
54
64
|
|
55
65
|
def unknown_tag(tag, markup, tokens)
|
56
|
-
return super unless tag == 'else'
|
57
|
-
@
|
66
|
+
return super unless tag == 'else'.freeze
|
67
|
+
@else_block = BlockBody.new
|
58
68
|
end
|
59
69
|
|
60
70
|
def render(context)
|
61
71
|
context.registers[:for] ||= Hash.new(0)
|
62
72
|
|
63
|
-
collection = context
|
73
|
+
collection = context.evaluate(@collection_name)
|
64
74
|
collection = collection.to_a if collection.is_a?(Range)
|
65
75
|
|
66
76
|
# Maintains Ruby 1.8.7 String#each behaviour on 1.9
|
67
77
|
return render_else(context) unless iterable?(collection)
|
68
78
|
|
69
|
-
from = if @
|
79
|
+
from = if @from == :continue
|
70
80
|
context.registers[:for][@name].to_i
|
71
81
|
else
|
72
|
-
context
|
82
|
+
context.evaluate(@from).to_i
|
73
83
|
end
|
74
84
|
|
75
|
-
limit = context
|
85
|
+
limit = context.evaluate(@limit)
|
76
86
|
to = limit ? limit.to_i + from : nil
|
77
87
|
|
78
|
-
|
79
|
-
segment = Utils.slice_collection_using_each(collection, from, to)
|
88
|
+
segment = Utils.slice_collection(collection, from, to)
|
80
89
|
|
81
90
|
return render_else(context) if segment.empty?
|
82
91
|
|
@@ -92,17 +101,18 @@ module Liquid
|
|
92
101
|
context.stack do
|
93
102
|
segment.each_with_index do |item, index|
|
94
103
|
context[@variable_name] = item
|
95
|
-
context['forloop'] = {
|
96
|
-
'name' => @name,
|
97
|
-
'length' => length,
|
98
|
-
'index' => index + 1,
|
99
|
-
'index0' => index,
|
100
|
-
'rindex' => length - index,
|
101
|
-
'rindex0' => length - index - 1,
|
102
|
-
'first' => (index == 0),
|
103
|
-
|
104
|
-
|
105
|
-
|
104
|
+
context['forloop'.freeze] = {
|
105
|
+
'name'.freeze => @name,
|
106
|
+
'length'.freeze => length,
|
107
|
+
'index'.freeze => index + 1,
|
108
|
+
'index0'.freeze => index,
|
109
|
+
'rindex'.freeze => length - index,
|
110
|
+
'rindex0'.freeze => length - index - 1,
|
111
|
+
'first'.freeze => (index == 0),
|
112
|
+
'last'.freeze => (index == length - 1)
|
113
|
+
}
|
114
|
+
|
115
|
+
result << @for_block.render(context)
|
106
116
|
|
107
117
|
# Handle any interrupts if they exist.
|
108
118
|
if context.has_interrupt?
|
@@ -120,48 +130,60 @@ module Liquid
|
|
120
130
|
def lax_parse(markup)
|
121
131
|
if markup =~ Syntax
|
122
132
|
@variable_name = $1
|
123
|
-
|
124
|
-
@name = "#{$1}-#{$2}"
|
133
|
+
collection_name = $2
|
125
134
|
@reversed = $3
|
126
|
-
@
|
135
|
+
@name = "#{@variable_name}-#{collection_name}"
|
136
|
+
@collection_name = Expression.parse(collection_name)
|
127
137
|
markup.scan(TagAttributes) do |key, value|
|
128
|
-
|
138
|
+
set_attribute(key, value)
|
129
139
|
end
|
130
140
|
else
|
131
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.for")
|
141
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.for".freeze))
|
132
142
|
end
|
133
143
|
end
|
134
144
|
|
135
145
|
def strict_parse(markup)
|
136
146
|
p = Parser.new(markup)
|
137
147
|
@variable_name = p.consume(:id)
|
138
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in")
|
139
|
-
|
140
|
-
@name = "#{@variable_name}-#{
|
141
|
-
@
|
148
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_in".freeze)) unless p.id?('in'.freeze)
|
149
|
+
collection_name = p.expression
|
150
|
+
@name = "#{@variable_name}-#{collection_name}"
|
151
|
+
@collection_name = Expression.parse(collection_name)
|
152
|
+
@reversed = p.id?('reversed'.freeze)
|
142
153
|
|
143
|
-
@attributes = {}
|
144
154
|
while p.look(:id) && p.look(:colon, 1)
|
145
|
-
unless attribute = p.id?('limit') || p.id?('offset')
|
146
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute")
|
155
|
+
unless attribute = p.id?('limit'.freeze) || p.id?('offset'.freeze)
|
156
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.for_invalid_attribute".freeze))
|
147
157
|
end
|
148
158
|
p.consume
|
149
|
-
|
150
|
-
@attributes[attribute] = val
|
159
|
+
set_attribute(attribute, p.expression)
|
151
160
|
end
|
152
161
|
p.consume(:end_of_string)
|
153
162
|
end
|
154
163
|
|
155
164
|
private
|
156
165
|
|
157
|
-
|
158
|
-
|
166
|
+
def set_attribute(key, expr)
|
167
|
+
case key
|
168
|
+
when 'offset'.freeze
|
169
|
+
@from = if expr == 'continue'.freeze
|
170
|
+
:continue
|
171
|
+
else
|
172
|
+
Expression.parse(expr)
|
173
|
+
end
|
174
|
+
when 'limit'.freeze
|
175
|
+
@limit = Expression.parse(expr)
|
159
176
|
end
|
177
|
+
end
|
160
178
|
|
161
|
-
|
162
|
-
|
163
|
-
|
179
|
+
def render_else(context)
|
180
|
+
@else_block ? @else_block.render(context) : ''.freeze
|
181
|
+
end
|
182
|
+
|
183
|
+
def iterable?(collection)
|
184
|
+
collection.respond_to?(:each) || Utils.non_blank_string?(collection)
|
185
|
+
end
|
164
186
|
end
|
165
187
|
|
166
|
-
Template.register_tag('for', For)
|
188
|
+
Template.register_tag('for'.freeze, For)
|
167
189
|
end
|
data/lib/liquid/tags/if.rb
CHANGED
@@ -12,15 +12,25 @@ module Liquid
|
|
12
12
|
class If < Block
|
13
13
|
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
|
14
14
|
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
|
15
|
+
BOOLEAN_OPERATORS = %w(and or)
|
15
16
|
|
16
|
-
def initialize(tag_name, markup,
|
17
|
-
@blocks = []
|
18
|
-
push_block('if', markup)
|
17
|
+
def initialize(tag_name, markup, options)
|
19
18
|
super
|
19
|
+
@blocks = []
|
20
|
+
push_block('if'.freeze, markup)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse(tokens)
|
24
|
+
while more = parse_body(@blocks.last.attachment, tokens)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def nodelist
|
29
|
+
@blocks.map(&:attachment)
|
20
30
|
end
|
21
31
|
|
22
32
|
def unknown_tag(tag, markup, tokens)
|
23
|
-
if ['elsif', 'else'].include?(tag)
|
33
|
+
if ['elsif'.freeze, 'else'.freeze].include?(tag)
|
24
34
|
push_block(tag, markup)
|
25
35
|
else
|
26
36
|
super
|
@@ -31,39 +41,40 @@ module Liquid
|
|
31
41
|
context.stack do
|
32
42
|
@blocks.each do |block|
|
33
43
|
if block.evaluate(context)
|
34
|
-
return
|
44
|
+
return block.attachment.render(context)
|
35
45
|
end
|
36
46
|
end
|
37
|
-
''
|
47
|
+
''.freeze
|
38
48
|
end
|
39
49
|
end
|
40
50
|
|
41
51
|
private
|
42
52
|
|
43
53
|
def push_block(tag, markup)
|
44
|
-
block = if tag == 'else'
|
54
|
+
block = if tag == 'else'.freeze
|
45
55
|
ElseCondition.new
|
46
56
|
else
|
47
57
|
parse_with_selected_parser(markup)
|
48
58
|
end
|
49
59
|
|
50
60
|
@blocks.push(block)
|
51
|
-
|
61
|
+
block.attach(BlockBody.new)
|
52
62
|
end
|
53
63
|
|
54
64
|
def lax_parse(markup)
|
55
|
-
expressions = markup.scan(ExpressionsAndOperators)
|
56
|
-
raise(SyntaxError.new(options[:locale].t("errors.syntax.if"))
|
65
|
+
expressions = markup.scan(ExpressionsAndOperators)
|
66
|
+
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop =~ Syntax
|
57
67
|
|
58
|
-
condition = Condition.new($1, $2, $3)
|
68
|
+
condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
59
69
|
|
60
70
|
while not expressions.empty?
|
61
|
-
operator =
|
71
|
+
operator = expressions.pop.to_s.strip
|
62
72
|
|
63
|
-
raise(SyntaxError.new(options[:locale].t("errors.syntax.if"))
|
73
|
+
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless expressions.pop.to_s =~ Syntax
|
64
74
|
|
65
|
-
new_condition = Condition.new($1, $2, $3)
|
66
|
-
|
75
|
+
new_condition = Condition.new(Expression.parse($1), $2, Expression.parse($3))
|
76
|
+
raise(SyntaxError.new(options[:locale].t("errors.syntax.if".freeze))) unless BOOLEAN_OPERATORS.include?(operator)
|
77
|
+
new_condition.send(operator, condition)
|
67
78
|
condition = new_condition
|
68
79
|
end
|
69
80
|
|
@@ -75,7 +86,7 @@ module Liquid
|
|
75
86
|
|
76
87
|
condition = parse_comparison(p)
|
77
88
|
|
78
|
-
while op = (p.id?('and') || p.id?('or'))
|
89
|
+
while op = (p.id?('and'.freeze) || p.id?('or'.freeze))
|
79
90
|
new_cond = parse_comparison(p)
|
80
91
|
new_cond.send(op, condition)
|
81
92
|
condition = new_cond
|
@@ -86,9 +97,9 @@ module Liquid
|
|
86
97
|
end
|
87
98
|
|
88
99
|
def parse_comparison(p)
|
89
|
-
a = p.expression
|
100
|
+
a = Expression.parse(p.expression)
|
90
101
|
if op = p.consume?(:comparison)
|
91
|
-
b = p.expression
|
102
|
+
b = Expression.parse(p.expression)
|
92
103
|
Condition.new(a, op, b)
|
93
104
|
else
|
94
105
|
Condition.new(a)
|
@@ -96,5 +107,5 @@ module Liquid
|
|
96
107
|
end
|
97
108
|
end
|
98
109
|
|
99
|
-
Template.register_tag('if', If)
|
110
|
+
Template.register_tag('if'.freeze, If)
|
100
111
|
end
|
@@ -4,17 +4,17 @@ module Liquid
|
|
4
4
|
def render(context)
|
5
5
|
context.stack do
|
6
6
|
|
7
|
-
output =
|
7
|
+
output = super
|
8
8
|
|
9
9
|
if output != context.registers[:ifchanged]
|
10
10
|
context.registers[:ifchanged] = output
|
11
11
|
output
|
12
12
|
else
|
13
|
-
''
|
13
|
+
''.freeze
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
Template.register_tag('ifchanged', Ifchanged)
|
20
|
-
end
|
19
|
+
Template.register_tag('ifchanged'.freeze, Ifchanged)
|
20
|
+
end
|
data/lib/liquid/tags/include.rb
CHANGED
@@ -17,47 +17,47 @@ module Liquid
|
|
17
17
|
class Include < Tag
|
18
18
|
Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o
|
19
19
|
|
20
|
-
def initialize(tag_name, markup,
|
20
|
+
def initialize(tag_name, markup, options)
|
21
|
+
super
|
22
|
+
|
21
23
|
if markup =~ Syntax
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
+
template_name = $1
|
26
|
+
variable_name = $3
|
27
|
+
|
28
|
+
@variable_name = Expression.parse(variable_name || template_name[1..-2])
|
29
|
+
@context_variable_name = template_name[1..-2].split('/'.freeze).last
|
30
|
+
@template_name = Expression.parse(template_name)
|
25
31
|
@attributes = {}
|
26
32
|
|
27
33
|
markup.scan(TagAttributes) do |key, value|
|
28
|
-
@attributes[key] = value
|
34
|
+
@attributes[key] = Expression.parse(value)
|
29
35
|
end
|
30
36
|
|
31
37
|
else
|
32
|
-
raise SyntaxError.new(options[:locale].t("errors.syntax.include")
|
38
|
+
raise SyntaxError.new(options[:locale].t("errors.syntax.include".freeze))
|
33
39
|
end
|
34
|
-
|
35
|
-
super
|
36
40
|
end
|
37
41
|
|
38
42
|
def parse(tokens)
|
39
43
|
end
|
40
44
|
|
41
|
-
def blank?
|
42
|
-
false
|
43
|
-
end
|
44
|
-
|
45
45
|
def render(context)
|
46
46
|
partial = load_cached_partial(context)
|
47
|
-
variable = context
|
47
|
+
variable = context.evaluate(@variable_name)
|
48
48
|
|
49
49
|
context.stack do
|
50
50
|
@attributes.each do |key, value|
|
51
|
-
context[key] = context
|
51
|
+
context[key] = context.evaluate(value)
|
52
52
|
end
|
53
53
|
|
54
54
|
if variable.is_a?(Array)
|
55
55
|
variable.collect do |var|
|
56
|
-
context[@
|
56
|
+
context[@context_variable_name] = var
|
57
57
|
partial.render(context)
|
58
58
|
end
|
59
59
|
else
|
60
|
-
context[@
|
60
|
+
context[@context_variable_name] = variable
|
61
61
|
partial.render(context)
|
62
62
|
end
|
63
63
|
end
|
@@ -66,13 +66,13 @@ module Liquid
|
|
66
66
|
private
|
67
67
|
def load_cached_partial(context)
|
68
68
|
cached_partials = context.registers[:cached_partials] || {}
|
69
|
-
template_name = context
|
69
|
+
template_name = context.evaluate(@template_name)
|
70
70
|
|
71
71
|
if cached = cached_partials[template_name]
|
72
72
|
return cached
|
73
73
|
end
|
74
74
|
source = read_template_from_file_system(context)
|
75
|
-
partial = Liquid::Template.parse(source)
|
75
|
+
partial = Liquid::Template.parse(source, pass_options)
|
76
76
|
cached_partials[template_name] = partial
|
77
77
|
context.registers[:cached_partials] = cached_partials
|
78
78
|
partial
|
@@ -84,14 +84,24 @@ module Liquid
|
|
84
84
|
# make read_template_file call backwards-compatible.
|
85
85
|
case file_system.method(:read_template_file).arity
|
86
86
|
when 1
|
87
|
-
file_system.read_template_file(context
|
87
|
+
file_system.read_template_file(context.evaluate(@template_name))
|
88
88
|
when 2
|
89
|
-
file_system.read_template_file(context
|
89
|
+
file_system.read_template_file(context.evaluate(@template_name), context)
|
90
90
|
else
|
91
91
|
raise ArgumentError, "file_system.read_template_file expects two parameters: (template_name, context)"
|
92
92
|
end
|
93
93
|
end
|
94
|
+
|
95
|
+
def pass_options
|
96
|
+
dont_pass = @options[:include_options_blacklist]
|
97
|
+
return {locale: @options[:locale]} if dont_pass == true
|
98
|
+
opts = @options.merge(included: true, include_options_blacklist: false)
|
99
|
+
if dont_pass.is_a?(Array)
|
100
|
+
dont_pass.each {|o| opts.delete(o)}
|
101
|
+
end
|
102
|
+
opts
|
103
|
+
end
|
94
104
|
end
|
95
105
|
|
96
|
-
Template.register_tag('include', Include)
|
106
|
+
Template.register_tag('include'.freeze, Include)
|
97
107
|
end
|
@@ -15,9 +15,9 @@ module Liquid
|
|
15
15
|
# Hello: 2
|
16
16
|
#
|
17
17
|
class Increment < Tag
|
18
|
-
def initialize(tag_name, markup,
|
19
|
-
@variable = markup.strip
|
18
|
+
def initialize(tag_name, markup, options)
|
20
19
|
super
|
20
|
+
@variable = markup.strip
|
21
21
|
end
|
22
22
|
|
23
23
|
def render(context)
|
@@ -25,12 +25,7 @@ module Liquid
|
|
25
25
|
context.environments.first[@variable] = value + 1
|
26
26
|
value.to_s
|
27
27
|
end
|
28
|
-
|
29
|
-
|
30
|
-
def blank?
|
31
|
-
false
|
32
|
-
end
|
33
28
|
end
|
34
29
|
|
35
|
-
Template.register_tag('increment', Increment)
|
30
|
+
Template.register_tag('increment'.freeze, Increment)
|
36
31
|
end
|
@@ -7,95 +7,93 @@ module Liquid
|
|
7
7
|
# {% block content }Hello world{% endblock %}
|
8
8
|
#
|
9
9
|
class InheritedBlock < Block
|
10
|
-
Syntax = /(#{QuotedFragment}+)/
|
10
|
+
Syntax = /(#{QuotedFragment}+)/o
|
11
11
|
|
12
|
-
attr_accessor :parent
|
13
12
|
attr_reader :name
|
14
13
|
|
15
|
-
|
14
|
+
# linked chain of inherited blocks included
|
15
|
+
# in different templates if multiple extends
|
16
|
+
attr_accessor :parent, :descendant
|
17
|
+
|
18
|
+
def initialize(tag_name, markup, options)
|
19
|
+
super
|
20
|
+
|
16
21
|
if markup =~ Syntax
|
17
22
|
@name = $1.gsub(/["']/o, '').strip
|
18
23
|
else
|
19
24
|
raise(SyntaxError.new(options[:locale].t("errors.syntax.block")), options[:line])
|
20
25
|
end
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
(options[:block_stack] ||= []).push(self)
|
25
|
-
options[:current_block] = self
|
26
|
-
|
27
|
-
super if tokens
|
27
|
+
prepare_for_inheritance
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def prepare_for_inheritance
|
31
|
+
# give a different name if this is a nested block
|
32
|
+
if block = options[:inherited_blocks][:nested].last
|
33
|
+
@name = "#{block.name}/#{@name}"
|
34
34
|
end
|
35
|
-
end
|
36
35
|
|
37
|
-
|
38
|
-
|
36
|
+
# append this block to the stack in order to
|
37
|
+
# get a name for the other nested inherited blocks
|
38
|
+
options[:inherited_blocks][:nested].push(self)
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
# build the linked chain of inherited blocks
|
41
|
+
# make a link with the descendant and the parent (chained list)
|
42
|
+
if descendant = options[:inherited_blocks][:all][@name]
|
43
|
+
self.descendant = descendant
|
44
|
+
descendant.parent = self
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
parent.render(context)
|
47
|
-
else
|
48
|
-
''
|
46
|
+
# get the value of the blank property from the descendant
|
47
|
+
@blank = descendant.blank? #false
|
49
48
|
end
|
50
|
-
end
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
new_block.parent = block.parent
|
55
|
-
new_block.nodelist = block.nodelist
|
56
|
-
new_block
|
50
|
+
# become the descendant of the inherited block from the parent template
|
51
|
+
options[:inherited_blocks][:all][@name] = self
|
57
52
|
end
|
58
53
|
|
59
|
-
|
54
|
+
def parse(tokens)
|
55
|
+
super
|
60
56
|
|
61
|
-
|
62
|
-
|
63
|
-
@name = options[:current_block].name + '/' + @name
|
64
|
-
end
|
57
|
+
# when the parsing of the block is done, we can then remove it from the stack
|
58
|
+
options[:inherited_blocks][:nested].pop
|
65
59
|
end
|
66
60
|
|
67
|
-
|
68
|
-
options[:blocks] ||= {}
|
61
|
+
alias_method :render_without_inheritance, :render
|
69
62
|
|
70
|
-
|
63
|
+
def render(context)
|
64
|
+
context.stack do
|
65
|
+
# look for the very first descendant
|
66
|
+
block = self_or_first_descendant
|
71
67
|
|
72
|
-
|
73
|
-
|
74
|
-
|
68
|
+
if block != self
|
69
|
+
# the block drop is in charge of rendering "{{ block.super }}"
|
70
|
+
context['block'] = InheritedBlockDrop.new(block)
|
71
|
+
end
|
75
72
|
|
76
|
-
|
77
|
-
block.parent = new_block
|
78
|
-
block.nodelist = @nodelist
|
73
|
+
block.render_without_inheritance(context)
|
79
74
|
end
|
80
75
|
end
|
81
76
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
77
|
+
# when we render an inherited block, we need the version of the
|
78
|
+
# very first descendant.
|
79
|
+
def self_or_first_descendant
|
80
|
+
block = self
|
81
|
+
while block.descendant; block = block.descendant; end
|
82
|
+
block
|
88
83
|
end
|
89
84
|
|
90
|
-
def
|
91
|
-
|
92
|
-
|
85
|
+
def call_super(context)
|
86
|
+
if parent
|
87
|
+
# remove the block from the linked chain
|
88
|
+
parent.descendant = nil
|
93
89
|
|
94
|
-
|
95
|
-
|
90
|
+
parent.render(context)
|
91
|
+
else
|
92
|
+
''
|
93
|
+
end
|
96
94
|
end
|
97
95
|
|
98
96
|
end
|
99
97
|
|
100
98
|
Template.register_tag('block', InheritedBlock)
|
101
|
-
end
|
99
|
+
end
|