liquid 4.0.2 → 5.1.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 (125) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +59 -0
  3. data/README.md +6 -0
  4. data/lib/liquid/block.rb +31 -14
  5. data/lib/liquid/block_body.rb +166 -53
  6. data/lib/liquid/condition.rb +41 -20
  7. data/lib/liquid/context.rb +107 -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 +29 -34
  12. data/lib/liquid/extensions.rb +2 -0
  13. data/lib/liquid/file_system.rb +6 -4
  14. data/lib/liquid/forloop_drop.rb +11 -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 +3 -1
  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/register.rb +6 -0
  28. data/lib/liquid/resource_limits.rb +47 -8
  29. data/lib/liquid/standardfilters.rb +95 -46
  30. data/lib/liquid/static_registers.rb +44 -0
  31. data/lib/liquid/strainer_factory.rb +36 -0
  32. data/lib/liquid/strainer_template.rb +53 -0
  33. data/lib/liquid/tablerowloop_drop.rb +6 -4
  34. data/lib/liquid/tag/disableable.rb +22 -0
  35. data/lib/liquid/tag/disabler.rb +21 -0
  36. data/lib/liquid/tag.rb +28 -6
  37. data/lib/liquid/tags/assign.rb +24 -10
  38. data/lib/liquid/tags/break.rb +8 -3
  39. data/lib/liquid/tags/capture.rb +11 -8
  40. data/lib/liquid/tags/case.rb +40 -27
  41. data/lib/liquid/tags/comment.rb +5 -3
  42. data/lib/liquid/tags/continue.rb +8 -3
  43. data/lib/liquid/tags/cycle.rb +25 -14
  44. data/lib/liquid/tags/decrement.rb +6 -3
  45. data/lib/liquid/tags/echo.rb +34 -0
  46. data/lib/liquid/tags/for.rb +68 -44
  47. data/lib/liquid/tags/if.rb +39 -23
  48. data/lib/liquid/tags/ifchanged.rb +11 -10
  49. data/lib/liquid/tags/include.rb +34 -47
  50. data/lib/liquid/tags/increment.rb +7 -3
  51. data/lib/liquid/tags/raw.rb +14 -11
  52. data/lib/liquid/tags/render.rb +84 -0
  53. data/lib/liquid/tags/table_row.rb +23 -19
  54. data/lib/liquid/tags/unless.rb +23 -15
  55. data/lib/liquid/template.rb +53 -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 +46 -41
  61. data/lib/liquid/variable_lookup.rb +11 -6
  62. data/lib/liquid/version.rb +2 -1
  63. data/lib/liquid.rb +17 -5
  64. data/test/integration/assign_test.rb +74 -5
  65. data/test/integration/blank_test.rb +11 -8
  66. data/test/integration/block_test.rb +47 -1
  67. data/test/integration/capture_test.rb +18 -10
  68. data/test/integration/context_test.rb +609 -5
  69. data/test/integration/document_test.rb +4 -2
  70. data/test/integration/drop_test.rb +67 -83
  71. data/test/integration/error_handling_test.rb +73 -61
  72. data/test/integration/expression_test.rb +46 -0
  73. data/test/integration/filter_test.rb +53 -42
  74. data/test/integration/hash_ordering_test.rb +5 -3
  75. data/test/integration/output_test.rb +26 -24
  76. data/test/integration/parsing_quirks_test.rb +19 -7
  77. data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
  78. data/test/integration/security_test.rb +30 -21
  79. data/test/integration/standard_filter_test.rb +385 -281
  80. data/test/integration/tag/disableable_test.rb +59 -0
  81. data/test/integration/tag_test.rb +45 -0
  82. data/test/integration/tags/break_tag_test.rb +4 -2
  83. data/test/integration/tags/continue_tag_test.rb +4 -2
  84. data/test/integration/tags/echo_test.rb +13 -0
  85. data/test/integration/tags/for_tag_test.rb +107 -51
  86. data/test/integration/tags/if_else_tag_test.rb +5 -3
  87. data/test/integration/tags/include_tag_test.rb +76 -52
  88. data/test/integration/tags/increment_tag_test.rb +4 -2
  89. data/test/integration/tags/liquid_tag_test.rb +116 -0
  90. data/test/integration/tags/raw_tag_test.rb +14 -11
  91. data/test/integration/tags/render_tag_test.rb +213 -0
  92. data/test/integration/tags/standard_tag_test.rb +38 -31
  93. data/test/integration/tags/statements_test.rb +23 -21
  94. data/test/integration/tags/table_row_test.rb +2 -0
  95. data/test/integration/tags/unless_else_tag_test.rb +4 -2
  96. data/test/integration/template_test.rb +132 -124
  97. data/test/integration/trim_mode_test.rb +78 -44
  98. data/test/integration/variable_test.rb +74 -32
  99. data/test/test_helper.rb +113 -22
  100. data/test/unit/block_unit_test.rb +19 -24
  101. data/test/unit/condition_unit_test.rb +79 -77
  102. data/test/unit/file_system_unit_test.rb +6 -4
  103. data/test/unit/i18n_unit_test.rb +7 -5
  104. data/test/unit/lexer_unit_test.rb +11 -9
  105. data/test/{integration → unit}/parse_tree_visitor_test.rb +16 -2
  106. data/test/unit/parser_unit_test.rb +37 -35
  107. data/test/unit/partial_cache_unit_test.rb +128 -0
  108. data/test/unit/regexp_unit_test.rb +17 -15
  109. data/test/unit/static_registers_unit_test.rb +156 -0
  110. data/test/unit/strainer_factory_unit_test.rb +100 -0
  111. data/test/unit/strainer_template_unit_test.rb +82 -0
  112. data/test/unit/tag_unit_test.rb +5 -3
  113. data/test/unit/tags/case_tag_unit_test.rb +3 -1
  114. data/test/unit/tags/for_tag_unit_test.rb +4 -2
  115. data/test/unit/tags/if_tag_unit_test.rb +3 -1
  116. data/test/unit/template_factory_unit_test.rb +12 -0
  117. data/test/unit/template_unit_test.rb +19 -10
  118. data/test/unit/tokenizer_unit_test.rb +26 -19
  119. data/test/unit/variable_unit_test.rb +51 -49
  120. metadata +76 -50
  121. data/lib/liquid/strainer.rb +0 -66
  122. data/lib/liquid/truffle.rb +0 -5
  123. data/test/truffle/truffle_test.rb +0 -9
  124. data/test/unit/context_unit_test.rb +0 -489
  125. data/test/unit/strainer_unit_test.rb +0 -164
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class TrimModeTest < Minitest::Test
@@ -67,7 +69,7 @@ class TrimModeTest < Minitest::Test
67
69
  # Make sure the trim isn't applied to standard tags
