liquid 4.0.3 → 5.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +89 -0
- data/README.md +10 -4
- data/lib/liquid/block.rb +31 -14
- data/lib/liquid/block_body.rb +169 -57
- data/lib/liquid/condition.rb +48 -21
- data/lib/liquid/context.rb +111 -52
- data/lib/liquid/document.rb +47 -9
- data/lib/liquid/drop.rb +4 -2
- data/lib/liquid/errors.rb +20 -18
- data/lib/liquid/expression.rb +28 -32
- data/lib/liquid/extensions.rb +2 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +54 -4
- data/lib/liquid/i18n.rb +5 -3
- data/lib/liquid/interrupts.rb +3 -1
- data/lib/liquid/lexer.rb +30 -23
- data/lib/liquid/locales/en.yml +8 -5
- data/lib/liquid/parse_context.rb +20 -4
- data/lib/liquid/parse_tree_visitor.rb +2 -2
- data/lib/liquid/parser.rb +30 -18
- data/lib/liquid/parser_switching.rb +17 -3
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/profiler.rb +67 -86
- data/lib/liquid/range_lookup.rb +13 -3
- data/lib/liquid/registers.rb +51 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/standardfilters.rb +551 -114
- data/lib/liquid/strainer_factory.rb +41 -0
- data/lib/liquid/strainer_template.rb +62 -0
- data/lib/liquid/tablerowloop_drop.rb +64 -5
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tag.rb +28 -6
- data/lib/liquid/tags/assign.rb +36 -18
- data/lib/liquid/tags/break.rb +16 -3
- data/lib/liquid/tags/capture.rb +24 -18
- data/lib/liquid/tags/case.rb +61 -27
- data/lib/liquid/tags/comment.rb +18 -3
- data/lib/liquid/tags/continue.rb +16 -12
- data/lib/liquid/tags/cycle.rb +37 -25
- data/lib/liquid/tags/decrement.rb +22 -20
- data/lib/liquid/tags/echo.rb +41 -0
- data/lib/liquid/tags/for.rb +90 -87
- data/lib/liquid/tags/if.rb +50 -32
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +49 -60
- data/lib/liquid/tags/increment.rb +23 -17
- data/lib/liquid/tags/inline_comment.rb +43 -0
- data/lib/liquid/tags/raw.rb +25 -11
- data/lib/liquid/tags/render.rb +109 -0
- data/lib/liquid/tags/table_row.rb +45 -19
- data/lib/liquid/tags/unless.rb +38 -19
- data/lib/liquid/template.rb +52 -72
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +18 -10
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +13 -3
- data/lib/liquid/variable.rb +49 -44
- data/lib/liquid/variable_lookup.rb +18 -10
- data/lib/liquid/version.rb +2 -1
- data/lib/liquid.rb +18 -6
- metadata +20 -108
- data/lib/liquid/strainer.rb +0 -66
- data/lib/liquid/truffle.rb +0 -5
- data/test/fixtures/en_locale.yml +0 -9
- data/test/integration/assign_test.rb +0 -48
- data/test/integration/blank_test.rb +0 -106
- data/test/integration/block_test.rb +0 -12
- data/test/integration/capture_test.rb +0 -50
- data/test/integration/context_test.rb +0 -32
- data/test/integration/document_test.rb +0 -19
- data/test/integration/drop_test.rb +0 -273
- data/test/integration/error_handling_test.rb +0 -260
- data/test/integration/filter_test.rb +0 -178
- data/test/integration/hash_ordering_test.rb +0 -23
- data/test/integration/output_test.rb +0 -123
- data/test/integration/parse_tree_visitor_test.rb +0 -247
- data/test/integration/parsing_quirks_test.rb +0 -122
- data/test/integration/render_profiling_test.rb +0 -154
- data/test/integration/security_test.rb +0 -80
- data/test/integration/standard_filter_test.rb +0 -776
- data/test/integration/tags/break_tag_test.rb +0 -15
- data/test/integration/tags/continue_tag_test.rb +0 -15
- data/test/integration/tags/for_tag_test.rb +0 -410
- data/test/integration/tags/if_else_tag_test.rb +0 -188
- data/test/integration/tags/include_tag_test.rb +0 -253
- data/test/integration/tags/increment_tag_test.rb +0 -23
- data/test/integration/tags/raw_tag_test.rb +0 -31
- data/test/integration/tags/standard_tag_test.rb +0 -296
- data/test/integration/tags/statements_test.rb +0 -111
- data/test/integration/tags/table_row_test.rb +0 -64
- data/test/integration/tags/unless_else_tag_test.rb +0 -26
- data/test/integration/template_test.rb +0 -332
- data/test/integration/trim_mode_test.rb +0 -529
- data/test/integration/variable_test.rb +0 -96
- data/test/test_helper.rb +0 -116
- data/test/truffle/truffle_test.rb +0 -9
- data/test/unit/block_unit_test.rb +0 -58
- data/test/unit/condition_unit_test.rb +0 -166
- data/test/unit/context_unit_test.rb +0 -489
- data/test/unit/file_system_unit_test.rb +0 -35
- data/test/unit/i18n_unit_test.rb +0 -37
- data/test/unit/lexer_unit_test.rb +0 -51
- data/test/unit/parser_unit_test.rb +0 -82
- data/test/unit/regexp_unit_test.rb +0 -44
- data/test/unit/strainer_unit_test.rb +0 -164
- data/test/unit/tag_unit_test.rb +0 -21
- data/test/unit/tags/case_tag_unit_test.rb +0 -10
- data/test/unit/tags/for_tag_unit_test.rb +0 -13
- data/test/unit/tags/if_tag_unit_test.rb +0 -8
- data/test/unit/template_unit_test.rb +0 -78
- data/test/unit/tokenizer_unit_test.rb +0 -55
- data/test/unit/variable_unit_test.rb +0 -162
data/test/test_helper.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
ENV["MT_NO_EXPECTATIONS"] = "1"
|
4
|
-
require 'minitest/autorun'
|
5
|
-
|
6
|
-
$LOAD_PATH.unshift(File.join(File.expand_path(__dir__), '..', 'lib'))
|
7
|
-
require 'liquid.rb'
|
8
|
-
require 'liquid/profiler'
|
9
|
-
|
10
|
-
mode = :strict
|
11
|
-
if env_mode = ENV['LIQUID_PARSER_MODE']
|
12
|
-
puts "-- #{env_mode.upcase} ERROR MODE"
|
13
|
-
mode = env_mode.to_sym
|
14
|
-
end
|
15
|
-
Liquid::Template.error_mode = mode
|
16
|
-
|
17
|
-
if ENV['LIQUID-C'] == '1'
|
18
|
-
puts "-- LIQUID C"
|
19
|
-
require 'liquid/c'
|
20
|
-
end
|
21
|
-
|
22
|
-
if Minitest.const_defined?('Test')
|
23
|
-
# We're on Minitest 5+. Nothing to do here.
|
24
|
-
else
|
25
|
-
# Minitest 4 doesn't have Minitest::Test yet.
|
26
|
-
Minitest::Test = MiniTest::Unit::TestCase
|
27
|
-
end
|
28
|
-
|
29
|
-
module Minitest
|
30
|
-
class Test
|
31
|
-
def fixture(name)
|
32
|
-
File.join(File.expand_path(__dir__), "fixtures", name)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
module Assertions
|
37
|
-
include Liquid
|
38
|
-
|
39
|
-
def assert_template_result(expected, template, assigns = {}, message = nil)
|
40
|
-
assert_equal expected, Template.parse(template).render!(assigns), message
|
41
|
-
end
|
42
|
-
|
43
|
-
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
|
-
|
46
|
-
assert_match expected, Template.parse(template).render!(assigns), message
|
47
|
-
end
|
48
|
-
|
49
|
-
def assert_match_syntax_error(match, template, assigns = {})
|
50
|
-
exception = assert_raises(Liquid::SyntaxError) do
|
51
|
-
Template.parse(template).render(assigns)
|
52
|
-
end
|
53
|
-
assert_match match, exception.message
|
54
|
-
end
|
55
|
-
|
56
|
-
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
|
62
|
-
|
63
|
-
globals.each do |global|
|
64
|
-
Liquid::Template.register_filter(global)
|
65
|
-
end
|
66
|
-
yield
|
67
|
-
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
|
78
|
-
end
|
79
|
-
|
80
|
-
def with_error_mode(mode)
|
81
|
-
old_mode = Liquid::Template.error_mode
|
82
|
-
Liquid::Template.error_mode = mode
|
83
|
-
yield
|
84
|
-
ensure
|
85
|
-
Liquid::Template.error_mode = old_mode
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
class ThingWithToLiquid
|
91
|
-
def to_liquid
|
92
|
-
'foobar'
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
class ErrorDrop < Liquid::Drop
|
97
|
-
def standard_error
|
98
|
-
raise Liquid::StandardError, 'standard error'
|
99
|
-
end
|
100
|
-
|
101
|
-
def argument_error
|
102
|
-
raise Liquid::ArgumentError, 'argument error'
|
103
|
-
end
|
104
|
-
|
105
|
-
def syntax_error
|
106
|
-
raise Liquid::SyntaxError, 'syntax error'
|
107
|
-
end
|
108
|
-
|
109
|
-
def runtime_error
|
110
|
-
raise 'runtime error'
|
111
|
-
end
|
112
|
-
|
113
|
-
def exception
|
114
|
-
raise Exception, 'exception'
|
115
|
-
end
|
116
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class BlockUnitTest < Minitest::Test
|
4
|
-
include Liquid
|
5
|
-
|
6
|
-
def test_blankspace
|
7
|
-
template = Liquid::Template.parse(" ")
|
8
|
-
assert_equal [" "], template.root.nodelist
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_variable_beginning
|
12
|
-
template = Liquid::Template.parse("{{funk}} ")
|
13
|
-
assert_equal 2, template.root.nodelist.size
|
14
|
-
assert_equal Variable, template.root.nodelist[0].class
|
15
|
-
assert_equal String, template.root.nodelist[1].class
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_variable_end
|
19
|
-
template = Liquid::Template.parse(" {{funk}}")
|
20
|
-
assert_equal 2, template.root.nodelist.size
|
21
|
-
assert_equal String, template.root.nodelist[0].class
|
22
|
-
assert_equal Variable, template.root.nodelist[1].class
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_variable_middle
|
26
|
-
template = Liquid::Template.parse(" {{funk}} ")
|
27
|
-
assert_equal 3, template.root.nodelist.size
|
28
|
-
assert_equal String, template.root.nodelist[0].class
|
29
|
-
assert_equal Variable, template.root.nodelist[1].class
|
30
|
-
assert_equal String, template.root.nodelist[2].class
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_variable_many_embedded_fragments
|
34
|
-
template = Liquid::Template.parse(" {{funk}} {{so}} {{brother}} ")
|
35
|
-
assert_equal 7, template.root.nodelist.size
|
36
|
-
assert_equal [String, Variable, String, Variable, String, Variable, String],
|
37
|
-
block_types(template.root.nodelist)
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_with_block
|
41
|
-
template = Liquid::Template.parse(" {% comment %} {% endcomment %} ")
|
42
|
-
assert_equal [String, Comment, String], block_types(template.root.nodelist)
|
43
|
-
assert_equal 3, template.root.nodelist.size
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_with_custom_tag
|
47
|
-
Liquid::Template.register_tag("testtag", Block)
|
48
|
-
assert Liquid::Template.parse("{% testtag %} {% endtesttag %}")
|
49
|
-
ensure
|
50
|
-
Liquid::Template.tags.delete('testtag')
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
def block_types(nodelist)
|
56
|
-
nodelist.collect(&:class)
|
57
|
-
end
|
58
|
-
end # VariableTest
|
@@ -1,166 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class ConditionUnitTest < Minitest::Test
|
4
|
-
include Liquid
|
5
|
-
|
6
|
-
def setup
|
7
|
-
@context = Liquid::Context.new
|
8
|
-
end
|
9
|
-
|
10
|
-
def test_basic_condition
|
11
|
-
assert_equal false, Condition.new(1, '==', 2).evaluate
|
12
|
-
assert_equal true, Condition.new(1, '==', 1).evaluate
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_default_operators_evalute_true
|
16
|
-
assert_evaluates_true 1, '==', 1
|
17
|
-
assert_evaluates_true 1, '!=', 2
|
18
|
-
assert_evaluates_true 1, '<>', 2
|
19
|
-
assert_evaluates_true 1, '<', 2
|
20
|
-
assert_evaluates_true 2, '>', 1
|
21
|
-
assert_evaluates_true 1, '>=', 1
|
22
|
-
assert_evaluates_true 2, '>=', 1
|
23
|
-
assert_evaluates_true 1, '<=', 2
|
24
|
-
assert_evaluates_true 1, '<=', 1
|
25
|
-
# negative numbers
|
26
|
-
assert_evaluates_true 1, '>', -1
|
27
|
-
assert_evaluates_true -1, '<', 1
|
28
|
-
assert_evaluates_true 1.0, '>', -1.0
|
29
|
-
assert_evaluates_true -1.0, '<', 1.0
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_default_operators_evalute_false
|
33
|
-
assert_evaluates_false 1, '==', 2
|
34
|
-
assert_evaluates_false 1, '!=', 1
|
35
|
-
assert_evaluates_false 1, '<>', 1
|
36
|
-
assert_evaluates_false 1, '<', 0
|
37
|
-
assert_evaluates_false 2, '>', 4
|
38
|
-
assert_evaluates_false 1, '>=', 3
|
39
|
-
assert_evaluates_false 2, '>=', 4
|
40
|
-
assert_evaluates_false 1, '<=', 0
|
41
|
-
assert_evaluates_false 1, '<=', 0
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_contains_works_on_strings
|
45
|
-
assert_evaluates_true 'bob', 'contains', 'o'
|
46
|
-
assert_evaluates_true 'bob', 'contains', 'b'
|
47
|
-
assert_evaluates_true 'bob', 'contains', 'bo'
|
48
|
-
assert_evaluates_true 'bob', 'contains', 'ob'
|
49
|
-
assert_evaluates_true 'bob', 'contains', 'bob'
|
50
|
-
|
51
|
-
assert_evaluates_false 'bob', 'contains', 'bob2'
|
52
|
-
assert_evaluates_false 'bob', 'contains', 'a'
|
53
|
-
assert_evaluates_false 'bob', 'contains', '---'
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_invalid_comparation_operator
|
57
|
-
assert_evaluates_argument_error 1, '~~', 0
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_comparation_of_int_and_str
|
61
|
-
assert_evaluates_argument_error '1', '>', 0
|
62
|
-
assert_evaluates_argument_error '1', '<', 0
|
63
|
-
assert_evaluates_argument_error '1', '>=', 0
|
64
|
-
assert_evaluates_argument_error '1', '<=', 0
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_hash_compare_backwards_compatibility
|
68
|
-
assert_nil Condition.new({}, '>', 2).evaluate
|
69
|
-
assert_nil Condition.new(2, '>', {}).evaluate
|
70
|
-
assert_equal false, Condition.new({}, '==', 2).evaluate
|
71
|
-
assert_equal true, Condition.new({ 'a' => 1 }, '==', { 'a' => 1 }).evaluate
|
72
|
-
assert_equal true, Condition.new({ 'a' => 2 }, 'contains', 'a').evaluate
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_contains_works_on_arrays
|
76
|
-
@context = Liquid::Context.new
|
77
|
-
@context['array'] = [1, 2, 3, 4, 5]
|
78
|
-
array_expr = VariableLookup.new("array")
|
79
|
-
|
80
|
-
assert_evaluates_false array_expr, 'contains', 0
|
81
|
-
assert_evaluates_true array_expr, 'contains', 1
|
82
|
-
assert_evaluates_true array_expr, 'contains', 2
|
83
|
-
assert_evaluates_true array_expr, 'contains', 3
|
84
|
-
assert_evaluates_true array_expr, 'contains', 4
|
85
|
-
assert_evaluates_true array_expr, 'contains', 5
|
86
|
-
assert_evaluates_false array_expr, 'contains', 6
|
87
|
-
assert_evaluates_false array_expr, 'contains', "1"
|
88
|
-
end
|
89
|
-
|
90
|
-
def test_contains_returns_false_for_nil_operands
|
91
|
-
@context = Liquid::Context.new
|
92
|
-
assert_evaluates_false VariableLookup.new('not_assigned'), 'contains', '0'
|
93
|
-
assert_evaluates_false 0, 'contains', VariableLookup.new('not_assigned')
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_contains_return_false_on_wrong_data_type
|
97
|
-
assert_evaluates_false 1, 'contains', 0
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_contains_with_string_left_operand_coerces_right_operand_to_string
|
101
|
-
assert_evaluates_true ' 1 ', 'contains', 1
|
102
|
-
assert_evaluates_false ' 1 ', 'contains', 2
|
103
|
-
end
|
104
|
-
|
105
|
-
def test_or_condition
|
106
|
-
condition = Condition.new(1, '==', 2)
|
107
|
-
|
108
|
-
assert_equal false, condition.evaluate
|
109
|
-
|
110
|
-
condition.or Condition.new(2, '==', 1)
|
111
|
-
|
112
|
-
assert_equal false, condition.evaluate
|
113
|
-
|
114
|
-
condition.or Condition.new(1, '==', 1)
|
115
|
-
|
116
|
-
assert_equal true, condition.evaluate
|
117
|
-
end
|
118
|
-
|
119
|
-
def test_and_condition
|
120
|
-
condition = Condition.new(1, '==', 1)
|
121
|
-
|
122
|
-
assert_equal true, condition.evaluate
|
123
|
-
|
124
|
-
condition.and Condition.new(2, '==', 2)
|
125
|
-
|
126
|
-
assert_equal true, condition.evaluate
|
127
|
-
|
128
|
-
condition.and Condition.new(2, '==', 1)
|
129
|
-
|
130
|
-
assert_equal false, condition.evaluate
|
131
|
-
end
|
132
|
-
|
133
|
-
def test_should_allow_custom_proc_operator
|
134
|
-
Condition.operators['starts_with'] = proc { |cond, left, right| left =~ %r{^#{right}} }
|
135
|
-
|
136
|
-
assert_evaluates_true 'bob', 'starts_with', 'b'
|
137
|
-
assert_evaluates_false 'bob', 'starts_with', 'o'
|
138
|
-
ensure
|
139
|
-
Condition.operators.delete 'starts_with'
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_left_or_right_may_contain_operators
|
143
|
-
@context = Liquid::Context.new
|
144
|
-
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
|
145
|
-
|
146
|
-
assert_evaluates_true VariableLookup.new("one"), '==', VariableLookup.new("another")
|
147
|
-
end
|
148
|
-
|
149
|
-
private
|
150
|
-
|
151
|
-
def assert_evaluates_true(left, op, right)
|
152
|
-
assert Condition.new(left, op, right).evaluate(@context),
|
153
|
-
"Evaluated false: #{left} #{op} #{right}"
|
154
|
-
end
|
155
|
-
|
156
|
-
def assert_evaluates_false(left, op, right)
|
157
|
-
assert !Condition.new(left, op, right).evaluate(@context),
|
158
|
-
"Evaluated true: #{left} #{op} #{right}"
|
159
|
-
end
|
160
|
-
|
161
|
-
def assert_evaluates_argument_error(left, op, right)
|
162
|
-
assert_raises(Liquid::ArgumentError) do
|
163
|
-
Condition.new(left, op, right).evaluate(@context)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end # ConditionTest
|