liquid 4.0.3 → 5.0.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 +33 -0
  3. data/README.md +6 -0
  4. data/lib/liquid.rb +17 -5
  5. data/lib/liquid/block.rb +31 -14
  6. data/lib/liquid/block_body.rb +164 -54
  7. data/lib/liquid/condition.rb +39 -18
  8. data/lib/liquid/context.rb +106 -51
  9. data/lib/liquid/document.rb +47 -9
  10. data/lib/liquid/drop.rb +4 -2
  11. data/lib/liquid/errors.rb +20 -18
  12. data/lib/liquid/expression.rb +29 -34
  13. data/lib/liquid/extensions.rb +2 -0
  14. data/lib/liquid/file_system.rb +6 -4
  15. data/lib/liquid/forloop_drop.rb +11 -4
  16. data/lib/liquid/i18n.rb +5 -3
  17. data/lib/liquid/interrupts.rb +3 -1
  18. data/lib/liquid/lexer.rb +30 -23
  19. data/lib/liquid/locales/en.yml +3 -1
  20. data/lib/liquid/parse_context.rb +16 -4
  21. data/lib/liquid/parse_tree_visitor.rb +2 -2
  22. data/lib/liquid/parser.rb +30 -18
  23. data/lib/liquid/parser_switching.rb +17 -3
  24. data/lib/liquid/partial_cache.rb +24 -0
  25. data/lib/liquid/profiler.rb +67 -86
  26. data/lib/liquid/profiler/hooks.rb +26 -14
  27. data/lib/liquid/range_lookup.rb +5 -3
  28. data/lib/liquid/register.rb +6 -0
  29. data/lib/liquid/resource_limits.rb +47 -8
  30. data/lib/liquid/standardfilters.rb +63 -44
  31. data/lib/liquid/static_registers.rb +44 -0
  32. data/lib/liquid/strainer_factory.rb +36 -0
  33. data/lib/liquid/strainer_template.rb +53 -0
  34. data/lib/liquid/tablerowloop_drop.rb +6 -4
  35. data/lib/liquid/tag.rb +28 -6
  36. data/lib/liquid/tag/disableable.rb +22 -0
  37. data/lib/liquid/tag/disabler.rb +21 -0
  38. data/lib/liquid/tags/assign.rb +24 -10
  39. data/lib/liquid/tags/break.rb +8 -3
  40. data/lib/liquid/tags/capture.rb +11 -8
  41. data/lib/liquid/tags/case.rb +33 -27
  42. data/lib/liquid/tags/comment.rb +5 -3
  43. data/lib/liquid/tags/continue.rb +8 -3
  44. data/lib/liquid/tags/cycle.rb +25 -14
  45. data/lib/liquid/tags/decrement.rb +6 -3
  46. data/lib/liquid/tags/echo.rb +26 -0
  47. data/lib/liquid/tags/for.rb +68 -44
  48. data/lib/liquid/tags/if.rb +35 -23
  49. data/lib/liquid/tags/ifchanged.rb +11 -10
  50. data/lib/liquid/tags/include.rb +34 -47
  51. data/lib/liquid/tags/increment.rb +7 -3
  52. data/lib/liquid/tags/raw.rb +14 -11
  53. data/lib/liquid/tags/render.rb +84 -0
  54. data/lib/liquid/tags/table_row.rb +23 -19
  55. data/lib/liquid/tags/unless.rb +15 -15
  56. data/lib/liquid/template.rb +55 -71
  57. data/lib/liquid/template_factory.rb +9 -0
  58. data/lib/liquid/tokenizer.rb +17 -9
  59. data/lib/liquid/usage.rb +8 -0
  60. data/lib/liquid/utils.rb +5 -3
  61. data/lib/liquid/variable.rb +46 -41
  62. data/lib/liquid/variable_lookup.rb +8 -6
  63. data/lib/liquid/version.rb +2 -1
  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 +608 -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 +339 -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 +70 -54
  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 +118 -124
  97. data/test/integration/trim_mode_test.rb +78 -44
  98. data/test/integration/variable_test.rb +43 -32
  99. data/test/test_helper.rb +75 -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 +2 -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 +19 -17
  119. data/test/unit/variable_unit_test.rb +51 -49
  120. metadata +73 -47
  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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: liquid
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.3
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Lütke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-12 00:00:00.000000000 Z
11
+ date: 2021-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '11.3'
19
+ version: '13.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '11.3'
26
+ version: '13.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -70,14 +70,20 @@ files:
70
70
  - lib/liquid/parse_tree_visitor.rb
