liquid 5.3.0 → 5.4.0
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 +4 -4
- data/History.md +16 -1
- data/README.md +2 -2
- data/lib/liquid/block_body.rb +4 -4
- data/lib/liquid/context.rb +6 -2
- data/lib/liquid/forloop_drop.rb +44 -1
- data/lib/liquid/locales/en.yml +6 -5
- data/lib/liquid/partial_cache.rb +3 -3
- data/lib/liquid/{static_registers.rb → registers.rb} +13 -10
- data/lib/liquid/standardfilters.rb +406 -57
- data/lib/liquid/strainer_factory.rb +4 -0
- data/lib/liquid/strainer_template.rb +4 -0
- data/lib/liquid/tablerowloop_drop.rb +58 -1
- data/lib/liquid/tags/assign.rb +12 -8
- data/lib/liquid/tags/break.rb +8 -0
- data/lib/liquid/tags/capture.rb +13 -10
- data/lib/liquid/tags/case.rb +21 -0
- data/lib/liquid/tags/comment.rb +13 -0
- data/lib/liquid/tags/continue.rb +8 -9
- data/lib/liquid/tags/cycle.rb +12 -11
- data/lib/liquid/tags/decrement.rb +16 -17
- data/lib/liquid/tags/echo.rb +16 -9
- data/lib/liquid/tags/for.rb +22 -43
- data/lib/liquid/tags/if.rb +11 -9
- data/lib/liquid/tags/include.rb +15 -13
- data/lib/liquid/tags/increment.rb +16 -14
- data/lib/liquid/tags/inline_comment.rb +43 -0
- data/lib/liquid/tags/raw.rb +11 -0
- data/lib/liquid/tags/render.rb +29 -4
- data/lib/liquid/tags/table_row.rb +22 -0
- data/lib/liquid/tags/unless.rb +15 -4
- data/lib/liquid/template.rb +2 -3
- data/lib/liquid/variable.rb +4 -4
- data/lib/liquid/variable_lookup.rb +10 -7
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +2 -2
- metadata +7 -123
- data/lib/liquid/register.rb +0 -6
- data/test/fixtures/en_locale.yml +0 -9
- data/test/integration/assign_test.rb +0 -117
- data/test/integration/blank_test.rb +0 -109
- data/test/integration/block_test.rb +0 -58
- data/test/integration/capture_test.rb +0 -58
- data/test/integration/context_test.rb +0 -634
- data/test/integration/document_test.rb +0 -21
- data/test/integration/drop_test.rb +0 -257
- data/test/integration/error_handling_test.rb +0 -272
- data/test/integration/expression_test.rb +0 -46
- data/test/integration/filter_kwarg_test.rb +0 -24
- data/test/integration/filter_test.rb +0 -189
- data/test/integration/hash_ordering_test.rb +0 -25
- data/test/integration/output_test.rb +0 -125
- data/test/integration/parsing_quirks_test.rb +0 -134
- data/test/integration/profiler_test.rb +0 -240
- data/test/integration/security_test.rb +0 -89
- data/test/integration/standard_filter_test.rb +0 -925
- data/test/integration/tag/disableable_test.rb +0 -59
- data/test/integration/tag_test.rb +0 -45
- data/test/integration/tags/break_tag_test.rb +0 -17
- data/test/integration/tags/continue_tag_test.rb +0 -17
- data/test/integration/tags/echo_test.rb +0 -13
- data/test/integration/tags/for_tag_test.rb +0 -466
- data/test/integration/tags/if_else_tag_test.rb +0 -190
- data/test/integration/tags/include_tag_test.rb +0 -269
- data/test/integration/tags/increment_tag_test.rb +0 -25
- data/test/integration/tags/liquid_tag_test.rb +0 -116
- data/test/integration/tags/raw_tag_test.rb +0 -34
- data/test/integration/tags/render_tag_test.rb +0 -213
- data/test/integration/tags/standard_tag_test.rb +0 -303
- data/test/integration/tags/statements_test.rb +0 -113
- data/test/integration/tags/table_row_test.rb +0 -66
- data/test/integration/tags/unless_else_tag_test.rb +0 -28
- data/test/integration/template_test.rb +0 -340
- data/test/integration/trim_mode_test.rb +0 -563
- data/test/integration/variable_test.rb +0 -138
- data/test/test_helper.rb +0 -207
- data/test/unit/block_unit_test.rb +0 -53
- data/test/unit/condition_unit_test.rb +0 -181
- data/test/unit/file_system_unit_test.rb +0 -37
- data/test/unit/i18n_unit_test.rb +0 -39
- data/test/unit/lexer_unit_test.rb +0 -53
- data/test/unit/parse_tree_visitor_test.rb +0 -261
- data/test/unit/parser_unit_test.rb +0 -84
- data/test/unit/partial_cache_unit_test.rb +0 -128
- data/test/unit/regexp_unit_test.rb +0 -46
- data/test/unit/static_registers_unit_test.rb +0 -156
- data/test/unit/strainer_factory_unit_test.rb +0 -101
- data/test/unit/strainer_template_unit_test.rb +0 -82
- data/test/unit/tag_unit_test.rb +0 -23
- data/test/unit/tags/case_tag_unit_test.rb +0 -12
- data/test/unit/tags/for_tag_unit_test.rb +0 -15
- data/test/unit/tags/if_tag_unit_test.rb +0 -10
- data/test/unit/template_factory_unit_test.rb +0 -12
- data/test/unit/template_unit_test.rb +0 -87
- data/test/unit/tokenizer_unit_test.rb +0 -62
- data/test/unit/variable_unit_test.rb +0 -164
@@ -1,240 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
class ProfilerTest < Minitest::Test
|
6
|
-
class TestDrop < Liquid::Drop
|
7
|
-
def initialize(value)
|
8
|
-
super()
|
9
|
-
@value = value
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
artificial_execution_time
|
14
|
-
|
15
|
-
@value
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
# Monotonic clock precision fluctuate based on the operating system
|
21
|
-
# By introducing a small sleep we ensure ourselves to register a non zero unit of time
|
22
|
-
def artificial_execution_time
|
23
|
-
sleep(Process.clock_getres(Process::CLOCK_MONOTONIC))
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
include Liquid
|
28
|
-
|
29
|
-
class ProfilingFileSystem
|
30
|
-
def read_template_file(template_path)
|
31
|
-
"Rendering template {% assign template_name = '#{template_path}'%}\n{{ template_name }}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def setup
|
36
|
-
Liquid::Template.file_system = ProfilingFileSystem.new
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_template_allows_flagging_profiling
|
40
|
-
t = Template.parse("{{ 'a string' | upcase }}")
|
41
|
-
t.render!
|
42
|
-
|
43
|
-
assert_nil(t.profiler)
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_parse_makes_available_simple_profiling
|
47
|
-
t = Template.parse("{{ 'a string' | upcase }}", profile: true)
|
48
|
-
t.render!
|
49
|
-
|
50
|
-
assert_equal(1, t.profiler.length)
|
51
|
-
|
52
|
-
node = t.profiler[0]
|
53
|
-
assert_equal(" 'a string' | upcase ", node.code)
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_render_ignores_raw_strings_when_profiling
|
57
|
-
t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
|
58
|
-
t.render!
|
59
|
-
|
60
|
-
assert_equal(0, t.profiler.length)
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_profiling_includes_line_numbers_of_liquid_nodes
|
64
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
65
|
-
t.render!
|
66
|
-
assert_equal(2, t.profiler.length)
|
67
|
-
|
68
|
-
# {{ 'a string' | upcase }}
|
69
|
-
assert_equal(1, t.profiler[0].line_number)
|
70
|
-
# {{ increment test }}
|
71
|
-
assert_equal(2, t.profiler[1].line_number)
|
72
|
-
end
|
73
|
-
|
74
|
-
def test_profiling_includes_line_numbers_of_included_partials
|
75
|
-
t = Template.parse("{% include 'a_template' %}", profile: true)
|
76
|
-
t.render!
|
77
|
-
|
78
|
-
included_children = t.profiler[0].children
|
79
|
-
|
80
|
-
# {% assign template_name = 'a_template' %}
|
81
|
-
assert_equal(1, included_children[0].line_number)
|
82
|
-
# {{ template_name }}
|
83
|
-
assert_equal(2, included_children[1].line_number)
|
84
|
-
end
|
85
|
-
|
86
|
-
def test_profiling_render_tag
|
87
|
-
t = Template.parse("{% render 'a_template' %}", profile: true)
|
88
|
-
t.render!
|
89
|
-
|
90
|
-
render_children = t.profiler[0].children
|
91
|
-
render_children.each do |timing|
|
92
|
-
assert_equal('a_template', timing.partial)
|
93
|
-
end
|
94
|
-
assert_equal([1, 2], render_children.map(&:line_number))
|
95
|
-
end
|
96
|
-
|
97
|
-
def test_profiling_times_the_rendering_of_tokens
|
98
|
-
t = Template.parse("{% include 'a_template' %}", profile: true)
|
99
|
-
t.render!
|
100
|
-
|
101
|
-
node = t.profiler[0]
|
102
|
-
refute_nil(node.render_time)
|
103
|
-
end
|
104
|
-
|
105
|
-
def test_profiling_times_the_entire_render
|
106
|
-
t = Template.parse("{% include 'a_template' %}", profile: true)
|
107
|
-
t.render!
|
108
|
-
|
109
|
-
assert(t.profiler.total_render_time >= 0, "Total render time was not calculated")
|
110
|
-
end
|
111
|
-
|
112
|
-
class SleepTag < Liquid::Tag
|
113
|
-
def initialize(tag_name, markup, parse_context)
|
114
|
-
super
|
115
|
-
@duration = Float(markup)
|
116
|
-
end
|
117
|
-
|
118
|
-
def render_to_output_buffer(_context, _output)
|
119
|
-
sleep(@duration)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def test_profiling_multiple_renders
|
124
|
-
with_custom_tag('sleep', SleepTag) do
|
125
|
-
context = Liquid::Context.new
|
126
|
-
t = Liquid::Template.parse("{% sleep 0.001 %}", profile: true)
|
127
|
-
context.template_name = 'index'
|
128
|
-
t.render!(context)
|
129
|
-
context.template_name = 'layout'
|
130
|
-
first_render_time = context.profiler.total_time
|
131
|
-
t.render!(context)
|
132
|
-
|
133
|
-
profiler = context.profiler
|
134
|
-
children = profiler.children
|
135
|
-
assert_operator(first_render_time, :>=, 0.001)
|
136
|
-
assert_operator(profiler.total_time, :>=, 0.001 + first_render_time)
|
137
|
-
assert_equal(["index", "layout"], children.map(&:template_name))
|
138
|
-
assert_equal([nil, nil], children.map(&:code))
|
139
|
-
assert_equal(profiler.total_time, children.map(&:total_time).reduce(&:+))
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_profiling_uses_include_to_mark_children
|
144
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
|
145
|
-
t.render!
|
146
|
-
|
147
|
-
include_node = t.profiler[1]
|
148
|
-
assert_equal(2, include_node.children.length)
|
149
|
-
end
|
150
|
-
|
151
|
-
def test_profiling_marks_children_with_the_name_of_included_partial
|
152
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
|
153
|
-
t.render!
|
154
|
-
|
155
|
-
include_node = t.profiler[1]
|
156
|
-
include_node.children.each do |child|
|
157
|
-
assert_equal("a_template", child.partial)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def test_profiling_supports_multiple_templates
|
162
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", profile: true)
|
163
|
-
t.render!
|
164
|
-
|
165
|
-
a_template = t.profiler[1]
|
166
|
-
a_template.children.each do |child|
|
167
|
-
assert_equal("a_template", child.partial)
|
168
|
-
end
|
169
|
-
|
170
|
-
b_template = t.profiler[2]
|
171
|
-
b_template.children.each do |child|
|
172
|
-
assert_equal("b_template", child.partial)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def test_profiling_supports_rendering_the_same_partial_multiple_times
|
177
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", profile: true)
|
178
|
-
t.render!
|
179
|
-
|
180
|
-
a_template1 = t.profiler[1]
|
181
|
-
a_template1.children.each do |child|
|
182
|
-
assert_equal("a_template", child.partial)
|
183
|
-
end
|
184
|
-
|
185
|
-
a_template2 = t.profiler[2]
|
186
|
-
a_template2.children.each do |child|
|
187
|
-
assert_equal("a_template", child.partial)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def test_can_iterate_over_each_profiling_entry
|
192
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
193
|
-
t.render!
|
194
|
-
|
195
|
-
timing_count = 0
|
196
|
-
t.profiler.each do |_timing|
|
197
|
-
timing_count += 1
|
198
|
-
end
|
199
|
-
|
200
|
-
assert_equal(2, timing_count)
|
201
|
-
end
|
202
|
-
|
203
|
-
def test_profiling_marks_children_of_if_blocks
|
204
|
-
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
205
|
-
t.render!
|
206
|
-
|
207
|
-
assert_equal(1, t.profiler.length)
|
208
|
-
assert_equal(2, t.profiler[0].children.length)
|
209
|
-
end
|
210
|
-
|
211
|
-
def test_profiling_marks_children_of_for_blocks
|
212
|
-
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
213
|
-
t.render!("collection" => ["one", "two"])
|
214
|
-
|
215
|
-
assert_equal(1, t.profiler.length)
|
216
|
-
# Will profile each invocation of the for block
|
217
|
-
assert_equal(2, t.profiler[0].children.length)
|
218
|
-
end
|
219
|
-
|
220
|
-
def test_profiling_supports_self_time
|
221
|
-
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
222
|
-
collection = [
|
223
|
-
TestDrop.new("one"),
|
224
|
-
TestDrop.new("two"),
|
225
|
-
]
|
226
|
-
output = t.render!("collection" => collection)
|
227
|
-
assert_equal(" one two ", output)
|
228
|
-
|
229
|
-
leaf = t.profiler[0].children[0]
|
230
|
-
assert_operator(leaf.self_time, :>, 0.0)
|
231
|
-
end
|
232
|
-
|
233
|
-
def test_profiling_supports_total_time
|
234
|
-
t = Template.parse("{% if true %} {{ test }} {% endif %}", profile: true)
|
235
|
-
output = t.render!("test" => TestDrop.new("one"))
|
236
|
-
assert_equal(" one ", output)
|
237
|
-
|
238
|
-
assert_operator(t.profiler[0].total_time, :>, 0.0)
|
239
|
-
end
|
240
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
module SecurityFilter
|
6
|
-
def add_one(input)
|
7
|
-
"#{input} + 1"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class SecurityTest < Minitest::Test
|
12
|
-
include Liquid
|
13
|
-
|
14
|
-
def setup
|
15
|
-
@assigns = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_no_instance_eval
|
19
|
-
text = %( {{ '1+1' | instance_eval }} )
|
20
|
-
expected = %( 1+1 )
|
21
|
-
|
22
|
-
assert_equal(expected, Template.parse(text).render!(@assigns))
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_no_existing_instance_eval
|
26
|
-
text = %( {{ '1+1' | __instance_eval__ }} )
|
27
|
-
expected = %( 1+1 )
|
28
|
-
|
29
|
-
assert_equal(expected, Template.parse(text).render!(@assigns))
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_no_instance_eval_after_mixing_in_new_filter
|
33
|
-
text = %( {{ '1+1' | instance_eval }} )
|
34
|
-
expected = %( 1+1 )
|
35
|
-
|
36
|
-
assert_equal(expected, Template.parse(text).render!(@assigns))
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_no_instance_eval_later_in_chain
|
40
|
-
text = %( {{ '1+1' | add_one | instance_eval }} )
|
41
|
-
expected = %( 1+1 + 1 )
|
42
|
-
|
43
|
-
assert_equal(expected, Template.parse(text).render!(@assigns, filters: SecurityFilter))
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_does_not_permanently_add_filters_to_symbol_table
|
47
|
-
current_symbols = Symbol.all_symbols
|
48
|
-
|
49
|
-
# MRI imprecisely marks objects found on the C stack, which can result
|
50
|
-
# in uninitialized memory being marked. This can even result in the test failing
|
51
|
-
# deterministically for a given compilation of ruby. Using a separate thread will
|
52
|
-
# keep these writes of the symbol pointer on a separate stack that will be garbage
|
53
|
-
# collected after Thread#join.
|
54
|
-
Thread.new do
|
55
|
-
test = %( {{ "some_string" | a_bad_filter }} )
|
56
|
-
Template.parse(test).render!
|
57
|
-
nil
|
58
|
-
end.join
|
59
|
-
|
60
|
-
GC.start
|
61
|
-
|
62
|
-
assert_equal([], (Symbol.all_symbols - current_symbols))
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_does_not_add_drop_methods_to_symbol_table
|
66
|
-
current_symbols = Symbol.all_symbols
|
67
|
-
|
68
|
-
assigns = { 'drop' => Drop.new }
|
69
|
-
assert_equal("", Template.parse("{{ drop.custom_method_1 }}", assigns).render!)
|
70
|
-
assert_equal("", Template.parse("{{ drop.custom_method_2 }}", assigns).render!)
|
71
|
-
assert_equal("", Template.parse("{{ drop.custom_method_3 }}", assigns).render!)
|
72
|
-
|
73
|
-
assert_equal([], (Symbol.all_symbols - current_symbols))
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_max_depth_nested_blocks_does_not_raise_exception
|
77
|
-
depth = Liquid::Block::MAX_DEPTH
|
78
|
-
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
79
|
-
assert_equal("rendered", Template.parse(code).render!)
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_more_than_max_depth_nested_blocks_raises_exception
|
83
|
-
depth = Liquid::Block::MAX_DEPTH + 1
|
84
|
-
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
85
|
-
assert_raises(Liquid::StackLevelError) do
|
86
|
-
Template.parse(code).render!
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end # SecurityTest
|