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.
- checksums.yaml +4 -4
- data/History.md +33 -0
- data/README.md +6 -0
- data/lib/liquid.rb +17 -5
- data/lib/liquid/block.rb +31 -14
- data/lib/liquid/block_body.rb +164 -54
- data/lib/liquid/condition.rb +39 -18
- data/lib/liquid/context.rb +106 -51
- 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 +29 -34
- data/lib/liquid/extensions.rb +2 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +11 -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 +3 -1
- data/lib/liquid/parse_context.rb +16 -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.rb +67 -86
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/range_lookup.rb +5 -3
- data/lib/liquid/register.rb +6 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/standardfilters.rb +63 -44
- data/lib/liquid/static_registers.rb +44 -0
- data/lib/liquid/strainer_factory.rb +36 -0
- data/lib/liquid/strainer_template.rb +53 -0
- data/lib/liquid/tablerowloop_drop.rb +6 -4
- data/lib/liquid/tag.rb +28 -6
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tags/assign.rb +24 -10
- data/lib/liquid/tags/break.rb +8 -3
- data/lib/liquid/tags/capture.rb +11 -8
- data/lib/liquid/tags/case.rb +33 -27
- data/lib/liquid/tags/comment.rb +5 -3
- data/lib/liquid/tags/continue.rb +8 -3
- data/lib/liquid/tags/cycle.rb +25 -14
- data/lib/liquid/tags/decrement.rb +6 -3
- data/lib/liquid/tags/echo.rb +26 -0
- data/lib/liquid/tags/for.rb +68 -44
- data/lib/liquid/tags/if.rb +35 -23
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +34 -47
- data/lib/liquid/tags/increment.rb +7 -3
- data/lib/liquid/tags/raw.rb +14 -11
- data/lib/liquid/tags/render.rb +84 -0
- data/lib/liquid/tags/table_row.rb +23 -19
- data/lib/liquid/tags/unless.rb +15 -15
- data/lib/liquid/template.rb +55 -71
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +17 -9
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +5 -3
- data/lib/liquid/variable.rb +46 -41
- data/lib/liquid/variable_lookup.rb +8 -6
- data/lib/liquid/version.rb +2 -1
- data/test/integration/assign_test.rb +74 -5
- data/test/integration/blank_test.rb +11 -8
- data/test/integration/block_test.rb +47 -1
- data/test/integration/capture_test.rb +18 -10
- data/test/integration/context_test.rb +608 -5
- data/test/integration/document_test.rb +4 -2
- data/test/integration/drop_test.rb +67 -83
- data/test/integration/error_handling_test.rb +73 -61
- data/test/integration/expression_test.rb +46 -0
- data/test/integration/filter_test.rb +53 -42
- data/test/integration/hash_ordering_test.rb +5 -3
- data/test/integration/output_test.rb +26 -24
- data/test/integration/parsing_quirks_test.rb +19 -7
- data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
- data/test/integration/security_test.rb +30 -21
- data/test/integration/standard_filter_test.rb +339 -281
- data/test/integration/tag/disableable_test.rb +59 -0
- data/test/integration/tag_test.rb +45 -0
- data/test/integration/tags/break_tag_test.rb +4 -2
- data/test/integration/tags/continue_tag_test.rb +4 -2
- data/test/integration/tags/echo_test.rb +13 -0
- data/test/integration/tags/for_tag_test.rb +107 -51
- data/test/integration/tags/if_else_tag_test.rb +5 -3
- data/test/integration/tags/include_tag_test.rb +70 -54
- data/test/integration/tags/increment_tag_test.rb +4 -2
- data/test/integration/tags/liquid_tag_test.rb +116 -0
- data/test/integration/tags/raw_tag_test.rb +14 -11
- data/test/integration/tags/render_tag_test.rb +213 -0
- data/test/integration/tags/standard_tag_test.rb +38 -31
- data/test/integration/tags/statements_test.rb +23 -21
- data/test/integration/tags/table_row_test.rb +2 -0
- data/test/integration/tags/unless_else_tag_test.rb +4 -2
- data/test/integration/template_test.rb +118 -124
- data/test/integration/trim_mode_test.rb +78 -44
- data/test/integration/variable_test.rb +43 -32
- data/test/test_helper.rb +75 -22
- data/test/unit/block_unit_test.rb +19 -24
- data/test/unit/condition_unit_test.rb +79 -77
- data/test/unit/file_system_unit_test.rb +6 -4
- data/test/unit/i18n_unit_test.rb +7 -5
- data/test/unit/lexer_unit_test.rb +11 -9
- data/test/{integration → unit}/parse_tree_visitor_test.rb +2 -2
- data/test/unit/parser_unit_test.rb +37 -35
- data/test/unit/partial_cache_unit_test.rb +128 -0
- data/test/unit/regexp_unit_test.rb +17 -15
- data/test/unit/static_registers_unit_test.rb +156 -0
- data/test/unit/strainer_factory_unit_test.rb +100 -0
- data/test/unit/strainer_template_unit_test.rb +82 -0
- data/test/unit/tag_unit_test.rb +5 -3
- data/test/unit/tags/case_tag_unit_test.rb +3 -1
- data/test/unit/tags/for_tag_unit_test.rb +4 -2
- data/test/unit/tags/if_tag_unit_test.rb +3 -1
- data/test/unit/template_factory_unit_test.rb +12 -0
- data/test/unit/template_unit_test.rb +19 -10
- data/test/unit/tokenizer_unit_test.rb +19 -17
- data/test/unit/variable_unit_test.rb +51 -49
- metadata +73 -47
- data/lib/liquid/strainer.rb +0 -66
- data/lib/liquid/truffle.rb +0 -5
- data/test/truffle/truffle_test.rb +0 -9
- data/test/unit/context_unit_test.rb +0 -489
- 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
|
+
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:
|
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: '
|
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: '
|
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/
|
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/
|
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/
|
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/
|
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.
|
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.
|
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/
|
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/
|
185
|
-
- test/
|
186
|
-
- test/
|
187
|
-
- test/
|
188
|
-
- test/
|
189
|
-
- test/
|
190
|
-
- test/
|
191
|
-
- test/
|
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/
|
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/
|
201
|
-
- test/integration/
|
202
|
-
- test/integration/tags/
|
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/
|
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/
|
213
|
-
- test/integration/
|
214
|
-
- test/integration/
|
215
|
-
- test/integration/
|
216
|
-
- test/integration/
|
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
|
data/lib/liquid/strainer.rb
DELETED
@@ -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
|
data/lib/liquid/truffle.rb
DELETED
@@ -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
|