71
71
  - lib/liquid/parser.rb
72
72
  - lib/liquid/parser_switching.rb
73
+ - lib/liquid/partial_cache.rb
73
74
  - lib/liquid/profiler.rb
74
75
  - lib/liquid/profiler/hooks.rb
75
76
  - lib/liquid/range_lookup.rb
77
+ - lib/liquid/register.rb
76
78
  - lib/liquid/resource_limits.rb
77
79
  - lib/liquid/standardfilters.rb
78
- - lib/liquid/strainer.rb
80
+ - lib/liquid/static_registers.rb
81
+ - lib/liquid/strainer_factory.rb
82
+ - lib/liquid/strainer_template.rb
79
83
  - lib/liquid/tablerowloop_drop.rb
80
84
  - lib/liquid/tag.rb
85
+ - lib/liquid/tag/disableable.rb
86
+ - lib/liquid/tag/disabler.rb
81
87
  - lib/liquid/tags/assign.rb
82
88
  - lib/liquid/tags/break.rb
83
89
  - lib/liquid/tags/capture.rb
@@ -86,17 +92,20 @@ files:
86
92
  - lib/liquid/tags/continue.rb
87
93
  - lib/liquid/tags/cycle.rb
88
94
  - lib/liquid/tags/decrement.rb
95
+ - lib/liquid/tags/echo.rb
89
96
  - lib/liquid/tags/for.rb
90
97
  - lib/liquid/tags/if.rb
91
98
  - lib/liquid/tags/ifchanged.rb
92
99
  - lib/liquid/tags/include.rb
93
100
  - lib/liquid/tags/increment.rb
94
101
  - lib/liquid/tags/raw.rb
102
+ - lib/liquid/tags/render.rb
95
103
  - lib/liquid/tags/table_row.rb
96
104
  - lib/liquid/tags/unless.rb
97
105
  - lib/liquid/template.rb
106
+ - lib/liquid/template_factory.rb
98
107
  - lib/liquid/tokenizer.rb
99
- - lib/liquid/truffle.rb
108
+ - lib/liquid/usage.rb
100
109
  - lib/liquid/utils.rb
101
110
  - lib/liquid/variable.rb
102
111
  - lib/liquid/variable_lookup.rb
@@ -110,21 +119,26 @@ files:
110
119
  - test/integration/document_test.rb
111
120
  - test/integration/drop_test.rb
112
121
  - test/integration/error_handling_test.rb
122
+ - test/integration/expression_test.rb
113
123
  - test/integration/filter_test.rb
114
124
  - test/integration/hash_ordering_test.rb
115
125
  - test/integration/output_test.rb
116
- - test/integration/parse_tree_visitor_test.rb
117
126
  - test/integration/parsing_quirks_test.rb
118
- - test/integration/render_profiling_test.rb
127
+ - test/integration/profiler_test.rb
119
128
  - test/integration/security_test.rb
120
129
  - test/integration/standard_filter_test.rb
130
+ - test/integration/tag/disableable_test.rb
131
+ - test/integration/tag_test.rb
121
132
  - test/integration/tags/break_tag_test.rb
122
133
  - test/integration/tags/continue_tag_test.rb
134
+ - test/integration/tags/echo_test.rb
123
135
  - test/integration/tags/for_tag_test.rb
124
136
  - test/integration/tags/if_else_tag_test.rb
125
137
  - test/integration/tags/include_tag_test.rb
126
138
  - test/integration/tags/increment_tag_test.rb
139
+ - test/integration/tags/liquid_tag_test.rb
127
140
  - test/integration/tags/raw_tag_test.rb
141
+ - test/integration/tags/render_tag_test.rb
128
142
  - test/integration/tags/standard_tag_test.rb
129
143
  - test/integration/tags/statements_test.rb
130
144
  - test/integration/tags/table_row_test.rb
@@ -133,27 +147,31 @@ files:
133
147
  - test/integration/trim_mode_test.rb
134
148
  - test/integration/variable_test.rb
135
149
  - test/test_helper.rb
136
- - test/truffle/truffle_test.rb
137
150
  - test/unit/block_unit_test.rb
138
151
  - test/unit/condition_unit_test.rb
