liquid 5.3.0 → 5.5.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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +20 -1
  3. data/README.md +5 -5
  4. data/lib/liquid/block.rb +8 -4
  5. data/lib/liquid/block_body.rb +21 -6
  6. data/lib/liquid/condition.rb +9 -4
  7. data/lib/liquid/context.rb +13 -5
  8. data/lib/liquid/drop.rb +4 -0
  9. data/lib/liquid/errors.rb +16 -15
  10. data/lib/liquid/expression.rb +4 -1
  11. data/lib/liquid/forloop_drop.rb +45 -5
  12. data/lib/liquid/lexer.rb +2 -3
  13. data/lib/liquid/locales/en.yml +7 -5
  14. data/lib/liquid/partial_cache.rb +15 -6
  15. data/lib/liquid/range_lookup.rb +11 -1
  16. data/lib/liquid/{static_registers.rb → registers.rb} +13 -10
  17. data/lib/liquid/standardfilters.rb +480 -68
  18. data/lib/liquid/strainer_factory.rb +4 -0
  19. data/lib/liquid/strainer_template.rb +4 -0
  20. data/lib/liquid/tablerowloop_drop.rb +58 -1
  21. data/lib/liquid/tag/disabler.rb +0 -8
  22. data/lib/liquid/tag.rb +10 -3
  23. data/lib/liquid/tags/assign.rb +12 -8
  24. data/lib/liquid/tags/break.rb +8 -0
  25. data/lib/liquid/tags/capture.rb +13 -10
  26. data/lib/liquid/tags/case.rb +22 -1
  27. data/lib/liquid/tags/comment.rb +72 -0
  28. data/lib/liquid/tags/continue.rb +8 -9
  29. data/lib/liquid/tags/cycle.rb +12 -11
  30. data/lib/liquid/tags/decrement.rb +22 -20
  31. data/lib/liquid/tags/echo.rb +16 -9
  32. data/lib/liquid/tags/for.rb +25 -46
  33. data/lib/liquid/tags/if.rb +12 -10
  34. data/lib/liquid/tags/include.rb +21 -17
  35. data/lib/liquid/tags/increment.rb +22 -17
  36. data/lib/liquid/tags/inline_comment.rb +30 -0
  37. data/lib/liquid/tags/raw.rb +13 -2
  38. data/lib/liquid/tags/render.rb +37 -8
  39. data/lib/liquid/tags/table_row.rb +33 -3
  40. data/lib/liquid/tags/unless.rb +17 -6
  41. data/lib/liquid/template.rb +11 -4
  42. data/lib/liquid/tokenizer.rb +9 -3
  43. data/lib/liquid/variable.rb +4 -4
  44. data/lib/liquid/variable_lookup.rb +10 -7
  45. data/lib/liquid/version.rb +1 -1
  46. data/lib/liquid.rb +3 -3
  47. metadata +7 -123
  48. data/lib/liquid/register.rb +0 -6
  49. data/test/fixtures/en_locale.yml +0 -9
  50. data/test/integration/assign_test.rb +0 -117
  51. data/test/integration/blank_test.rb +0 -109
  52. data/test/integration/block_test.rb +0 -58
  53. data/test/integration/capture_test.rb +0 -58
  54. data/test/integration/context_test.rb +0 -634
  55. data/test/integration/document_test.rb +0 -21
  56. data/test/integration/drop_test.rb +0 -257
  57. data/test/integration/error_handling_test.rb +0 -272
  58. data/test/integration/expression_test.rb +0 -46
  59. data/test/integration/filter_kwarg_test.rb +0 -24
  60. data/test/integration/filter_test.rb +0 -189
  61. data/test/integration/hash_ordering_test.rb +0 -25
  62. data/test/integration/output_test.rb +0 -125
  63. data/test/integration/parsing_quirks_test.rb +0 -134
  64. data/test/integration/profiler_test.rb +0 -240
  65. data/test/integration/security_test.rb +0 -89
  66. data/test/integration/standard_filter_test.rb +0 -925
  67. data/test/integration/tag/disableable_test.rb +0 -59
  68. data/test/integration/tag_test.rb +0 -45
  69. data/test/integration/tags/break_tag_test.rb +0 -17
  70. data/test/integration/tags/continue_tag_test.rb +0 -17
  71. data/test/integration/tags/echo_test.rb +0 -13
  72. data/test/integration/tags/for_tag_test.rb +0 -466
  73. data/test/integration/tags/if_else_tag_test.rb +0 -190
  74. data/test/integration/tags/include_tag_test.rb +0 -269
  75. data/test/integration/tags/increment_tag_test.rb +0 -25
  76. data/test/integration/tags/liquid_tag_test.rb +0 -116
  77. data/test/integration/tags/raw_tag_test.rb +0 -34
  78. data/test/integration/tags/render_tag_test.rb +0 -213
  79. data/test/integration/tags/standard_tag_test.rb +0 -303
  80. data/test/integration/tags/statements_test.rb +0 -113
  81. data/test/integration/tags/table_row_test.rb +0 -66
  82. data/test/integration/tags/unless_else_tag_test.rb +0 -28
  83. data/test/integration/template_test.rb +0 -340
  84. data/test/integration/trim_mode_test.rb +0 -563
  85. data/test/integration/variable_test.rb +0 -138
  86. data/test/test_helper.rb +0 -207
  87. data/test/unit/block_unit_test.rb +0 -53
  88. data/test/unit/condition_unit_test.rb +0 -181
  89. data/test/unit/file_system_unit_test.rb +0 -37
  90. data/test/unit/i18n_unit_test.rb +0 -39
  91. data/test/unit/lexer_unit_test.rb +0 -53
  92. data/test/unit/parse_tree_visitor_test.rb +0 -261
  93. data/test/unit/parser_unit_test.rb +0 -84
  94. data/test/unit/partial_cache_unit_test.rb +0 -128
  95. data/test/unit/regexp_unit_test.rb +0 -46
  96. data/test/unit/static_registers_unit_test.rb +0 -156
  97. data/test/unit/strainer_factory_unit_test.rb +0 -101
  98. data/test/unit/strainer_template_unit_test.rb +0 -82
  99. data/test/unit/tag_unit_test.rb +0 -23
  100. data/test/unit/tags/case_tag_unit_test.rb +0 -12
  101. data/test/unit/tags/for_tag_unit_test.rb +0 -15
  102. data/test/unit/tags/if_tag_unit_test.rb +0 -10
  103. data/test/unit/template_factory_unit_test.rb +0 -12
  104. data/test/unit/template_unit_test.rb +0 -87
  105. data/test/unit/tokenizer_unit_test.rb +0 -62
  106. 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