68
70
  def test_standard_tags
69
71
  whitespace = ' '
70
- text = <<-END_TEMPLATE
72
+ text = <<-END_TEMPLATE
71
73
  <div>
72
74
  <p>
73
75
  {% if true %}
@@ -76,14 +78,14 @@ class TrimModeTest < Minitest::Test
76
78
  </p>
77
79
  </div>
78
80
  END_TEMPLATE
79
- expected = <<-END_EXPECTED
80
- <div>
81
- <p>
82
- #{whitespace}
83
- yes
84
- #{whitespace}
85
- </p>
86
- </div>
81
+ expected = <<~END_EXPECTED
82
+ <div>
83
+ <p>
84
+ #{whitespace}
85
+ yes
86
+ #{whitespace}
87
+ </p>
88
+ </div>
87
89
  END_EXPECTED
88
90
  assert_template_result(expected, text)
89
91
 
@@ -96,70 +98,70 @@ class TrimModeTest < Minitest::Test
96
98
  </p>
97
99
  </div>
98
100
  END_TEMPLATE
99
- expected = <<-END_EXPECTED
100
- <div>
101
- <p>
102
- #{whitespace}
103
- </p>
104
- </div>
101
+ expected = <<~END_EXPECTED
102
+ <div>
103
+ <p>
104
+ #{whitespace}
105
+ </p>
106
+ </div>
105
107
  END_EXPECTED