139
- - test/unit/context_unit_test.rb
140
152
  - test/unit/file_system_unit_test.rb
141
153
  - test/unit/i18n_unit_test.rb
142
154
  - test/unit/lexer_unit_test.rb
155
+ - test/unit/parse_tree_visitor_test.rb
143
156
  - test/unit/parser_unit_test.rb
157
+ - test/unit/partial_cache_unit_test.rb
144
158
  - test/unit/regexp_unit_test.rb
145
- - test/unit/strainer_unit_test.rb
159
+ - test/unit/static_registers_unit_test.rb
160
+ - test/unit/strainer_factory_unit_test.rb
161
+ - test/unit/strainer_template_unit_test.rb
146
162
  - test/unit/tag_unit_test.rb
147
163
  - test/unit/tags/case_tag_unit_test.rb
148
164
  - test/unit/tags/for_tag_unit_test.rb
149
165
  - test/unit/tags/if_tag_unit_test.rb
166
+ - test/unit/template_factory_unit_test.rb
150
167
  - test/unit/template_unit_test.rb
151
168
  - test/unit/tokenizer_unit_test.rb
152
169
  - test/unit/variable_unit_test.rb
153
170
  homepage: http://www.liquidmarkup.org
154
171
  licenses:
155
172
  - MIT
156
- metadata: {}
173
+ metadata:
174
+ allowed_push_host: https://rubygems.org
157
175
  post_install_message:
158
176
  rdoc_options: []
159
177
  require_paths:
@@ -162,64 +180,72 @@ required_ruby_version: !ruby/object:Gem::Requirement
162
180
  requirements:
163
181
  - - ">="
164
182
  - !ruby/object:Gem::Version
165
- version: 2.1.0
183
+ version: 2.5.0
166
184
  required_rubygems_version: !ruby/object:Gem::Requirement
167
185
  requirements:
168
186
  - - ">="
169
187
  - !ruby/object:Gem::Version
170
188
  version: 1.3.7
171
189
  requirements: []
172
- rubygems_version: 3.0.2
190
+ rubygems_version: 3.0.3
173
191
  signing_key:
174
192
  specification_version: 4
175
193
  summary: A secure, non-evaling end user template engine with aesthetic markup.
176
194
  test_files:
177
195
  - test/unit/lexer_unit_test.rb
196
+ - test/unit/condition_unit_test.rb
197
+ - test/unit/template_factory_unit_test.rb
198
+ - test/unit/tag_unit_test.rb
199
+ - test/unit/tokenizer_unit_test.rb
200
+ - test/unit/regexp_unit_test.rb
201
+ - test/unit/file_system_unit_test.rb
178
202
  - test/unit/block_unit_test.rb
203
+ - test/unit/strainer_factory_unit_test.rb
204
+ - test/unit/i18n_unit_test.rb
179
205
  - test/unit/variable_unit_test.rb
180
- - test/unit/parser_unit_test.rb
206
+ - test/unit/static_registers_unit_test.rb
207
+ - test/unit/strainer_template_unit_test.rb
208
+ - test/unit/template_unit_test.rb
209
+ - test/unit/partial_cache_unit_test.rb
210
+ - test/unit/parse_tree_visitor_test.rb
181
211
  - test/unit/tags/if_tag_unit_test.rb
182
212
  - test/unit/tags/case_tag_unit_test.rb
183
213
  - test/unit/tags/for_tag_unit_test.rb
184
- - test/unit/context_unit_test.rb
185
- - test/unit/tokenizer_unit_test.rb
186
- - test/unit/tag_unit_test.rb
187
- - test/unit/i18n_unit_test.rb
188
- - test/unit/template_unit_test.rb
189
- - test/unit/condition_unit_test.rb
190
- - test/unit/file_system_unit_test.rb
191
- - test/unit/regexp_unit_test.rb
192
- - test/unit/strainer_unit_test.rb
193
- - test/integration/output_test.rb
194
- - test/integration/hash_ordering_test.rb
195
- - test/integration/variable_test.rb
214
+ - test/unit/parser_unit_test.rb
215
+ - test/test_helper.rb
216
+ - test/integration/expression_test.rb
217
+ - test/integration/parsing_quirks_test.rb
218
+ - test/integration/security_test.rb
219
+ - test/integration/template_test.rb
220
+ - test/integration/filter_test.rb
221
+ - test/integration/drop_test.rb
196
222
  - test/integration/blank_test.rb
