liquid 5.3.0 → 5.4.0

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