106
108
  assert_template_result(expected, text)
107
109
  end
108
110
 
109
111
  # Make sure the trim isn't too agressive
110
112
  def test_no_trim_output
111
- text = '<p>{{- \'John\' -}}</p>'
113
+ text = '<p>{{- \'John\' -}}</p>'
112
114
  expected = '<p>John</p>'
113
115
  assert_template_result(expected, text)
114
116
  end
115
117
 
116
118
  # Make sure the trim isn't too agressive
117
119
  def test_no_trim_tags
118
- text = '<p>{%- if true -%}yes{%- endif -%}</p>'
120
+ text = '<p>{%- if true -%}yes{%- endif -%}</p>'
119
121
  expected = '<p>yes</p>'
120
122
  assert_template_result(expected, text)
121
123
 
122
- text = '<p>{%- if false -%}no{%- endif -%}</p>'
124
+ text = '<p>{%- if false -%}no{%- endif -%}</p>'
123
125
  expected = '<p></p>'
124
126
  assert_template_result(expected, text)
125
127
  end
126
128
 
127
129
  def test_single_line_outer_tag
128
- text = '<p> {%- if true %} yes {% endif -%} </p>'
130
+ text = '<p> {%- if true %} yes {% endif -%} </p>'
129
131
  expected = '<p> yes </p>'
130
132
  assert_template_result(expected, text)
131
133
 
132
- text = '<p> {%- if false %} no {% endif -%} </p>'
134
+ text = '<p> {%- if false %} no {% endif -%} </p>'
133
135
  expected = '<p></p>'
134
136
  assert_template_result(expected, text)
135
137
  end
136
138
 
137
139
  def test_single_line_inner_tag
138
- text = '<p> {% if true -%} yes {%- endif %} </p>'
140
+ text = '<p> {% if true -%} yes {%- endif %} </p>'
139
141
  expected = '<p> yes </p>'
140
142
  assert_template_result(expected, text)
141
143
 
142
- text = '<p> {% if false -%} no {%- endif %} </p>'
144
+ text = '<p> {% if false -%} no {%- endif %} </p>'
143
145
  expected = '<p> </p>'
144
146
  assert_template_result(expected, text)
145
147
  end
146
148
 
147
149
  def test_single_line_post_tag
148
- text = '<p> {% if true -%} yes {% endif -%} </p>'
150
+ text = '<p> {% if true -%} yes {% endif -%} </p>'
149
151
  expected = '<p> yes </p>'
150
152
  assert_template_result(expected, text)
151
153
 
152
- text = '<p> {% if false -%} no {% endif -%} </p>'
154
+ text = '<p> {% if false -%} no {% endif -%} </p>'
153
155
  expected = '<p> </p>'
154
156
  assert_template_result(expected, text)
155
157
  end
156
158
 
157
159
  def test_single_line_pre_tag
158
- text = '<p> {%- if true %} yes {%- endif %} </p>'
160
+ text = '<p> {%- if true %} yes {%- endif %} </p>'
159
161
  expected = '<p> yes </p>'
160
162
  assert_template_result(expected, text)
161
163
 
162
- text = '<p> {%- if false %} no {%- endif %} </p>'
164
+ text = '<p> {%- if false %} no {%- endif %} </p>'
163
165
  expected = '<p> </p>'
164
166
  assert_template_result(expected, text)
165
167
  end
@@ -328,7 +330,7 @@ class TrimModeTest < Minitest::Test
328
330
  assert_template_result(expected, text)
329
331
 
330
332
  whitespace = ' '