197
- - test/integration/parse_tree_visitor_test.rb
223
+ - test/integration/capture_test.rb
224
+ - test/integration/context_test.rb
225
+ - test/integration/document_test.rb
226
+ - test/integration/block_test.rb
227
+ - test/integration/tag_test.rb
228
+ - test/integration/tag/disableable_test.rb
229
+ - test/integration/standard_filter_test.rb
230
+ - test/integration/output_test.rb
198
231
  - test/integration/assign_test.rb
232
+ - test/integration/profiler_test.rb
199
233
  - test/integration/trim_mode_test.rb
200
- - test/integration/context_test.rb
201
- - test/integration/capture_test.rb
202
- - test/integration/tags/increment_tag_test.rb
234
+ - test/integration/error_handling_test.rb
235
+ - test/integration/tags/echo_test.rb
236
+ - test/integration/tags/raw_tag_test.rb
237
+ - test/integration/tags/statements_test.rb
203
238
  - test/integration/tags/for_tag_test.rb
204
239
  - test/integration/tags/standard_tag_test.rb
240
+ - test/integration/tags/render_tag_test.rb
205
241
  - test/integration/tags/table_row_test.rb
206
- - test/integration/tags/include_tag_test.rb
207
- - test/integration/tags/raw_tag_test.rb
208
- - test/integration/tags/statements_test.rb
242
+ - test/integration/tags/break_tag_test.rb
209
243
  - test/integration/tags/if_else_tag_test.rb
210
244
  - test/integration/tags/unless_else_tag_test.rb
211
245
  - test/integration/tags/continue_tag_test.rb
212
- - test/integration/tags/break_tag_test.rb
213
- - test/integration/block_test.rb
214
- - test/integration/standard_filter_test.rb
215
- - test/integration/drop_test.rb
216
- - test/integration/error_handling_test.rb
217
- - test/integration/template_test.rb
218
- - test/integration/document_test.rb
219
- - test/integration/security_test.rb
220
- - test/integration/render_profiling_test.rb
221
- - test/integration/parsing_quirks_test.rb
222
- - test/integration/filter_test.rb
223
- - test/truffle/truffle_test.rb
246
+ - test/integration/tags/include_tag_test.rb
247
+ - test/integration/tags/liquid_tag_test.rb
248
+ - test/integration/tags/increment_tag_test.rb
249
+ - test/integration/hash_ordering_test.rb
250
+ - test/integration/variable_test.rb
224
251
  - test/fixtures/en_locale.yml
