liquid 5.0.1 → 5.3.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.
- checksums.yaml +4 -4
- data/History.md +31 -0
- data/README.md +2 -2
- data/lib/liquid/block_body.rb +2 -2
- data/lib/liquid/condition.rb +10 -4
- data/lib/liquid/context.rb +1 -1
- data/lib/liquid/expression.rb +11 -10
- data/lib/liquid/range_lookup.rb +8 -0
- data/lib/liquid/standardfilters.rb +87 -20
- data/lib/liquid/static_registers.rb +5 -1
- data/lib/liquid/strainer_factory.rb +11 -10
- data/lib/liquid/strainer_template.rb +5 -0
- data/lib/liquid/tags/case.rb +8 -1
- data/lib/liquid/tags/if.rb +5 -1
- data/lib/liquid/tags/unless.rb +10 -2
- data/lib/liquid/tokenizer.rb +2 -2
- data/lib/liquid/utils.rb +8 -0
- data/lib/liquid/variable_lookup.rb +3 -0
- data/lib/liquid/version.rb +1 -1
- data/lib/liquid.rb +2 -2
- data/test/integration/context_test.rb +12 -14
- data/test/integration/filter_kwarg_test.rb +24 -0
- data/test/integration/profiler_test.rb +33 -6
- data/test/integration/standard_filter_test.rb +119 -32
- data/test/integration/template_test.rb +14 -0
- data/test/integration/variable_test.rb +31 -0
- data/test/test_helper.rb +48 -10
- data/test/unit/condition_unit_test.rb +27 -14
- data/test/unit/parse_tree_visitor_test.rb +7 -0
- data/test/unit/strainer_factory_unit_test.rb +2 -1
- data/test/unit/strainer_template_unit_test.rb +1 -1
- metadata +48 -46
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class FilterKwargTest < Minitest::Test
|
6
|
+
module KwargFilter
|
7
|
+
def html_tag(_tag, attributes)
|
8
|
+
attributes
|
9
|
+
.map { |key, value| "#{key}='#{value}'" }
|
10
|
+
.join(' ')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
include Liquid
|
15
|
+
|
16
|
+
def test_can_parse_data_kwargs
|
17
|
+
with_global_filter(KwargFilter) do
|
18
|
+
assert_equal(
|
19
|
+
"data-src='src' data-widths='100, 200'",
|
20
|
+
Template.parse("{{ 'img' | html_tag: data-src: 'src', data-widths: '100, 200' }}").render(nil, nil)
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -3,6 +3,27 @@
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
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
|
+
|
6
27
|
include Liquid
|
7
28
|
|
8
29
|
class ProfilingFileSystem
|
@@ -198,16 +219,22 @@ class ProfilerTest < Minitest::Test
|
|
198
219
|
|
199
220
|
def test_profiling_supports_self_time
|
200
221
|
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
201
|
-
|
202
|
-
|
222
|
+
collection = [
|
223
|
+
TestDrop.new("one"),
|
224
|
+
TestDrop.new("two"),
|
225
|
+
]
|
226
|
+
output = t.render!("collection" => collection)
|
227
|
+
assert_equal(" one two ", output)
|
203
228
|
|
204
|
-
|
229
|
+
leaf = t.profiler[0].children[0]
|
230
|
+
assert_operator(leaf.self_time, :>, 0.0)
|
205
231
|
end
|
206
232
|
|
207
233
|
def test_profiling_supports_total_time
|
208
|
-
t = Template.parse("{% if true %} {
|
209
|
-
t.render!
|
234
|
+
t = Template.parse("{% if true %} {{ test }} {% endif %}", profile: true)
|
235
|
+
output = t.render!("test" => TestDrop.new("one"))
|
236
|
+
assert_equal(" one ", output)
|
210
237
|
|
211
|
-
assert_operator(t.profiler[0].total_time, :>, 0)
|
238
|
+
assert_operator(t.profiler[0].total_time, :>, 0.0)
|
212
239
|
end
|
213
240
|
end
|
@@ -3,10 +3,6 @@
|
|
3
3
|
|
4
4
|
require 'test_helper'
|
5
5
|
|
6
|
-
class Filters
|
7
|
-
include Liquid::StandardFilters
|
8
|
-
end
|
9
|
-
|
10
6
|
class TestThing
|
11
7
|
attr_reader :foo
|
12
8
|
|
@@ -29,8 +25,24 @@ class TestThing
|
|
29
25
|
end
|
30
26
|
|
31
27
|
class TestDrop < Liquid::Drop
|
32
|
-
def
|
33
|
-
|
28
|
+
def initialize(value:)
|
29
|
+
@value = value
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :value
|
33
|
+
|
34
|
+
def registers
|
35
|
+
@context.registers
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class TestModel
|
40
|
+
def initialize(value:)
|
41
|
+
@value = value
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_liquid
|
45
|
+
TestDrop.new(value: @value)
|
34
46
|
end
|
35
47
|
end
|
36
48
|
|
@@ -53,10 +65,13 @@ class NumberLikeThing < Liquid::Drop
|
|
53
65
|
end
|
54
66
|
|
55
67
|
class StandardFiltersTest < Minitest::Test
|
68
|
+
Filters = Class.new(Liquid::StrainerTemplate)
|
69
|
+
Filters.add_filter(Liquid::StandardFilters)
|
70
|
+
|
56
71
|
include Liquid
|
57
72
|
|
58
73
|
def setup
|
59
|
-
@filters = Filters.new
|
74
|
+
@filters = Filters.new(Context.new)
|
60
75
|
end
|
61
76
|
|
62
77
|
def test_size
|
@@ -145,6 +160,40 @@ class StandardFiltersTest < Minitest::Test
|
|
145
160
|
assert_equal('<strong>Hulk</strong>', @filters.escape_once('<strong>Hulk</strong>'))
|
146
161
|
end
|
147
162
|
|
163
|
+
def test_base64_encode
|
164
|
+
assert_equal('b25lIHR3byB0aHJlZQ==', @filters.base64_encode('one two three'))
|
165
|
+
assert_equal('', @filters.base64_encode(nil))
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_base64_decode
|
169
|
+
assert_equal('one two three', @filters.base64_decode('b25lIHR3byB0aHJlZQ=='))
|
170
|
+
|
171
|
+
exception = assert_raises(Liquid::ArgumentError) do
|
172
|
+
@filters.base64_decode("invalidbase64")
|
173
|
+
end
|
174
|
+
|
175
|
+
assert_equal('Liquid error: invalid base64 provided to base64_decode', exception.message)
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_base64_url_safe_encode
|
179
|
+
assert_equal(
|
180
|
+
'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8',
|
181
|
+
@filters.base64_url_safe_encode('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|')
|
182
|
+
)
|
183
|
+
assert_equal('', @filters.base64_url_safe_encode(nil))
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_base64_url_safe_decode
|
187
|
+
assert_equal(
|
188
|
+
'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|',
|
189
|
+
@filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8')
|
190
|
+
)
|
191
|
+
exception = assert_raises(Liquid::ArgumentError) do
|
192
|
+
@filters.base64_url_safe_decode("invalidbase64")
|
193
|
+
end
|
194
|
+
assert_equal('Liquid error: invalid base64 provided to base64_url_safe_decode', exception.message)
|
195
|
+
end
|
196
|
+
|
148
197
|
def test_url_encode
|
149
198
|
assert_equal('foo%2B1%40example.com', @filters.url_encode('foo+1@example.com'))
|
150
199
|
assert_equal('1', @filters.url_encode(1))
|
@@ -178,6 +227,10 @@ class StandardFiltersTest < Minitest::Test
|
|
178
227
|
assert_equal('one two three...', @filters.truncatewords("one two\tthree\nfour", 3))
|
179
228
|
assert_equal('one two...', @filters.truncatewords("one two three four", 2))
|
180
229
|
assert_equal('one...', @filters.truncatewords("one two three four", 0))
|
230
|
+
exception = assert_raises(Liquid::ArgumentError) do
|
231
|
+
@filters.truncatewords("one two three four", 1 << 31)
|
232
|
+
end
|
233
|
+
assert_equal("Liquid error: integer #{1 << 31} too big for truncatewords", exception.message)
|
181
234
|
end
|
182
235
|
|
183
236
|
def test_strip_html
|
@@ -221,8 +274,8 @@ class StandardFiltersTest < Minitest::Test
|
|
221
274
|
{ "price" => 1, "handle" => "gamma" },
|
222
275
|
{ "price" => 2, "handle" => "epsilon" },
|
223
276
|
{ "price" => 4, "handle" => "alpha" },
|
224
|
-
{ "handle" => "delta" },
|
225
277
|
{ "handle" => "beta" },
|
278
|
+
{ "handle" => "delta" },
|
226
279
|
]
|
227
280
|
assert_equal(expectation, @filters.sort(input, "price"))
|
228
281
|
end
|
@@ -325,8 +378,9 @@ class StandardFiltersTest < Minitest::Test
|
|
325
378
|
assert_equal(["foo"], @filters.uniq("foo"))
|
326
379
|
assert_equal([1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1]))
|
327
380
|
assert_equal([{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a"))
|
328
|
-
|
329
|
-
|
381
|
+
test_drop = TestDrop.new(value: "test")
|
382
|
+
test_drop_alternate = TestDrop.new(value: "test")
|
383
|
+
assert_equal([test_drop], @filters.uniq([test_drop, test_drop_alternate], 'value'))
|
330
384
|
end
|
331
385
|
|
332
386
|
def test_uniq_empty_array
|
@@ -385,6 +439,16 @@ class StandardFiltersTest < Minitest::Test
|
|
385
439
|
assert_template_result("woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t])
|
386
440
|
end
|
387
441
|
|
442
|
+
def test_map_calls_context=
|
443
|
+
model = TestModel.new(value: "test")
|
444
|
+
|
445
|
+
template = Template.parse('{{ foo | map: "registers" }}')
|
446
|
+
template.registers[:test] = 1234
|
447
|
+
template.assigns['foo'] = [model]
|
448
|
+
|
449
|
+
assert_template_result("{:test=>1234}", template.render!)
|
450
|
+
end
|
451
|
+
|
388
452
|
def test_map_on_hashes
|
389
453
|
assert_template_result("4217", '{{ thing | map: "foo" | map: "bar" }}',
|
390
454
|
"thing" => { "foo" => [{ "bar" => 42 }, { "bar" => 17 }] })
|
@@ -403,9 +467,9 @@ class StandardFiltersTest < Minitest::Test
|
|
403
467
|
end
|
404
468
|
|
405
469
|
def test_map_over_proc
|
406
|
-
drop = TestDrop.new
|
470
|
+
drop = TestDrop.new(value: "testfoo")
|
407
471
|
p = proc { drop }
|
408
|
-
templ = '{{ procs | map: "
|
472
|
+
templ = '{{ procs | map: "value" }}'
|
409
473
|
assert_template_result("testfoo", templ, "procs" => [p])
|
410
474
|
end
|
411
475
|
|
@@ -501,19 +565,31 @@ class StandardFiltersTest < Minitest::Test
|
|
501
565
|
end
|
502
566
|
|
503
567
|
def test_replace
|
504
|
-
assert_equal('
|
568
|
+
assert_equal('b b b b', @filters.replace('a a a a', 'a', 'b'))
|
505
569
|
assert_equal('2 2 2 2', @filters.replace('1 1 1 1', 1, 2))
|
506
|
-
assert_equal('
|
570
|
+
assert_equal('1 1 1 1', @filters.replace('1 1 1 1', 2, 3))
|
571
|
+
assert_template_result('2 2 2 2', "{{ '1 1 1 1' | replace: '1', 2 }}")
|
572
|
+
|
573
|
+
assert_equal('b a a a', @filters.replace_first('a a a a', 'a', 'b'))
|
507
574
|
assert_equal('2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2))
|
575
|
+
assert_equal('1 1 1 1', @filters.replace_first('1 1 1 1', 2, 3))
|
508
576
|
assert_template_result('2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}")
|
577
|
+
|
578
|
+
assert_equal('a a a b', @filters.replace_last('a a a a', 'a', 'b'))
|
579
|
+
assert_equal('1 1 1 2', @filters.replace_last('1 1 1 1', 1, 2))
|
580
|
+
assert_equal('1 1 1 1', @filters.replace_last('1 1 1 1', 2, 3))
|
581
|
+
assert_template_result('1 1 1 2', "{{ '1 1 1 1' | replace_last: '1', 2 }}")
|
509
582
|
end
|
510
583
|
|
511
584
|
def test_remove
|
512
585
|
assert_equal(' ', @filters.remove("a a a a", 'a'))
|
513
|
-
|
514
|
-
|
515
|
-
assert_equal('
|
516
|
-
assert_template_result('
|
586
|
+
assert_template_result(' ', "{{ '1 1 1 1' | remove: 1 }}")
|
587
|
+
|
588
|
+
assert_equal('b a a', @filters.remove_first("a b a a", 'a '))
|
589
|
+
assert_template_result(' 1 1 1', "{{ '1 1 1 1' | remove_first: 1 }}")
|
590
|
+
|
591
|
+
assert_equal('a a b', @filters.remove_last("a a b a", ' a'))
|
592
|
+
assert_template_result('1 1 1 ', "{{ '1 1 1 1' | remove_last: 1 }}")
|
517
593
|
end
|
518
594
|
|
519
595
|
def test_pipes_in_string_arguments
|
@@ -690,6 +766,8 @@ class StandardFiltersTest < Minitest::Test
|
|
690
766
|
assert_equal("bar", @filters.default([], "bar"))
|
691
767
|
assert_equal("bar", @filters.default({}, "bar"))
|
692
768
|
assert_template_result('bar', "{{ false | default: 'bar' }}")
|
769
|
+
assert_template_result('bar', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(false))
|
770
|
+
assert_template_result('Yay', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(true))
|
693
771
|
end
|
694
772
|
|
695
773
|
def test_default_handle_false
|
@@ -700,6 +778,8 @@ class StandardFiltersTest < Minitest::Test
|
|
700
778
|
assert_equal("bar", @filters.default([], "bar", "allow_false" => true))
|
701
779
|
assert_equal("bar", @filters.default({}, "bar", "allow_false" => true))
|
702
780
|
assert_template_result('false', "{{ false | default: 'bar', allow_false: true }}")
|
781
|
+
assert_template_result('Nay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(false))
|
782
|
+
assert_template_result('Yay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(true))
|
703
783
|
end
|
704
784
|
|
705
785
|
def test_cannot_access_private_methods
|
@@ -728,6 +808,18 @@ class StandardFiltersTest < Minitest::Test
|
|
728
808
|
assert_equal(expectation, @filters.where(input, "ok"))
|
729
809
|
end
|
730
810
|
|
811
|
+
def test_where_string_keys
|
812
|
+
input = [
|
813
|
+
"alpha", "beta", "gamma", "delta"
|
814
|
+
]
|
815
|
+
|
816
|
+
expectation = [
|
817
|
+
"beta",
|
818
|
+
]
|
819
|
+
|
820
|
+
assert_equal(expectation, @filters.where(input, "be"))
|
821
|
+
end
|
822
|
+
|
731
823
|
def test_where_no_key_set
|
732
824
|
input = [
|
733
825
|
{ "handle" => "alpha", "ok" => true },
|
@@ -773,7 +865,7 @@ class StandardFiltersTest < Minitest::Test
|
|
773
865
|
end
|
774
866
|
|
775
867
|
def test_all_filters_never_raise_non_liquid_exception
|
776
|
-
test_drop = TestDrop.new
|
868
|
+
test_drop = TestDrop.new(value: "test")
|
777
869
|
test_drop.context = Context.new
|
778
870
|
test_enum = TestEnumerable.new
|
779
871
|
test_enum.context = Context.new
|
@@ -798,19 +890,14 @@ class StandardFiltersTest < Minitest::Test
|
|
798
890
|
{ 1 => "bar" },
|
799
891
|
["foo", 123, nil, true, false, Drop, ["foo"], { foo: "bar" }],
|
800
892
|
]
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
@filters.send(method, *inputs)
|
810
|
-
rescue Liquid::ArgumentError, Liquid::ZeroDivisionError
|
811
|
-
nil
|
812
|
-
end
|
813
|
-
end
|
893
|
+
StandardFilters.public_instance_methods(false).each do |method|
|
894
|
+
arg_count = @filters.method(method).arity
|
895
|
+
arg_count *= -1 if arg_count < 0
|
896
|
+
|
897
|
+
test_types.repeated_permutation(arg_count) do |args|
|
898
|
+
@filters.send(method, *args)
|
899
|
+
rescue Liquid::Error
|
900
|
+
nil
|
814
901
|
end
|
815
902
|
end
|
816
903
|
end
|
@@ -323,4 +323,18 @@ class TemplateTest < Minitest::Test
|
|
323
323
|
result = t.render('x' => 1, 'y' => 5)
|
324
324
|
assert_equal('12345', result)
|
325
325
|
end
|
326
|
+
|
327
|
+
def test_source_string_subclass
|
328
|
+
string_subclass = Class.new(String) do
|
329
|
+
# E.g. ActiveSupport::SafeBuffer does this, so don't just rely on to_s to return a String
|
330
|
+
def to_s
|
331
|
+
self
|
332
|
+
end
|
333
|
+
end
|
334
|
+
source = string_subclass.new("{% assign x = 2 -%} x= {{- x }}")
|
335
|
+
assert_instance_of(string_subclass, source)
|
336
|
+
output = Template.parse(source).render!
|
337
|
+
assert_equal("x=2", output)
|
338
|
+
assert_instance_of(String, output)
|
339
|
+
end
|
326
340
|
end
|
@@ -15,6 +15,33 @@ class VariableTest < Minitest::Test
|
|
15
15
|
assert_template_result('foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new)
|
16
16
|
end
|
17
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'))
|
43
|
+
end
|
44
|
+
|
18
45
|
def test_simple_with_whitespaces
|
19
46
|
template = Template.parse(%( {{ test }} ))
|
20
47
|
assert_equal(' worked ', template.render!('test' => 'worked'))
|
@@ -104,4 +131,8 @@ class VariableTest < Minitest::Test
|
|
104
131
|
def test_dynamic_find_var
|
105
132
|
assert_template_result('bar', '{{ [key] }}', 'key' => 'foo', 'foo' => 'bar')
|
106
133
|
end
|
134
|
+
|
135
|
+
def test_raw_value_variable
|
136
|
+
assert_template_result('bar', '{{ [key] }}', 'key' => 'foo', 'foo' => 'bar')
|
137
|
+
end
|
107
138
|
end
|
data/test/test_helper.rb
CHANGED
@@ -72,21 +72,21 @@ module Minitest
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def with_global_filter(*globals)
|
75
|
-
|
76
|
-
Liquid::StrainerFactory.
|
77
|
-
|
78
|
-
Liquid::StrainerFactory.add_global_filter(global)
|
79
|
-
end
|
80
|
-
|
81
|
-
Liquid::StrainerFactory.send(:strainer_class_cache).clear
|
75
|
+
original_global_cache = Liquid::StrainerFactory::GlobalCache
|
76
|
+
Liquid::StrainerFactory.send(:remove_const, :GlobalCache)
|
77
|
+
Liquid::StrainerFactory.const_set(:GlobalCache, Class.new(Liquid::StrainerTemplate))
|
82
78
|
|
83
79
|
globals.each do |global|
|
84
80
|
Liquid::Template.register_filter(global)
|
85
81
|
end
|
86
|
-
yield
|
87
|
-
ensure
|
88
82
|
Liquid::StrainerFactory.send(:strainer_class_cache).clear
|
89
|
-
|
83
|
+
begin
|
84
|
+
yield
|
85
|
+
ensure
|
86
|
+
Liquid::StrainerFactory.send(:remove_const, :GlobalCache)
|
87
|
+
Liquid::StrainerFactory.const_set(:GlobalCache, original_global_cache)
|
88
|
+
Liquid::StrainerFactory.send(:strainer_class_cache).clear
|
89
|
+
end
|
90
90
|
end
|
91
91
|
|
92
92
|
def with_error_mode(mode)
|
@@ -119,6 +119,44 @@ class ThingWithToLiquid
|
|
119
119
|
end
|
120
120
|
end
|
121
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
|
+
|
122
160
|
class ErrorDrop < Liquid::Drop
|
123
161
|
def standard_error
|
124
162
|
raise Liquid::StandardError, 'standard error'
|
@@ -10,8 +10,8 @@ class ConditionUnitTest < Minitest::Test
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_basic_condition
|
13
|
-
assert_equal(false, Condition.new(1, '==', 2).evaluate)
|
14
|
-
assert_equal(true, Condition.new(1, '==', 1).evaluate)
|
13
|
+
assert_equal(false, Condition.new(1, '==', 2).evaluate(Context.new))
|
14
|
+
assert_equal(true, Condition.new(1, '==', 1).evaluate(Context.new))
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_default_operators_evalute_true
|
@@ -67,11 +67,11 @@ class ConditionUnitTest < Minitest::Test
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def test_hash_compare_backwards_compatibility
|
70
|
-
assert_nil(Condition.new({}, '>', 2).evaluate)
|
71
|
-
assert_nil(Condition.new(2, '>', {}).evaluate)
|
72
|
-
assert_equal(false, Condition.new({}, '==', 2).evaluate)
|
73
|
-
assert_equal(true, Condition.new({ 'a' => 1 }, '==', 'a' => 1).evaluate)
|
74
|
-
assert_equal(true, Condition.new({ 'a' => 2 }, 'contains', 'a').evaluate)
|
70
|
+
assert_nil(Condition.new({}, '>', 2).evaluate(Context.new))
|
71
|
+
assert_nil(Condition.new(2, '>', {}).evaluate(Context.new))
|
72
|
+
assert_equal(false, Condition.new({}, '==', 2).evaluate(Context.new))
|
73
|
+
assert_equal(true, Condition.new({ 'a' => 1 }, '==', 'a' => 1).evaluate(Context.new))
|
74
|
+
assert_equal(true, Condition.new({ 'a' => 2 }, 'contains', 'a').evaluate(Context.new))
|
75
75
|
end
|
76
76
|
|
77
77
|
def test_contains_works_on_arrays
|
@@ -106,30 +106,29 @@ class ConditionUnitTest < Minitest::Test
|
|
106
106
|
|
107
107
|
def test_or_condition
|
108
108
|
condition = Condition.new(1, '==', 2)
|
109
|
-
|
110
|
-
assert_equal(false, condition.evaluate)
|
109
|
+
assert_equal(false, condition.evaluate(Context.new))
|
111
110
|
|
112
111
|
condition.or(Condition.new(2, '==', 1))
|
113
112
|
|
114
|
-
assert_equal(false, condition.evaluate)
|
113
|
+
assert_equal(false, condition.evaluate(Context.new))
|
115
114
|
|
116
115
|
condition.or(Condition.new(1, '==', 1))
|
117
116
|
|
118
|
-
assert_equal(true, condition.evaluate)
|
117
|
+
assert_equal(true, condition.evaluate(Context.new))
|
119
118
|
end
|
120
119
|
|
121
120
|
def test_and_condition
|
122
121
|
condition = Condition.new(1, '==', 1)
|
123
122
|
|
124
|
-
assert_equal(true, condition.evaluate)
|
123
|
+
assert_equal(true, condition.evaluate(Context.new))
|
125
124
|
|
126
125
|
condition.and(Condition.new(2, '==', 2))
|
127
126
|
|
128
|
-
assert_equal(true, condition.evaluate)
|
127
|
+
assert_equal(true, condition.evaluate(Context.new))
|
129
128
|
|
130
129
|
condition.and(Condition.new(2, '==', 1))
|
131
130
|
|
132
|
-
assert_equal(false, condition.evaluate)
|
131
|
+
assert_equal(false, condition.evaluate(Context.new))
|
133
132
|
end
|
134
133
|
|
135
134
|
def test_should_allow_custom_proc_operator
|
@@ -148,6 +147,20 @@ class ConditionUnitTest < Minitest::Test
|
|
148
147
|
assert_evaluates_true(VariableLookup.new("one"), '==', VariableLookup.new("another"))
|
149
148
|
end
|
150
149
|
|
150
|
+
def test_default_context_is_deprecated
|
151
|
+
if Gem::Version.new(Liquid::VERSION) >= Gem::Version.new('6.0.0')
|
152
|
+
flunk("Condition#evaluate without a context argument is to be removed")
|
153
|
+
end
|
154
|
+
|
155
|
+
_out, err = capture_io do
|
156
|
+
assert_equal(true, Condition.new(1, '==', 1).evaluate)
|
157
|
+
end
|
158
|
+
|
159
|
+
expected = "DEPRECATION WARNING: Condition#evaluate without a context argument is deprecated" \
|
160
|
+
" and will be removed from Liquid 6.0.0."
|
161
|
+
assert_includes(err.lines.map(&:strip), expected)
|
162
|
+
end
|
163
|
+
|
151
164
|
private
|
152
165
|
|
153
166
|
def assert_evaluates_true(left, op, right)
|
@@ -159,6 +159,13 @@ class ParseTreeVisitorTest < Minitest::Test
|
|
159
159
|
)
|
160
160
|
end
|
161
161
|
|
162
|
+
def test_for_range
|
163
|
+
assert_equal(
|
164
|
+
["test"],
|
165
|
+
visit(%({% for x in (1..test) %}{% endfor %}))
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
162
169
|
def test_tablerow_in
|
163
170
|
assert_equal(
|
164
171
|
["test"],
|
@@ -52,7 +52,8 @@ class StrainerFactoryUnitTest < Minitest::Test
|
|
52
52
|
/\ALiquid error: wrong number of arguments \((1 for 0|given 1, expected 0)\)\z/,
|
53
53
|
exception.message
|
54
54
|
)
|
55
|
-
|
55
|
+
source = AccessScopeFilters.instance_method(:public_filter).source_location
|
56
|
+
assert_equal(source.map(&:to_s), exception.backtrace[0].split(':')[0..1])
|
56
57
|
end
|
57
58
|
|
58
59
|
def test_strainer_only_invokes_public_filter_methods
|
@@ -57,8 +57,8 @@ class StrainerTemplateUnitTest < Minitest::Test
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def test_add_filter_does_not_raise_when_module_overrides_previously_registered_method
|
60
|
-
strainer = Context.new.strainer
|
61
60
|
with_global_filter do
|
61
|
+
strainer = Context.new.strainer
|
62
62
|
strainer.class.add_filter(PublicMethodOverrideFilter)
|
63
63
|
assert(strainer.class.send(:filter_methods).include?('public_filter'))
|
64
64
|
end
|