331
- text = <<-END_TEMPLATE
333
+ text = <<-END_TEMPLATE
332
334
  <div>
333
335
  <p>
334
336
  {% if false -%}
@@ -337,12 +339,12 @@ class TrimModeTest < Minitest::Test
337
339
  </p>
338
340
  </div>
339
341
  END_TEMPLATE
340
- expected = <<-END_EXPECTED
341
- <div>
342
- <p>
343
- #{whitespace}
344
- </p>
345
- </div>
342
+ expected = <<~END_EXPECTED
343
+ <div>
344
+ <p>
345
+ #{whitespace}
346
+ </p>
347
+ </div>
346
348
  END_EXPECTED
347
349
  assert_template_result(expected, text)
348
350
  end
@@ -502,7 +504,7 @@ class TrimModeTest < Minitest::Test
502
504
 
503
505
  def test_raw_output
504
506
  whitespace = ' '
505
- text = <<-END_TEMPLATE
507
+ text = <<-END_TEMPLATE
506
508
  <div>
507
509
  {% raw %}
508
510
  {%- if true -%}
@@ -513,17 +515,49 @@ class TrimModeTest < Minitest::Test
513
515
  {% endraw %}
514
516
  </div>
515
517
  END_TEMPLATE
516
- expected = <<-END_EXPECTED
517
- <div>
518
- #{whitespace}
519
- {%- if true -%}
520
- <p>
521
- {{- 'John' -}}
522
- </p>
523
- {%- endif -%}
524
- #{whitespace}
525
- </div>
518
+ expected = <<~END_EXPECTED
519
+ <div>
520
+ #{whitespace}
521
+ {%- if true -%}
522
+ <p>
523
+ {{- 'John' -}}
524
+ </p>
525
+ {%- endif -%}
526
+ #{whitespace}
527
+ </div>
526
528
  END_EXPECTED
527
529
  assert_template_result(expected, text)
528
530
  end
531
+
532
+ def test_pre_trim_blank_preceding_text
533
+ template = Liquid::Template.parse("\n{%- raw %}{% endraw %}")
534
+ assert_equal("", template.render)
535
+
536
+ template = Liquid::Template.parse("\n{%- if true %}{% endif %}")
537
+ assert_equal("", template.render)
538
+
539
+ template = Liquid::Template.parse("{{ 'B' }} \n{%- if true %}C{% endif %}")
540
+ assert_equal("BC", template.render)
541
+ end
542
+
543
+ def test_bug_compatible_pre_trim
544
+ template = Liquid::Template.parse("\n {%- raw %}{% endraw %}", bug_compatible_whitespace_trimming: true)
545
+ assert_equal("\n", template.render)
546
+
547
+ template = Liquid::Template.parse("\n {%- if true %}{% endif %}", bug_compatible_whitespace_trimming: true)
548
+ assert_equal("\n", template.render)
549
+
550
+ template = Liquid::Template.parse("{{ 'B' }} \n{%- if true %}C{% endif %}", bug_compatible_whitespace_trimming: true)
551
+ assert_equal("B C", template.render)
552
+
553
+ template = Liquid::Template.parse("B\n {%- raw %}{% endraw %}", bug_compatible_whitespace_trimming: true)
554
+ assert_equal("B", template.render)
555
+
556
+ template = Liquid::Template.parse("B\n {%- if true %}{% endif %}", bug_compatible_whitespace_trimming: true)
557
+ assert_equal("B", template.render)
558
+ end
559
+
560
+ def test_trim_blank
561
+ assert_template_result('foobar', 'foo {{-}} bar')
562
+ end
529
563
  end # TrimModeTest
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class VariableTest < Minitest::Test
@@ -5,92 +7,132 @@ class VariableTest < Minitest::Test
5
7
 
6
8
  def test_simple_variable
7
9
  template = Template.parse(%({{test}}))
