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