liquid 4.0.3 → 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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +89 -0
  3. data/README.md +10 -4
  4. data/lib/liquid/block.rb +31 -14
  5. data/lib/liquid/block_body.rb +169 -57
  6. data/lib/liquid/condition.rb +48 -21
  7. data/lib/liquid/context.rb +111 -52
  8. data/lib/liquid/document.rb +47 -9
  9. data/lib/liquid/drop.rb +4 -2
  10. data/lib/liquid/errors.rb +20 -18
  11. data/lib/liquid/expression.rb +28 -32
  12. data/lib/liquid/extensions.rb +2 -0
  13. data/lib/liquid/file_system.rb +6 -4
  14. data/lib/liquid/forloop_drop.rb +54 -4
  15. data/lib/liquid/i18n.rb +5 -3
  16. data/lib/liquid/interrupts.rb +3 -1
  17. data/lib/liquid/lexer.rb +30 -23
  18. data/lib/liquid/locales/en.yml +8 -5
  19. data/lib/liquid/parse_context.rb +20 -4
  20. data/lib/liquid/parse_tree_visitor.rb +2 -2
  21. data/lib/liquid/parser.rb +30 -18
  22. data/lib/liquid/parser_switching.rb +17 -3
  23. data/lib/liquid/partial_cache.rb +24 -0
  24. data/lib/liquid/profiler/hooks.rb +26 -14
  25. data/lib/liquid/profiler.rb +67 -86
  26. data/lib/liquid/range_lookup.rb +13 -3
  27. data/lib/liquid/registers.rb +51 -0
  28. data/lib/liquid/resource_limits.rb +47 -8
  29. data/lib/liquid/standardfilters.rb +551 -114
  30. data/lib/liquid/strainer_factory.rb +41 -0
  31. data/lib/liquid/strainer_template.rb +62 -0
  32. data/lib/liquid/tablerowloop_drop.rb +64 -5
  33. data/lib/liquid/tag/disableable.rb +22 -0
  34. data/lib/liquid/tag/disabler.rb +21 -0
  35. data/lib/liquid/tag.rb +28 -6
  36. data/lib/liquid/tags/assign.rb +36 -18
  37. data/lib/liquid/tags/break.rb +16 -3
  38. data/lib/liquid/tags/capture.rb +24 -18
  39. data/lib/liquid/tags/case.rb +61 -27
  40. data/lib/liquid/tags/comment.rb +18 -3
  41. data/lib/liquid/tags/continue.rb +16 -12
  42. data/lib/liquid/tags/cycle.rb +37 -25
  43. data/lib/liquid/tags/decrement.rb +22 -20
  44. data/lib/liquid/tags/echo.rb +41 -0
  45. data/lib/liquid/tags/for.rb +90 -87
  46. data/lib/liquid/tags/if.rb +50 -32
  47. data/lib/liquid/tags/ifchanged.rb +11 -10
  48. data/lib/liquid/tags/include.rb +49 -60
  49. data/lib/liquid/tags/increment.rb +23 -17
  50. data/lib/liquid/tags/inline_comment.rb +43 -0
  51. data/lib/liquid/tags/raw.rb +25 -11
  52. data/lib/liquid/tags/render.rb +109 -0
  53. data/lib/liquid/tags/table_row.rb +45 -19
  54. data/lib/liquid/tags/unless.rb +38 -19
  55. data/lib/liquid/template.rb +52 -72
  56. data/lib/liquid/template_factory.rb +9 -0
  57. data/lib/liquid/tokenizer.rb +18 -10
  58. data/lib/liquid/usage.rb +8 -0
  59. data/lib/liquid/utils.rb +13 -3
  60. data/lib/liquid/variable.rb +49 -44
  61. data/lib/liquid/variable_lookup.rb +18 -10
  62. data/lib/liquid/version.rb +2 -1
  63. data/lib/liquid.rb +18 -6
  64. metadata +20 -108
  65. data/lib/liquid/strainer.rb +0 -66
  66. data/lib/liquid/truffle.rb +0 -5
  67. data/test/fixtures/en_locale.yml +0 -9
  68. data/test/integration/assign_test.rb +0 -48
  69. data/test/integration/blank_test.rb +0 -106
  70. data/test/integration/block_test.rb +0 -12
  71. data/test/integration/capture_test.rb +0 -50
  72. data/test/integration/context_test.rb +0 -32
  73. data/test/integration/document_test.rb +0 -19
  74. data/test/integration/drop_test.rb +0 -273
  75. data/test/integration/error_handling_test.rb +0 -260
  76. data/test/integration/filter_test.rb +0 -178
  77. data/test/integration/hash_ordering_test.rb +0 -23
  78. data/test/integration/output_test.rb +0 -123
  79. data/test/integration/parse_tree_visitor_test.rb +0 -247
  80. data/test/integration/parsing_quirks_test.rb +0 -122
  81. data/test/integration/render_profiling_test.rb +0 -154
  82. data/test/integration/security_test.rb +0 -80
  83. data/test/integration/standard_filter_test.rb +0 -776
  84. data/test/integration/tags/break_tag_test.rb +0 -15
  85. data/test/integration/tags/continue_tag_test.rb +0 -15
  86. data/test/integration/tags/for_tag_test.rb +0 -410
  87. data/test/integration/tags/if_else_tag_test.rb +0 -188
  88. data/test/integration/tags/include_tag_test.rb +0 -253
  89. data/test/integration/tags/increment_tag_test.rb +0 -23
  90. data/test/integration/tags/raw_tag_test.rb +0 -31
  91. data/test/integration/tags/standard_tag_test.rb +0 -296
  92. data/test/integration/tags/statements_test.rb +0 -111
  93. data/test/integration/tags/table_row_test.rb +0 -64
  94. data/test/integration/tags/unless_else_tag_test.rb +0 -26
  95. data/test/integration/template_test.rb +0 -332
  96. data/test/integration/trim_mode_test.rb +0 -529
  97. data/test/integration/variable_test.rb +0 -96
  98. data/test/test_helper.rb +0 -116
  99. data/test/truffle/truffle_test.rb +0 -9
  100. data/test/unit/block_unit_test.rb +0 -58
  101. data/test/unit/condition_unit_test.rb +0 -166
  102. data/test/unit/context_unit_test.rb +0 -489
  103. data/test/unit/file_system_unit_test.rb +0 -35
  104. data/test/unit/i18n_unit_test.rb +0 -37
  105. data/test/unit/lexer_unit_test.rb +0 -51
  106. data/test/unit/parser_unit_test.rb +0 -82
  107. data/test/unit/regexp_unit_test.rb +0 -44
  108. data/test/unit/strainer_unit_test.rb +0 -164
  109. data/test/unit/tag_unit_test.rb +0 -21
  110. data/test/unit/tags/case_tag_unit_test.rb +0 -10
  111. data/test/unit/tags/for_tag_unit_test.rb +0 -13
  112. data/test/unit/tags/if_tag_unit_test.rb +0 -8
  113. data/test/unit/template_unit_test.rb +0 -78
  114. data/test/unit/tokenizer_unit_test.rb +0 -55
  115. data/test/unit/variable_unit_test.rb +0 -162