8
- assert_equal 'worked', template.render!('test' => 'worked')
9
- assert_equal 'worked wonderfully', template.render!('test' => 'worked wonderfully')
10
+ assert_equal('worked', template.render!('test' => 'worked'))
11
+ assert_equal('worked wonderfully', template.render!('test' => 'worked wonderfully'))
10
12
  end
11
13
 
12
14
  def test_variable_render_calls_to_liquid
13
- assert_template_result 'foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new
15
+ assert_template_result('foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new)
16
+ end
17
+
18
+ def test_variable_lookup_calls_to_liquid_value
19
+ assert_template_result('1', '{{ foo }}', 'foo' => IntegerDrop.new('1'))
20
+ assert_template_result('2', '{{ list[foo] }}', 'foo' => IntegerDrop.new('1'), 'list' => [1, 2, 3])
21
+ assert_template_result('one', '{{ list[foo] }}', 'foo' => IntegerDrop.new('1'), 'list' => { 1 => 'one' })
22
+ assert_template_result('Yay', '{{ foo }}', 'foo' => BooleanDrop.new(true))
23
+ assert_template_result('YAY', '{{ foo | upcase }}', 'foo' => BooleanDrop.new(true))
24
+ end
25
+
26
+ def test_if_tag_calls_to_liquid_value
27
+ assert_template_result('one', '{% if foo == 1 %}one{% endif %}', 'foo' => IntegerDrop.new('1'))
28
+ assert_template_result('one', '{% if 0 < foo %}one{% endif %}', 'foo' => IntegerDrop.new('1'))
29
+ assert_template_result('one', '{% if foo > 0 %}one{% endif %}', 'foo' => IntegerDrop.new('1'))
30
+ assert_template_result('true', '{% if foo == true %}true{% endif %}', 'foo' => BooleanDrop.new(true))
31
+ assert_template_result('true', '{% if foo %}true{% endif %}', 'foo' => BooleanDrop.new(true))
32
+
33
+ assert_template_result('', '{% if foo %}true{% endif %}', 'foo' => BooleanDrop.new(false))
34
+ assert_template_result('', '{% if foo == true %}True{% endif %}', 'foo' => BooleanDrop.new(false))
35
+ end
36
+
37
+ def test_unless_tag_calls_to_liquid_value
38
+ assert_template_result('', '{% unless foo %}true{% endunless %}', 'foo' => BooleanDrop.new(true))
39
+ end
40
+
41
+ def test_case_tag_calls_to_liquid_value
42
+ assert_template_result('One', '{% case foo %}{% when 1 %}One{% endcase %}', 'foo' => IntegerDrop.new('1'))
14
43
  end
15
44
 
16
45
  def test_simple_with_whitespaces
17
46
  template = Template.parse(%( {{ test }} ))
18
- assert_equal ' worked ', template.render!('test' => 'worked')
19
- assert_equal ' worked wonderfully ', template.render!('test' => 'worked wonderfully')
47
+ assert_equal(' worked ', template.render!('test' => 'worked'))
48
+ assert_equal(' worked wonderfully ', template.render!('test' => 'worked wonderfully'))
49
+ end
50
+
51
+ def test_expression_with_whitespace_in_square_brackets
52
+ assert_template_result('result', "{{ a[ 'b' ] }}", 'a' => { 'b' => 'result' })
53
+ assert_template_result('result', "{{ a[ [ 'b' ] ] }}", 'b' => 'c', 'a' => { 'c' => 'result' })
20
54
  end
21
55
 
22
56
  def test_ignore_unknown
23
57
  template = Template.parse(%({{ test }}))
24
- assert_equal '', template.render!
58
+ assert_equal('', template.render!)
25
59
  end
26
60
 
27
61
  def test_using_blank_as_variable_name
28
62
  template = Template.parse("{% assign foo = blank %}{{ foo }}")
29
- assert_equal '', template.render!
63
+ assert_equal('', template.render!)
30
64
  end
31
65
 
32
66
  def test_using_empty_as_variable_name
33
67
  template = Template.parse("{% assign foo = empty %}{{ foo }}")
34
- assert_equal '', template.render!
68
+ assert_equal('', template.render!)
35
69
  end
36
70
 
37
71
  def test_hash_scoping
38
- template = Template.parse(%({{ test.test }}))
39
- assert_equal 'worked', template.render!('test' => { 'test' => 'worked' })
72
+ assert_template_result('worked', "{{ test.test }}", 'test' => { 'test' => 'worked' })
73
+ assert_template_result('worked', "{{ test . test }}", 'test' => { 'test' => 'worked' })
40
74
  end
41
75
 
42
76
  def test_false_renders_as_false
43
- assert_equal 'false', Template.parse("{{ foo }}").render!('foo' => false)
44
- assert_equal 'false', Template.parse("{{ false }}").render!
77
+ assert_equal('false', Template.parse("{{ foo }}").render!('foo' => false))
78
+ assert_equal('false', Template.parse("{{ false }}").render!)
45
79
  end
46
80
 
47
81
  def test_nil_renders_as_empty_string
48
- assert_equal '', Template.parse("{{ nil }}").render!
49
- assert_equal 'cat', Template.parse("{{ nil | append: 'cat' }}").render!
82
+ assert_equal('', Template.parse("{{ nil }}").render!)
83
+ assert_equal('cat', Template.parse("{{ nil | append: 'cat' }}").render!)
50
84
  end
51
85
 
52
86
  def test_preset_assigns
53
- template = Template.parse(%({{ test }}))
87
+ template = Template.parse(%({{ test }}))
54
88
  template.assigns['test'] = 'worked'
55
- assert_equal 'worked', template.render!
89
+ assert_equal('worked', template.render!)
56
90
  end
57
91
 
58
92
  def test_reuse_parsed_template
59
- template = Template.parse(%({{ greeting }} {{ name }}))
93
+ template = Template.parse(%({{ greeting }} {{ name }}))
60
94
  template.assigns['greeting'] = 'Goodbye'
61
- assert_equal 'Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi')
62
- assert_equal 'Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi')
63
- assert_equal 'Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian')
64
- assert_equal 'Goodbye Brian', template.render!('name' => 'Brian')
95
+ assert_equal('Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi'))
96
+ assert_equal('Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi'))
97
+ assert_equal('Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian'))
98
+ assert_equal('Goodbye Brian', template.render!('name' => 'Brian'))
65
99
  assert_equal({ 'greeting' => 'Goodbye' }, template.assigns)
