liquid 4.0.3 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
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,178 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MoneyFilter
4
- def money(input)
5
- sprintf(' %d$ ', input)
6
- end
7
-
8
- def money_with_underscore(input)
9
- sprintf(' %d$ ', input)
10
- end
11
- end
12
-
13
- module CanadianMoneyFilter
14
- def money(input)
15
- sprintf(' %d$ CAD ', input)
16
- end
17
- end
18
-
19
- module SubstituteFilter
20
- def substitute(input, params = {})
21
- input.gsub(/%\{(\w+)\}/) { |match| params[$1] }
22
- end
23
- end
24
-
25
- class FiltersTest < Minitest::Test
26
- include Liquid
27
-
28
- module OverrideObjectMethodFilter
29
- def tap(input)
30
- "tap overridden"
31
- end
32
- end
33
-
34
- def setup
35
- @context = Context.new
36
- end
37
-
38
- def test_local_filter
39
- @context['var'] = 1000
40
- @context.add_filters(MoneyFilter)
41
-
42
- assert_equal ' 1000$ ', Template.parse("{{var | money}}").render(@context)
43
- end
44
-
45
- def test_underscore_in_filter_name
46
- @context['var'] = 1000
47
- @context.add_filters(MoneyFilter)
48
- assert_equal ' 1000$ ', Template.parse("{{var | money_with_underscore}}").render(@context)
49
- end
50
-
51
- def test_second_filter_overwrites_first
52
- @context['var'] = 1000
53
- @context.add_filters(MoneyFilter)
54
- @context.add_filters(CanadianMoneyFilter)
55
-
56
- assert_equal ' 1000$ CAD ', Template.parse("{{var | money}}").render(@context)
57
- end
58
-
59
- def test_size
60
- @context['var'] = 'abcd'
61
- @context.add_filters(MoneyFilter)
62
-
63
- assert_equal '4', Template.parse("{{var | size}}").render(@context)
64
- end
65
-
66
- def test_join
67
- @context['var'] = [1, 2, 3, 4]
68
-
69
- assert_equal "1 2 3 4", Template.parse("{{var | join}}").render(@context)
70
- end
71
-
72
- def test_sort
73
- @context['value'] = 3
74
- @context['numbers'] = [2, 1, 4, 3]
75
- @context['words'] = ['expected', 'as', 'alphabetic']
76
- @context['arrays'] = ['flower', 'are']
77
- @context['case_sensitive'] = ['sensitive', 'Expected', 'case']
78
-
79
- assert_equal '1 2 3 4', Template.parse("{{numbers | sort | join}}").render(@context)
80
- assert_equal 'alphabetic as expected', Template.parse("{{words | sort | join}}").render(@context)
81
- assert_equal '3', Template.parse("{{value | sort}}").render(@context)
82
- assert_equal 'are flower', Template.parse("{{arrays | sort | join}}").render(@context)
83
- assert_equal 'Expected case sensitive', Template.parse("{{case_sensitive | sort | join}}").render(@context)
84
- end
85
-
86
- def test_sort_natural
87
- @context['words'] = ['case', 'Assert', 'Insensitive']
88
- @context['hashes'] = [{ 'a' => 'A' }, { 'a' => 'b' }, { 'a' => 'C' }]
89
- @context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
90
-
91
- # Test strings
92
- assert_equal 'Assert case Insensitive', Template.parse("{{words | sort_natural | join}}").render(@context)
93
-
94
- # Test hashes
95
- assert_equal 'A b C', Template.parse("{{hashes | sort_natural: 'a' | map: 'a' | join}}").render(@context)
96
-
97
- # Test objects
98
- assert_equal 'A b C', Template.parse("{{objects | sort_natural: 'a' | map: 'a' | join}}").render(@context)
99
- end
100
-
101
- def test_compact
102
- @context['words'] = ['a', nil, 'b', nil, 'c']
103
- @context['hashes'] = [{ 'a' => 'A' }, { 'a' => nil }, { 'a' => 'C' }]
104
- @context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')]
105
-
106
- # Test strings
107
- assert_equal 'a b c', Template.parse("{{words | compact | join}}").render(@context)
108
-
109
- # Test hashes
110
- assert_equal 'A C', Template.parse("{{hashes | compact: 'a' | map: 'a' | join}}").render(@context)
111
-
112
- # Test objects
113
- assert_equal 'A C', Template.parse("{{objects | compact: 'a' | map: 'a' | join}}").render(@context)
114
- end
115
-
116
- def test_strip_html
117
- @context['var'] = "<b>bla blub</a>"
118
-
119
- assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
120
- end
121
-
122
- def test_strip_html_ignore_comments_with_html
123
- @context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
124
-
125
- assert_equal "bla blub", Template.parse("{{ var | strip_html }}").render(@context)
126
- end
127
-
128
- def test_capitalize
129
- @context['var'] = "blub"
130
-
131
- assert_equal "Blub", Template.parse("{{ var | capitalize }}").render(@context)
132
- end
133
-
134
- def test_nonexistent_filter_is_ignored
135
- @context['var'] = 1000
136
-
137
- assert_equal '1000', Template.parse("{{ var | xyzzy }}").render(@context)
138
- end
139
-
140
- def test_filter_with_keyword_arguments
141
- @context['surname'] = 'john'
142
- @context['input'] = 'hello %{first_name}, %{last_name}'
143
- @context.add_filters(SubstituteFilter)
144
- output = Template.parse(%({{ input | substitute: first_name: surname, last_name: 'doe' }})).render(@context)
145
- assert_equal 'hello john, doe', output
146
- end
147
-
148
- def test_override_object_method_in_filter
149
- assert_equal "tap overridden", Template.parse("{{var | tap}}").render!({ 'var' => 1000 }, filters: [OverrideObjectMethodFilter])
150
-
151
- # tap still treated as a non-existent filter
152
- assert_equal "1000", Template.parse("{{var | tap}}").render!({ 'var' => 1000 })
153
- end
154
- end
155
-
156
- class FiltersInTemplate < Minitest::Test
157
- include Liquid
158
-
159
- def test_local_global
160
- with_global_filter(MoneyFilter) do
161
- assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
162
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: CanadianMoneyFilter)
163
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, filters: [CanadianMoneyFilter])
164
- end
165
- end
166
-
167
- def test_local_filter_with_deprecated_syntax
168
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, CanadianMoneyFilter)
169
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
170
- end
171
- end # FiltersTest
172
-
173
- class TestObject < Liquid::Drop
174
- attr_accessor :a
175
- def initialize(a)
176
- @a = a
177
- end
178
- end
@@ -1,23 +0,0 @@
1
- require 'test_helper'
2
-
3
- class HashOrderingTest < Minitest::Test
4
- module MoneyFilter
5
- def money(input)
6
- sprintf(' %d$ ', input)
7
- end
8
- end
9
-
10
- module CanadianMoneyFilter
11
- def money(input)
12
- sprintf(' %d$ CAD ', input)
13
- end
14
- end
15
-
16
- include Liquid
17
-
18
- def test_global_register_order
19
- with_global_filter(MoneyFilter, CanadianMoneyFilter) do
20
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil)
21
- end
22
- end
23
- end
@@ -1,123 +0,0 @@
1
- require 'test_helper'
2
-
3
- module FunnyFilter
4
- def make_funny(input)
5
- 'LOL'
6
- end
7
-
8
- def cite_funny(input)
9
- "LOL: #{input}"
10
- end
11
-
12
- def add_smiley(input, smiley = ":-)")
13
- "#{input} #{smiley}"
14
- end
15
-
16
- def add_tag(input, tag = "p", id = "foo")
17
- %(<#{tag} id="#{id}">#{input}</#{tag}>)
18
- end
19
-
20
- def paragraph(input)
21
- "<p>#{input}</p>"
22
- end
23
-
24
- def link_to(name, url)
25
- %(<a href="#{url}">#{name}</a>)
26
- end
27
- end
28
-
29
- class OutputTest < Minitest::Test
30
- include Liquid
31
-
32
- def setup
33
- @assigns = {
34
- 'best_cars' => 'bmw',
35
- 'car' => { 'bmw' => 'good', 'gm' => 'bad' }
36
- }
37
- end
38
-
39
- def test_variable
40
- text = %( {{best_cars}} )
41
-
42
- expected = %( bmw )
43
- assert_equal expected, Template.parse(text).render!(@assigns)
44
- end
45
-
46
- def test_variable_traversing_with_two_brackets
47
- text = %({{ site.data.menu[include.menu][include.locale] }})
48
- assert_equal "it works!", Template.parse(text).render!(
49
- "site" => { "data" => { "menu" => { "foo" => { "bar" => "it works!" } } } },
50
- "include" => { "menu" => "foo", "locale" => "bar" }
51
- )
52
- end
53
-
54
- def test_variable_traversing
55
- text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
56
-
57
- expected = %( good bad good )
58
- assert_equal expected, Template.parse(text).render!(@assigns)
59
- end
60
-
61
- def test_variable_piping
62
- text = %( {{ car.gm | make_funny }} )
63
- expected = %( LOL )
64
-
65
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
66
- end
67
-
68
- def test_variable_piping_with_input
69
- text = %( {{ car.gm | cite_funny }} )
70
- expected = %( LOL: bad )
71
-
72
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
73
- end
74
-
75
- def test_variable_piping_with_args
76
- text = %! {{ car.gm | add_smiley : ':-(' }} !
77
- expected = %| bad :-( |
78
-
79
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
80
- end
81
-
82
- def test_variable_piping_with_no_args
83
- text = %( {{ car.gm | add_smiley }} )
84
- expected = %| bad :-) |
85
-
86
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
87
- end
88
-
89
- def test_multiple_variable_piping_with_args
90
- text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
91
- expected = %| bad :-( :-( |
92
-
93
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
94
- end
95
-
96
- def test_variable_piping_with_multiple_args
97
- text = %( {{ car.gm | add_tag : 'span', 'bar'}} )
98
- expected = %( <span id="bar">bad</span> )
99
-
100
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
101
- end
102
-
103
- def test_variable_piping_with_variable_args
104
- text = %( {{ car.gm | add_tag : 'span', car.bmw}} )
105
- expected = %( <span id="good">bad</span> )
106
-
107
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
108
- end
109
-
110
- def test_multiple_pipings
111
- text = %( {{ best_cars | cite_funny | paragraph }} )
112
- expected = %( <p>LOL: bmw</p> )
113
-
114
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
115
- end
116
-
117
- def test_link_to
118
- text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
119
- expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
120
-
121
- assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
122
- end
123
- end # OutputTest
@@ -1,247 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class ParseTreeVisitorTest < Minitest::Test
6
- include Liquid
7
-
8
- def test_variable
9
- assert_equal(
10
- ["test"],
11
- visit(%({{ test }}))
12
- )
13
- end
14
-
15
- def test_varible_with_filter
16
- assert_equal(
17
- ["test", "infilter"],
18
- visit(%({{ test | split: infilter }}))
19
- )
20
- end
21
-
22
- def test_dynamic_variable
23
- assert_equal(
24
- ["test", "inlookup"],
25
- visit(%({{ test[inlookup] }}))
26
- )
27
- end
28
-
29
- def test_if_condition
30
- assert_equal(
31
- ["test"],
32
- visit(%({% if test %}{% endif %}))
33
- )
34
- end
35
-
36
- def test_complex_if_condition
37
- assert_equal(
38
- ["test"],
39
- visit(%({% if 1 == 1 and 2 == test %}{% endif %}))
40
- )
41
- end
42
-
43
- def test_if_body
44
- assert_equal(
45
- ["test"],
46
- visit(%({% if 1 == 1 %}{{ test }}{% endif %}))
47
- )
48
- end
49
-
50
- def test_unless_condition
51
- assert_equal(
52
- ["test"],
53
- visit(%({% unless test %}{% endunless %}))
54
- )
55
- end
56
-
57
- def test_complex_unless_condition
58
- assert_equal(
59
- ["test"],
60
- visit(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
61
- )
62
- end
63
-
64
- def test_unless_body
65
- assert_equal(
66
- ["test"],
67
- visit(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
68
- )
69
- end
70
-
71
- def test_elsif_condition
72
- assert_equal(
73
- ["test"],
74
- visit(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
75
- )
76
- end
77
-
78
- def test_complex_elsif_condition
79
- assert_equal(
80
- ["test"],
81
- visit(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
82
- )
83
- end
84
-
85
- def test_elsif_body
86
- assert_equal(
87
- ["test"],
88
- visit(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
89
- )
90
- end
91
-
92
- def test_else_body
93
- assert_equal(
94
- ["test"],
95
- visit(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
96
- )
97
- end
98
-
99
- def test_case_left
100
- assert_equal(
101
- ["test"],
102
- visit(%({% case test %}{% endcase %}))
103
- )
104
- end
105
-
106
- def test_case_condition
107
- assert_equal(
108
- ["test"],
109
- visit(%({% case 1 %}{% when test %}{% endcase %}))
110
- )
111
- end
112
-
113
- def test_case_when_body
114
- assert_equal(
115
- ["test"],
116
- visit(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
117
- )
118
- end
119
-
120
- def test_case_else_body
121
- assert_equal(
122
- ["test"],
123
- visit(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
124
- )
125
- end
126
-
127
- def test_for_in
128
- assert_equal(
129
- ["test"],
130
- visit(%({% for x in test %}{% endfor %}))
131
- )
132
- end
133
-
134
- def test_for_limit
135
- assert_equal(
136
- ["test"],
137
- visit(%({% for x in (1..5) limit: test %}{% endfor %}))
138
- )
139
- end
140
-
141
- def test_for_offset
142
- assert_equal(
143
- ["test"],
144
- visit(%({% for x in (1..5) offset: test %}{% endfor %}))
145
- )
146
- end
147
-
148
- def test_for_body
149
- assert_equal(
150
- ["test"],
151
- visit(%({% for x in (1..5) %}{{ test }}{% endfor %}))
152
- )
153
- end
154
-
155
- def test_tablerow_in
156
- assert_equal(
157
- ["test"],
158
- visit(%({% tablerow x in test %}{% endtablerow %}))
159
- )
160
- end
161
-
162
- def test_tablerow_limit
163
- assert_equal(
164
- ["test"],
165
- visit(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
166
- )
167
- end
168
-
169
- def test_tablerow_offset
170
- assert_equal(
171
- ["test"],
172
- visit(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
173
- )
174
- end
175
-
176
- def test_tablerow_body
177
- assert_equal(
178
- ["test"],
179
- visit(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
180
- )
181
- end
182
-
183
- def test_cycle
184
- assert_equal(
185
- ["test"],
186
- visit(%({% cycle test %}))
187
- )
188
- end
189
-
190
- def test_assign
191
- assert_equal(
192
- ["test"],
193
- visit(%({% assign x = test %}))
194
- )
195
- end
196
-
197
- def test_capture
198
- assert_equal(
199
- ["test"],
200
- visit(%({% capture x %}{{ test }}{% endcapture %}))
201
- )
202
- end
203
-
204
- def test_include
205
- assert_equal(
206
- ["test"],
207
- visit(%({% include test %}))
208
- )
209
- end
210
-
211
- def test_include_with
212
- assert_equal(
213
- ["test"],
214
- visit(%({% include "hai" with test %}))
215
- )
216
- end
217
-
218
- def test_include_for
219
- assert_equal(
220
- ["test"],
221
- visit(%({% include "hai" for test %}))
222
- )
223
- end
224
-
225
- def test_preserve_tree_structure
226
- assert_equal(
227
- [[nil, [
228
- [nil, [[nil, [["other", []]]]]],
229
- ["test", []],
230
- ["xs", []]
231
- ]]],
232
- traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit
233
- )
234
- end
235
-
236
- private
237
-
238
- def traversal(template)
239
- ParseTreeVisitor
240
- .for(Template.parse(template).root)
241
- .add_callback_for(VariableLookup, &:name)
242
- end
243
-
244
- def visit(template)
245
- traversal(template).visit.flatten.compact
246
- end
247
- end
@@ -1,122 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ParsingQuirksTest < Minitest::Test
4
- include Liquid
5
-
6
- def test_parsing_css
7
- text = " div { font-weight: bold; } "
8
- assert_equal text, Template.parse(text).render!
9
- end
10
-
11
- def test_raise_on_single_close_bracet
12
- assert_raises(SyntaxError) do
13
- Template.parse("text {{method} oh nos!")
14
- end
15
- end
16
-
17
- def test_raise_on_label_and_no_close_bracets
18
- assert_raises(SyntaxError) do
19
- Template.parse("TEST {{ ")
20
- end
21
- end
22
-
23
- def test_raise_on_label_and_no_close_bracets_percent
24
- assert_raises(SyntaxError) do
25
- Template.parse("TEST {% ")
26
- end
27
- end
28
-
29
- def test_error_on_empty_filter
30
- assert Template.parse("{{test}}")
31
-
32
- with_error_mode(:lax) do
33
- assert Template.parse("{{|test}}")
34
- end
35
-
36
- with_error_mode(:strict) do
37
- assert_raises(SyntaxError) { Template.parse("{{|test}}") }
38
- assert_raises(SyntaxError) { Template.parse("{{test |a|b|}}") }
39
- end
40
- end
41
-
42
- def test_meaningless_parens_error
43
- with_error_mode(:strict) do
44
- assert_raises(SyntaxError) do
45
- markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
46
- Template.parse("{% if #{markup} %} YES {% endif %}")
47
- end
48
- end
49
- end
50
-
51
- def test_unexpected_characters_syntax_error
52
- with_error_mode(:strict) do
53
- assert_raises(SyntaxError) do
54
- markup = "true && false"
55
- Template.parse("{% if #{markup} %} YES {% endif %}")
56
- end
57
- assert_raises(SyntaxError) do
58
- markup = "false || true"
59
- Template.parse("{% if #{markup} %} YES {% endif %}")
60
- end
61
- end
62
- end
63
-
64
- def test_no_error_on_lax_empty_filter
65
- assert Template.parse("{{test |a|b|}}", error_mode: :lax)
66
- assert Template.parse("{{test}}", error_mode: :lax)
67
- assert Template.parse("{{|test|}}", error_mode: :lax)
68
- end
69
-
70
- def test_meaningless_parens_lax
71
- with_error_mode(:lax) do
72
- assigns = { 'b' => 'bar', 'c' => 'baz' }
73
- markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
74
- assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}", assigns)
75
- end
76
- end
77
-
78
- def test_unexpected_characters_silently_eat_logic_lax
79
- with_error_mode(:lax) do
80
- markup = "true && false"
81
- assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}")
82
- markup = "false || true"
83
- assert_template_result('', "{% if #{markup} %} YES {% endif %}")
84
- end
85
- end
86
-
87
- def test_raise_on_invalid_tag_delimiter
88
- assert_raises(Liquid::SyntaxError) do
89
- Template.new.parse('{% end %}')
90
- end
91
- end
92
-
93
- def test_unanchored_filter_arguments
94
- with_error_mode(:lax) do
95
- assert_template_result('hi', "{{ 'hi there' | split$$$:' ' | first }}")
96
-
97
- assert_template_result('x', "{{ 'X' | downcase) }}")
98
-
99
- # After the messed up quotes a filter without parameters (reverse) should work
100
- # but one with parameters (remove) shouldn't be detected.
101
- assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
102
- assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
103
- end
104
- end
105
-
106
- def test_invalid_variables_work
107
- with_error_mode(:lax) do
108
- assert_template_result('bar', "{% assign 123foo = 'bar' %}{{ 123foo }}")
109
- assert_template_result('123', "{% assign 123 = 'bar' %}{{ 123 }}")
110
- end
111
- end
112
-
113
- def test_extra_dots_in_ranges
114
- with_error_mode(:lax) do
115
- assert_template_result('12345', "{% for i in (1...5) %}{{ i }}{% endfor %}")
116
- end
117
- end
118
-
119
- def test_contains_in_id
120
- assert_template_result(' YES ', '{% if containsallshipments == true %} YES {% endif %}', 'containsallshipments' => true)
121
- end
122
- end # ParsingQuirksTest