225
- - test/test_helper.rb
@@ -1,66 +0,0 @@
1
- require 'set'
2
-
3
- module Liquid
4
- # Strainer is the parent class for the filters system.
5
- # New filters are mixed into the strainer class which is then instantiated for each liquid template render run.
6
- #
7
- # The Strainer only allows method calls defined in filters given to it via Strainer.global_filter,
8
- # Context#add_filters or Template.register_filter
9
- class Strainer #:nodoc:
10
- @@global_strainer = Class.new(Strainer) do
11
- @filter_methods = Set.new
12
- end
13
- @@strainer_class_cache = Hash.new do |hash, filters|
14
- hash[filters] = Class.new(@@global_strainer) do
15
- @filter_methods = @@global_strainer.filter_methods.dup
16
- filters.each { |f| add_filter(f) }
17
- end
18
- end
19
-
20
- def initialize(context)
21
- @context = context
22
- end
23
-
24
- class << self
25
- attr_reader :filter_methods
26
- end
27
-
28
- def self.add_filter(filter)
29
- raise ArgumentError, "Expected module but got: #{filter.class}" unless filter.is_a?(Module)
30
- unless self.include?(filter)
31
- invokable_non_public_methods = (filter.private_instance_methods + filter.protected_instance_methods).select { |m| invokable?(m) }
32
- if invokable_non_public_methods.any?
33
- raise MethodOverrideError, "Filter overrides registered public methods as non public: #{invokable_non_public_methods.join(', ')}"
34
- else
35
- send(:include, filter)
36
- @filter_methods.merge(filter.public_instance_methods.map(&:to_s))
37
- end
38
- end
39
- end
40
-
41
- def self.global_filter(filter)
42
- @@strainer_class_cache.clear
43
- @@global_strainer.add_filter(filter)
44
- end
45
-
46
- def self.invokable?(method)
47
- @filter_methods.include?(method.to_s)
48
- end
49
-
50
- def self.create(context, filters = [])
51
- @@strainer_class_cache[filters].new(context)
52
- end
53
-
54
- def invoke(method, *args)
55
- if self.class.invokable?(method)
56
- send(method, *args)
57
- elsif @context && @context.strict_filters
58
- raise Liquid::UndefinedFilter, "undefined filter #{method}"
59
- else
60
- args.first
61
- end
62
- rescue ::ArgumentError => e
63
- raise Liquid::ArgumentError, e.message, e.backtrace
64
- end
65
- end
66
- end
@@ -1,5 +0,0 @@
1
- module Liquid
2
- module Truffle
3
-
4
- end
5
- end
@@ -1,9 +0,0 @@
1
- require 'test_helper'
2
-
3
- class TruffleTest < Minitest::Test
4
- include Liquid
5
-
6
- def test_truffle_works
7
-
8
- end
9
- end
@@ -1,489 +0,0 @@
1
- require 'test_helper'
2
-
3
- class HundredCentes
4
- def to_liquid
5
- 100
6
- end
7
- end
8
-
9
- class CentsDrop < Liquid::Drop
10
- def amount
11
- HundredCentes.new
12
- end
13
-
14
- def non_zero?
15
- true
16
- end
17
- end
18
-
19
- class ContextSensitiveDrop < Liquid::Drop
20
- def test
21
- @context['test']
22
- end
23
- end
24
-
25
- class Category < Liquid::Drop
26
- attr_accessor :name
27
-
28
- def initialize(name)
29
- @name = name
30
- end
31
-
32
- def to_liquid
33
- CategoryDrop.new(self)
34
- end
35
- end
36
-
37
- class CategoryDrop
38
- attr_accessor :category, :context
39
- def initialize(category)
40
- @category = category
41
- end
42
- end
43
-
44
- class CounterDrop < Liquid::Drop
45
- def count
46
- @count ||= 0
47
- @count += 1
48
- end
49
- end
50
-
51
- class ArrayLike
52
- def fetch(index)
53
- end
54
-
55
- def [](index)
56
- @counts ||= []
57
- @counts[index] ||= 0
58
- @counts[index] += 1
59
- end
60
-
61
- def to_liquid
62
- self
63
- end
64
- end
65
-
66
- class ContextUnitTest < Minitest::Test
67
- include Liquid
68
-
69
- def setup
70
- @context = Liquid::Context.new
71
- end
72
-
73
- def test_variables
74
- @context['string'] = 'string'
75
- assert_equal 'string', @context['string']
76
-
77
- @context['num'] = 5
78
- assert_equal 5, @context['num']
79
-
80
- @context['time'] = Time.parse('2006-06-06 12:00:00')
81
- assert_equal Time.parse('2006-06-06 12:00:00'), @context['time']
82
-
83
- @context['date'] = Date.today
84
- assert_equal Date.today, @context['date']
85
-
86
- now = DateTime.now
87
- @context['datetime'] = now
88
- assert_equal now, @context['datetime']
89
-
90
- @context['bool'] = true
91
- assert_equal true, @context['bool']
92
-
93
- @context['bool'] = false
94
- assert_equal false, @context['bool']
95
-
96
- @context['nil'] = nil
97
- assert_nil @context['nil']
98
- assert_nil @context['nil']
99
- end
100
-
101
- def test_variables_not_existing
102
- assert_nil @context['does_not_exist']
103
- end
104
-
105
- def test_scoping
106
- @context.push
107
- @context.pop
108
-
109
- assert_raises(Liquid::ContextError) do
110
- @context.pop
111
- end
112
-
113
- assert_raises(Liquid::ContextError) do
114
- @context.push
115
- @context.pop
116
- @context.pop
117
- end
118
- end
119
-
120
- def test_length_query
121
- @context['numbers'] = [1, 2, 3, 4]
122
-
123
- assert_equal 4, @context['numbers.size']
124
-
125
- @context['numbers'] = { 1 => 1, 2 => 2, 3 => 3, 4 => 4 }
126
-
127
- assert_equal 4, @context['numbers.size']
128
-
129
- @context['numbers'] = { 1 => 1, 2 => 2, 3 => 3, 4 => 4, 'size' => 1000 }
130
-
131
- assert_equal 1000, @context['numbers.size']
132
- end
133
-
134
- def test_hyphenated_variable
135
- @context['oh-my'] = 'godz'
136
- assert_equal 'godz', @context['oh-my']
137
- end
138
-
139
- def test_add_filter
140
- filter = Module.new do
141
- def hi(output)
142
- output + ' hi!'
143
- end
144
- end
145
-
146
- context = Context.new
147
- context.add_filters(filter)
148
- assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
149
-
150
- context = Context.new
151
- assert_equal 'hi?', context.invoke(:hi, 'hi?')
152
-
153
- context.add_filters(filter)
154
- assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
155
- end
156
-
157
- def test_only_intended_filters_make_it_there
158
- filter = Module.new do
159
- def hi(output)
160
- output + ' hi!'
161
- end
162
- end
163
-
164
- context = Context.new
165
- assert_equal "Wookie", context.invoke("hi", "Wookie")
166
-
167
- context.add_filters(filter)
168
- assert_equal "Wookie hi!", context.invoke("hi", "Wookie")
169
- end
170
-
171
- def test_add_item_in_outer_scope
172
- @context['test'] = 'test'
173
- @context.push
174
- assert_equal 'test', @context['test']
175
- @context.pop
176
- assert_equal 'test', @context['test']
177
- end
178
-
179
- def test_add_item_in_inner_scope
180
- @context.push
181
- @context['test'] = 'test'
182
- assert_equal 'test', @context['test']
183
- @context.pop
184
- assert_nil @context['test']
185
- end
186
-
187
- def test_hierachical_data
188
- @context['hash'] = { "name" => 'tobi' }
189
- assert_equal 'tobi', @context['hash.name']
190
- assert_equal 'tobi', @context['hash["name"]']
191
- end
192
-
193
- def test_keywords
194
- assert_equal true, @context['true']
195
- assert_equal false, @context['false']
196
- end
197
-
198
- def test_digits
199
- assert_equal 100, @context['100']
200
- assert_equal 100.00, @context['100.00']
201
- end
202
-
203
- def test_strings
204
- assert_equal "hello!", @context['"hello!"']
205
- assert_equal "hello!", @context["'hello!'"]
206
- end
207
-
208
- def test_merge
209
- @context.merge({ "test" => "test" })
210
- assert_equal 'test', @context['test']
211
- @context.merge({ "test" => "newvalue", "foo" => "bar" })
212
- assert_equal 'newvalue', @context['test']
213
- assert_equal 'bar', @context['foo']
214
- end
215
-
216
- def test_array_notation
217
- @context['test'] = [1, 2, 3, 4, 5]
218
-
219
- assert_equal 1, @context['test[0]']
220
- assert_equal 2, @context['test[1]']
221
- assert_equal 3, @context['test[2]']
222
- assert_equal 4, @context['test[3]']
223
- assert_equal 5, @context['test[4]']
224
- end
225
-
226
- def test_recoursive_array_notation
227
- @context['test'] = { 'test' => [1, 2, 3, 4, 5] }
228
-
229
- assert_equal 1, @context['test.test[0]']
230
-
231
- @context['test'] = [{ 'test' => 'worked' }]
232
-
233
- assert_equal 'worked', @context['test[0].test']
234
- end
235
-
236
- def test_hash_to_array_transition
237
- @context['colors'] = {
238
- 'Blue' => ['003366', '336699', '6699CC', '99CCFF'],
239
- 'Green' => ['003300', '336633', '669966', '99CC99'],
240
- 'Yellow' => ['CC9900', 'FFCC00', 'FFFF99', 'FFFFCC'],
241
- 'Red' => ['660000', '993333', 'CC6666', 'FF9999']
242
- }
243
-
244
- assert_equal '003366', @context['colors.Blue[0]']
245
- assert_equal 'FF9999', @context['colors.Red[3]']
246
- end
247
-
248
- def test_try_first
249
- @context['test'] = [1, 2, 3, 4, 5]
250
-
251
- assert_equal 1, @context['test.first']
252
- assert_equal 5, @context['test.last']
253
-
254
- @context['test'] = { 'test' => [1, 2, 3, 4, 5] }
255
-
256
- assert_equal 1, @context['test.test.first']
257
- assert_equal 5, @context['test.test.last']
258
-
259
- @context['test'] = [1]
260
- assert_equal 1, @context['test.first']
261
- assert_equal 1, @context['test.last']
262
- end
263
-
264
- def test_access_hashes_with_hash_notation
265
- @context['products'] = { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
266
- @context['product'] = { 'variants' => [ { 'title' => 'draft151cm' }, { 'title' => 'element151cm' } ] }
267
-
268
- assert_equal 5, @context['products["count"]']
269
- assert_equal 'deepsnow', @context['products["tags"][0]']
270
- assert_equal 'deepsnow', @context['products["tags"].first']
271
- assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
272
- assert_equal 'element151cm', @context['product["variants"][1]["title"]']
273
- assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
274
- assert_equal 'element151cm', @context['product["variants"].last["title"]']
275
- end
276
-
277
- def test_access_variable_with_hash_notation
278
- @context['foo'] = 'baz'
279
- @context['bar'] = 'foo'
280
-
281
- assert_equal 'baz', @context['["foo"]']
282
- assert_equal 'baz', @context['[bar]']
283
- end
284
-
285
- def test_access_hashes_with_hash_access_variables
286
- @context['var'] = 'tags'
287
- @context['nested'] = { 'var' => 'tags' }
288
- @context['products'] = { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
289
-
290
- assert_equal 'deepsnow', @context['products[var].first']
291
- assert_equal 'freestyle', @context['products[nested.var].last']
292
- end
293
-
294
- def test_hash_notation_only_for_hash_access
295
- @context['array'] = [1, 2, 3, 4, 5]
296
- @context['hash'] = { 'first' => 'Hello' }
297
-
298
- assert_equal 1, @context['array.first']
299
- assert_nil @context['array["first"]']
300
- assert_equal 'Hello', @context['hash["first"]']
301
- end
302
-
303
- def test_first_can_appear_in_middle_of_callchain
304
- @context['product'] = { 'variants' => [ { 'title' => 'draft151cm' }, { 'title' => 'element151cm' } ] }
305
-
306
- assert_equal 'draft151cm', @context['product.variants[0].title']
307
- assert_equal 'element151cm', @context['product.variants[1].title']
308
- assert_equal 'draft151cm', @context['product.variants.first.title']
309
- assert_equal 'element151cm', @context['product.variants.last.title']
310
- end
311
-
312
- def test_cents
313
- @context.merge("cents" => HundredCentes.new)
314
- assert_equal 100, @context['cents']
315
- end
316
-
317
- def test_nested_cents
318
- @context.merge("cents" => { 'amount' => HundredCentes.new })
319
- assert_equal 100, @context['cents.amount']
320
-
321
- @context.merge("cents" => { 'cents' => { 'amount' => HundredCentes.new } })
322
- assert_equal 100, @context['cents.cents.amount']
323
- end
324
-
325
- def test_cents_through_drop
326
- @context.merge("cents" => CentsDrop.new)
327
- assert_equal 100, @context['cents.amount']
328
- end
329
-
330
- def test_nested_cents_through_drop
331
- @context.merge("vars" => { "cents" => CentsDrop.new })
332
- assert_equal 100, @context['vars.cents.amount']
333
- end
334
-
335
- def test_drop_methods_with_question_marks
336
- @context.merge("cents" => CentsDrop.new)
337
- assert @context['cents.non_zero?']
338
- end
339
-
340
- def test_context_from_within_drop
341
- @context.merge("test" => '123', "vars" => ContextSensitiveDrop.new)
342
- assert_equal '123', @context['vars.test']
343
- end
344
-
345
- def test_nested_context_from_within_drop
346
- @context.merge("test" => '123', "vars" => { "local" => ContextSensitiveDrop.new })
347
- assert_equal '123', @context['vars.local.test']
348
- end
349
-
350
- def test_ranges
351
- @context.merge("test" => '5')
352
- assert_equal (1..5), @context['(1..5)']
353
- assert_equal (1..5), @context['(1..test)']
354
- assert_equal (5..5), @context['(test..test)']
355
- end
356
-
357
- def test_cents_through_drop_nestedly
358
- @context.merge("cents" => { "cents" => CentsDrop.new })
359
- assert_equal 100, @context['cents.cents.amount']
360
-
361
- @context.merge("cents" => { "cents" => { "cents" => CentsDrop.new } })
362
- assert_equal 100, @context['cents.cents.cents.amount']
363
- end
364
-
365
- def test_drop_with_variable_called_only_once
366
- @context['counter'] = CounterDrop.new
367
-
368
- assert_equal 1, @context['counter.count']
369
- assert_equal 2, @context['counter.count']
370
- assert_equal 3, @context['counter.count']
371
- end
372
-
373
- def test_drop_with_key_called_only_once
374
- @context['counter'] = CounterDrop.new
375
-
376
- assert_equal 1, @context['counter["count"]']
377
- assert_equal 2, @context['counter["count"]']
378
- assert_equal 3, @context['counter["count"]']
379
- end
380
-
381
- def test_proc_as_variable
382
- @context['dynamic'] = proc { 'Hello' }
383
-
384
- assert_equal 'Hello', @context['dynamic']
385
- end
386
-
387
- def test_lambda_as_variable
388
- @context['dynamic'] = proc { 'Hello' }
389
-
390
- assert_equal 'Hello', @context['dynamic']
391
- end
392
-
393
- def test_nested_lambda_as_variable
394
- @context['dynamic'] = { "lambda" => proc { 'Hello' } }
395
-
396
- assert_equal 'Hello', @context['dynamic.lambda']
397
- end
398
-
399
- def test_array_containing_lambda_as_variable
400
- @context['dynamic'] = [1, 2, proc { 'Hello' }, 4, 5]
401
-
402
- assert_equal 'Hello', @context['dynamic[2]']
403
- end
404
-
405
- def test_lambda_is_called_once
406
- @context['callcount'] = proc { @global ||= 0; @global += 1; @global.to_s }
407
-
408
- assert_equal '1', @context['callcount']
409
- assert_equal '1', @context['callcount']
410
- assert_equal '1', @context['callcount']
411
-
412
- @global = nil
413
- end
414
-
415
- def test_nested_lambda_is_called_once
416
- @context['callcount'] = { "lambda" => proc { @global ||= 0; @global += 1; @global.to_s } }
417
-
418
- assert_equal '1', @context['callcount.lambda']
419
- assert_equal '1', @context['callcount.lambda']
420
- assert_equal '1', @context['callcount.lambda']
421
-
422
- @global = nil
423
- end
424
-
425
- def test_lambda_in_array_is_called_once
426
- @context['callcount'] = [1, 2, proc { @global ||= 0; @global += 1; @global.to_s }, 4, 5]
427
-
428
- assert_equal '1', @context['callcount[2]']
429
- assert_equal '1', @context['callcount[2]']
430
- assert_equal '1', @context['callcount[2]']
431
-
432
- @global = nil
433
- end
434
-
435
- def test_access_to_context_from_proc
436
- @context.registers[:magic] = 345392
437
-
438
- @context['magic'] = proc { @context.registers[:magic] }
439
-
440
- assert_equal 345392, @context['magic']
441
- end
442
-
443
- def test_to_liquid_and_context_at_first_level
444
- @context['category'] = Category.new("foobar")
445
- assert_kind_of CategoryDrop, @context['category']
446
- assert_equal @context, @context['category'].context
447
- end
448
-
449
- def test_interrupt_avoids_object_allocations
450
- assert_no_object_allocations do
451
- @context.interrupt?
452
- end
453
- end
454
-
455
- def test_context_initialization_with_a_proc_in_environment
456
- contx = Context.new([test: ->(c) { c['poutine'] }], { test: :foo })
457
-
458
- assert contx
459
- assert_nil contx['poutine']
460
- end
461
-
462
- def test_apply_global_filter
463
- global_filter_proc = ->(output) { "#{output} filtered" }
464
-
465
- context = Context.new
466
- context.global_filter = global_filter_proc
467
-
468
- assert_equal 'hi filtered', context.apply_global_filter('hi')
469
- end
470
-
471
- def test_apply_global_filter_when_no_global_filter_exist
472
- context = Context.new
473
- assert_equal 'hi', context.apply_global_filter('hi')
474
- end
475
-
476
- private
477
-
478
- def assert_no_object_allocations
479
- unless RUBY_ENGINE == 'ruby'
480
- skip "stackprof needed to count object allocations"
481
- end
482
- require 'stackprof'
483
-
484
- profile = StackProf.run(mode: :object) do
485
- yield
486
- end
487
- assert_equal 0, profile[:samples]
488
- end
489
- end # ContextTest