66
100
  end
67
101
 
68
102
  def test_assigns_not_polluted_from_template
69
- template = Template.parse(%({{ test }}{% assign test = 'bar' %}{{ test }}))
103
+ template = Template.parse(%({{ test }}{% assign test = 'bar' %}{{ test }}))
70
104
  template.assigns['test'] = 'baz'
71
- assert_equal 'bazbar', template.render!
72
- assert_equal 'bazbar', template.render!
73
- assert_equal 'foobar', template.render!('test' => 'foo')
74
- assert_equal 'bazbar', template.render!
105
+ assert_equal('bazbar', template.render!)
106
+ assert_equal('bazbar', template.render!)
107
+ assert_equal('foobar', template.render!('test' => 'foo'))
108
+ assert_equal('bazbar', template.render!)
75
109
  end
76
110
 
77
111
  def test_hash_with_default_proc
78
- template = Template.parse(%(Hello {{ test }}))
79
- assigns = Hash.new { |h, k| raise "Unknown variable '#{k}'" }
112
+ template = Template.parse(%(Hello {{ test }}))
113
+ assigns = Hash.new { |_h, k| raise "Unknown variable '#{k}'" }
80
114
  assigns['test'] = 'Tobi'
81
- assert_equal 'Hello Tobi', template.render!(assigns)
115
+ assert_equal('Hello Tobi', template.render!(assigns))
82
116
  assigns.delete('test')
83
117
  e = assert_raises(RuntimeError) do
84
118
  template.render!(assigns)