@@ -1,154 +0,0 @@
1
- require 'test_helper'
2
-
3
- class RenderProfilingTest < Minitest::Test
4
- include Liquid
5
-
6
- class ProfilingFileSystem
7
- def read_template_file(template_path)
8
- "Rendering template {% assign template_name = '#{template_path}'%}\n{{ template_name }}"
9
- end
10
- end
11
-
12
- def setup
13
- Liquid::Template.file_system = ProfilingFileSystem.new
14
- end
15
-
16
- def test_template_allows_flagging_profiling
17
- t = Template.parse("{{ 'a string' | upcase }}")
18
- t.render!
19
-
20
- assert_nil t.profiler
21
- end
22
-
23
- def test_parse_makes_available_simple_profiling
24
- t = Template.parse("{{ 'a string' | upcase }}", profile: true)
25
- t.render!
26
-
27
- assert_equal 1, t.profiler.length
28
-
29
- node = t.profiler[0]
30
- assert_equal " 'a string' | upcase ", node.code
31
- end
32
-
33
- def test_render_ignores_raw_strings_when_profiling
34
- t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
35
- t.render!
36
-
37
- assert_equal 0, t.profiler.length
38
- end
39
-
40
- def test_profiling_includes_line_numbers_of_liquid_nodes
41
- t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
42
- t.render!
43
- assert_equal 2, t.profiler.length
44
-
45
- # {{ 'a string' | upcase }}
46
- assert_equal 1, t.profiler[0].line_number
47
- # {{ increment test }}
48
- assert_equal 2, t.profiler[1].line_number
49
- end
50
-
51
- def test_profiling_includes_line_numbers_of_included_partials
52
- t = Template.parse("{% include 'a_template' %}", profile: true)
53
- t.render!
54
-
55
- included_children = t.profiler[0].children
56
-
57
- # {% assign template_name = 'a_template' %}
58
- assert_equal 1, included_children[0].line_number
59
- # {{ template_name }}
60
- assert_equal 2, included_children[1].line_number
61
- end
62
-
63
- def test_profiling_times_the_rendering_of_tokens
64
- t = Template.parse("{% include 'a_template' %}", profile: true)
65
- t.render!
66
-
67
- node = t.profiler[0]
68
- refute_nil node.render_time
69
- end
70
-
71
- def test_profiling_times_the_entire_render
72
- t = Template.parse("{% include 'a_template' %}", profile: true)
73
- t.render!
74
-
75
- assert t.profiler.total_render_time >= 0, "Total render time was not calculated"
76
- end
77
-
78
- def test_profiling_uses_include_to_mark_children
79
- t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
80
- t.render!
81
-
82
- include_node = t.profiler[1]
83
- assert_equal 2, include_node.children.length
84
- end
85
-
86
- def test_profiling_marks_children_with_the_name_of_included_partial
87
- t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
88
- t.render!
89
-
90
- include_node = t.profiler[1]
91
- include_node.children.each do |child|
92
- assert_equal "a_template", child.partial
93
- end
94
- end
95
-
96
- def test_profiling_supports_multiple_templates
97
- t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", profile: true)
98
- t.render!
99
-
100
- a_template = t.profiler[1]
101
- a_template.children.each do |child|
102
- assert_equal "a_template", child.partial
103
- end
104
-
105
- b_template = t.profiler[2]
106
- b_template.children.each do |child|
107
- assert_equal "b_template", child.partial
108
- end
109
- end
110
-
111
- def test_profiling_supports_rendering_the_same_partial_multiple_times
112
- t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", profile: true)
113
- t.render!
114
-
115
- a_template1 = t.profiler[1]
116
- a_template1.children.each do |child|
117
- assert_equal "a_template", child.partial
118
- end
119
-
120
- a_template2 = t.profiler[2]
121
- a_template2.children.each do |child|
122
- assert_equal "a_template", child.partial
123
- end
124
- end
125
-
126
- def test_can_iterate_over_each_profiling_entry
127
- t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
128
- t.render!
129
-
130
- timing_count = 0
131
- t.profiler.each do |timing|
132
- timing_count += 1
133
- end
134
-
135
- assert_equal 2, timing_count
136
- end
137
-
138
- def test_profiling_marks_children_of_if_blocks
139
- t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
140
- t.render!
141
-
142
- assert_equal 1, t.profiler.length
143
- assert_equal 2, t.profiler[0].children.length
144
- end
145
-
146
- def test_profiling_marks_children_of_for_blocks
147
- t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
148
- t.render!({ "collection" => ["one", "two"] })
149
-
150
- assert_equal 1, t.profiler.length
151
- # Will profile each invocation of the for block
152
- assert_equal 2, t.profiler[0].children.length
153
- end
154
- end
@@ -1,80 +0,0 @@
1
- require 'test_helper'
2
-
3
- module SecurityFilter
4
- def add_one(input)
5
- "#{input} + 1"
6
- end
7
- end
8
-
9
- class SecurityTest < Minitest::Test
10
- include Liquid
11
-
12
- def setup
13
- @assigns = {}
14
- end
15
-
16
- def test_no_instance_eval
17
- text = %( {{ '1+1' | instance_eval }} )
18
- expected = %( 1+1 )
19
-
20
- assert_equal expected, Template.parse(text).render!(@assigns)
21
- end
22
-
23
- def test_no_existing_instance_eval
24
- text = %( {{ '1+1' | __instance_eval__ }} )
25
- expected = %( 1+1 )
26
-
27
- assert_equal expected, Template.parse(text).render!(@assigns)
28
- end
29
-
30
- def test_no_instance_eval_after_mixing_in_new_filter
31
- text = %( {{ '1+1' | instance_eval }} )
32
- expected = %( 1+1 )
33
-
34
- assert_equal expected, Template.parse(text).render!(@assigns)
35
- end
36
-
37
- def test_no_instance_eval_later_in_chain
38
- text = %( {{ '1+1' | add_one | instance_eval }} )
39
- expected = %( 1+1 + 1 )
40
-
41
- assert_equal expected, Template.parse(text).render!(@assigns, filters: SecurityFilter)
42
- end
43
-
44
- def test_does_not_add_filters_to_symbol_table
45
- current_symbols = Symbol.all_symbols
46
-
47
- test = %( {{ "some_string" | a_bad_filter }} )
48
-
49
- template = Template.parse(test)
50
- assert_equal [], (Symbol.all_symbols - current_symbols)
51
-
52
- template.render!
53
- assert_equal [], (Symbol.all_symbols - current_symbols)
54
- end
55
-
56
- def test_does_not_add_drop_methods_to_symbol_table
57
- current_symbols = Symbol.all_symbols
58
-
59
- assigns = { 'drop' => Drop.new }
60
- assert_equal "", Template.parse("{{ drop.custom_method_1 }}", assigns).render!
61
- assert_equal "", Template.parse("{{ drop.custom_method_2 }}", assigns).render!
62
- assert_equal "", Template.parse("{{ drop.custom_method_3 }}", assigns).render!
63
-
64
- assert_equal [], (Symbol.all_symbols - current_symbols)
65
- end
66
-
67
- def test_max_depth_nested_blocks_does_not_raise_exception
68
- depth = Liquid::Block::MAX_DEPTH
69
- code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
70
- assert_equal "rendered", Template.parse(code).render!
71
- end
72
-
73
- def test_more_than_max_depth_nested_blocks_raises_exception
74
- depth = Liquid::Block::MAX_DEPTH + 1
75
- code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
76
- assert_raises(Liquid::StackLevelError) do
77
- Template.parse(code).render!
78
- end
79
- end
80
- end # SecurityTest