85
119
  end
86
- assert_equal "Unknown variable 'test'", e.message
120
+ assert_equal("Unknown variable 'test'", e.message)
87
121
  end
88
122
 
89
123
  def test_multiline_variable
90
- assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked')
124
+ assert_equal('worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked'))
91
125
  end
92
126
 
93
127
  def test_render_symbol
94
- assert_template_result 'bar', '{{ foo }}', 'foo' => :bar
128
+ assert_template_result('bar', '{{ foo }}', 'foo' => :bar)
129
+ end
130
+
131
+ def test_dynamic_find_var
132
+ assert_template_result('bar', '{{ [key] }}', 'key' => 'foo', 'foo' => 'bar')
133
+ end
134
+
135
+ def test_raw_value_variable
136
+ assert_template_result('bar', '{{ [key] }}', 'key' => 'foo', 'foo' => 'bar')
95
137
  end
96
138
  end
data/test/test_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  ENV["MT_NO_EXPECTATIONS"] = "1"
4
5
  require 'minitest/autorun'
@@ -8,13 +9,13 @@ require 'liquid.rb'
8
9
  require 'liquid/profiler'
9
10
 
10
11
  mode = :strict
11
- if env_mode = ENV['LIQUID_PARSER_MODE']
12
+ if (env_mode = ENV['LIQUID_PARSER_MODE'])
12
13
  puts "-- #{env_mode.upcase} ERROR MODE"
13
14
  mode = env_mode.to_sym
14
15
  end
15
16
  Liquid::Template.error_mode = mode
16
17
 
17
- if ENV['LIQUID-C'] == '1'
18
+ if ENV['LIQUID_C'] == '1'
18
19
  puts "-- LIQUID C"
19
20
  require 'liquid/c'
20
21
  end
@@ -37,44 +38,55 @@ module Minitest
37
38
  include Liquid
38
39
 
39
40
  def assert_template_result(expected, template, assigns = {}, message = nil)
40
- assert_equal expected, Template.parse(template).render!(assigns), message
41
+ assert_equal(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
41
42
  end
42
43
 
43
44
  def assert_template_result_matches(expected, template, assigns = {}, message = nil)
44
- return assert_template_result(expected, template, assigns, message) unless expected.is_a? Regexp
45
+ return assert_template_result(expected, template, assigns, message) unless expected.is_a?(Regexp)
45
46
 
46
- assert_match expected, Template.parse(template).render!(assigns), message
47
+ assert_match(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
47
48
  end
48
49
 
49
50
  def assert_match_syntax_error(match, template, assigns = {})
50
51
  exception = assert_raises(Liquid::SyntaxError) do
51
- Template.parse(template).render(assigns)
52
+ Template.parse(template, line_numbers: true).render(assigns)
52
53
  end
53
- assert_match match, exception.message
54
+ assert_match(match, exception.message)
55
+ end
56
+
57
+ def assert_usage_increment(name, times: 1)
58
+ old_method = Liquid::Usage.method(:increment)
59
+ calls = 0
60
+ begin
61
+ Liquid::Usage.singleton_class.send(:remove_method, :increment)
62
+ Liquid::Usage.define_singleton_method(:increment) do |got_name|
63
+ calls += 1 if got_name == name
64
+ old_method.call(got_name)
65
+ end
66
+ yield
67
+ ensure
68
+ Liquid::Usage.singleton_class.send(:remove_method, :increment)
69
+ Liquid::Usage.define_singleton_method(:increment, old_method)
70
+ end
71
+ assert_equal(times, calls, "Number of calls to Usage.increment with #{name.inspect}")
54
72
  end
55
73
 
56
74
  def with_global_filter(*globals)
57
- original_global_strainer = Liquid::Strainer.class_variable_get(:@@global_strainer)
58
- Liquid::Strainer.class_variable_set(:@@global_strainer, Class.new(Liquid::Strainer) do
59
- @filter_methods = Set.new
60
- end)
61
- Liquid::Strainer.class_variable_get(:@@strainer_class_cache).clear
75
+ original_global_filters = Liquid::StrainerFactory.instance_variable_get(:@global_filters)
76
+ Liquid::StrainerFactory.instance_variable_set(:@global_filters, [])
77
+ globals.each do |global|
78
+ Liquid::StrainerFactory.add_global_filter(global)
79
+ end
80
+
81
+ Liquid::StrainerFactory.send(:strainer_class_cache).clear
62
82
 
63
83
  globals.each do |global|
64
84
  Liquid::Template.register_filter(global)
65
85
  end
66
86
  yield
67
87
  ensure
68
- Liquid::Strainer.class_variable_get(:@@strainer_class_cache).clear
69
- Liquid::Strainer.class_variable_set(:@@global_strainer, original_global_strainer)
70
- end
71
-
72
- def with_taint_mode(mode)
73
- old_mode = Liquid::Template.taint_mode
74
- Liquid::Template.taint_mode = mode
75
- yield
76
- ensure
77
- Liquid::Template.taint_mode = old_mode
88
+ Liquid::StrainerFactory.send(:strainer_class_cache).clear
89
+ Liquid::StrainerFactory.instance_variable_set(:@global_filters, original_global_filters)
78
90
  end
79
91
 
80
92
  def with_error_mode(mode)
@@ -84,6 +96,20 @@ module Minitest
84
96
  ensure
85
97
  Liquid::Template.error_mode = old_mode
86
98
  end
99
+
100
+ def with_custom_tag(tag_name, tag_class)
101
+ old_tag = Liquid::Template.tags[tag_name]
102
+ begin
103
+ Liquid::Template.register_tag(tag_name, tag_class)
104
+ yield
105
+ ensure
106
+ if old_tag
107
+ Liquid::Template.tags[tag_name] = old_tag
108
+ else
109
+ Liquid::Template.tags.delete(tag_name)
110
+ end
111
+ end
112
+ end
87
113
  end
88
114
  end
89
115
 
@@ -93,6 +119,44 @@ class ThingWithToLiquid
93
119
  end
94
120
  end
95
121
 
122
+ class IntegerDrop < Liquid::Drop
123
+ def initialize(value)
124
+ super()
125
+ @value = value.to_i
126
+ end
127
+
128
+ def ==(other)
129
+ @value == other
130
+ end
131
+
132
+ def to_s
133
+ @value.to_s
134
+ end
135
+
136
+ def to_liquid_value
137
+ @value
138
+ end
139
+ end
140
+
141
+ class BooleanDrop < Liquid::Drop
142
+ def initialize(value)
143
+ super()
144
+ @value = value
145
+ end
146
+
147
+ def ==(other)
148
+ @value == other
149
+ end
150
+
151
+ def to_liquid_value
152
+ @value
153
+ end
154
+
155
+ def to_s
156
+ @value ? "Yay" : "Nay"
157
+ end
158
+ end
159
+
96
160
  class ErrorDrop < Liquid::Drop
97
161
  def standard_error
98
162
  raise Liquid::StandardError, 'standard error'
@@ -114,3 +178,30 @@ class ErrorDrop < Liquid::Drop
114
178
  raise Exception, 'exception'
115
179
  end
116
180
  end
181
+
182
+ class StubFileSystem
183
+ attr_reader :file_read_count
184
+
185
+ def initialize(values)
186
+ @file_read_count = 0
187
+ @values = values
188
+ end
189
+
190
+ def read_template_file(template_path)
191
+ @file_read_count += 1
192
+ @values.fetch(template_path)
193
+ end
194
+ end
195
+
196
+ class StubTemplateFactory
197
+ attr_reader :count
198
+
199
+ def initialize
200
+ @count = 0
201
+ end
202
+
203
+ def for(_template_name)
204
+ @count += 1
205
+ Liquid::Template.new
206
+ end
207
+ end