locomotivecms-liquid 2.6.0 → 4.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +62 -5
  3. data/README.md +4 -4
  4. data/lib/liquid.rb +16 -12
  5. data/lib/liquid/block.rb +37 -118
  6. data/lib/liquid/block_body.rb +131 -0
  7. data/lib/liquid/condition.rb +28 -17
  8. data/lib/liquid/context.rb +94 -146
  9. data/lib/liquid/document.rb +16 -10
  10. data/lib/liquid/drop.rb +8 -5
  11. data/lib/liquid/drops/inherited_block_drop.rb +24 -0
  12. data/lib/liquid/errors.rb +44 -5
  13. data/lib/liquid/expression.rb +33 -0
  14. data/lib/liquid/file_system.rb +17 -6
  15. data/lib/liquid/i18n.rb +2 -2
  16. data/lib/liquid/interrupts.rb +1 -1
  17. data/lib/liquid/lexer.rb +11 -9
  18. data/lib/liquid/locales/en.yml +2 -4
  19. data/lib/liquid/parser.rb +2 -1
  20. data/lib/liquid/parser_switching.rb +31 -0
  21. data/lib/liquid/profiler.rb +162 -0
  22. data/lib/liquid/profiler/hooks.rb +23 -0
  23. data/lib/liquid/range_lookup.rb +22 -0
  24. data/lib/liquid/resource_limits.rb +23 -0
  25. data/lib/liquid/standardfilters.rb +142 -67
  26. data/lib/liquid/strainer.rb +14 -4
  27. data/lib/liquid/tag.rb +22 -41
  28. data/lib/liquid/tags/assign.rb +15 -10
  29. data/lib/liquid/tags/break.rb +1 -1
  30. data/lib/liquid/tags/capture.rb +7 -9
  31. data/lib/liquid/tags/case.rb +28 -19
  32. data/lib/liquid/tags/comment.rb +2 -2
  33. data/lib/liquid/tags/continue.rb +1 -4
  34. data/lib/liquid/tags/cycle.rb +10 -14
  35. data/lib/liquid/tags/decrement.rb +3 -4
  36. data/lib/liquid/tags/extends.rb +28 -44
  37. data/lib/liquid/tags/for.rb +64 -42
  38. data/lib/liquid/tags/if.rb +30 -19
  39. data/lib/liquid/tags/ifchanged.rb +4 -4
  40. data/lib/liquid/tags/include.rb +30 -20
  41. data/lib/liquid/tags/increment.rb +3 -8
  42. data/lib/liquid/tags/inherited_block.rb +54 -56
  43. data/lib/liquid/tags/raw.rb +18 -10
  44. data/lib/liquid/tags/table_row.rb +72 -0
  45. data/lib/liquid/tags/unless.rb +5 -7
  46. data/lib/liquid/template.rb +113 -53
  47. data/lib/liquid/token.rb +18 -0
  48. data/lib/liquid/utils.rb +13 -4
  49. data/lib/liquid/variable.rb +68 -50
  50. data/lib/liquid/variable_lookup.rb +78 -0
  51. data/lib/liquid/version.rb +1 -1
  52. data/test/fixtures/en_locale.yml +9 -0
  53. data/test/integration/assign_test.rb +48 -0
  54. data/test/integration/blank_test.rb +106 -0
  55. data/test/integration/capture_test.rb +50 -0
  56. data/test/integration/context_test.rb +32 -0
  57. data/test/integration/document_test.rb +19 -0
  58. data/test/integration/drop_test.rb +271 -0
  59. data/test/integration/error_handling_test.rb +207 -0
  60. data/test/integration/filter_test.rb +125 -0
  61. data/test/integration/hash_ordering_test.rb +23 -0
  62. data/test/integration/output_test.rb +116 -0
  63. data/test/integration/parsing_quirks_test.rb +119 -0
  64. data/test/integration/render_profiling_test.rb +154 -0
  65. data/test/integration/security_test.rb +64 -0
  66. data/test/integration/standard_filter_test.rb +379 -0
  67. data/test/integration/tags/break_tag_test.rb +16 -0
  68. data/test/integration/tags/continue_tag_test.rb +16 -0
  69. data/test/integration/tags/extends_tag_test.rb +104 -0
  70. data/test/integration/tags/for_tag_test.rb +375 -0
  71. data/test/integration/tags/if_else_tag_test.rb +169 -0
  72. data/test/integration/tags/include_tag_test.rb +234 -0
  73. data/test/integration/tags/increment_tag_test.rb +24 -0
  74. data/test/integration/tags/raw_tag_test.rb +25 -0
  75. data/test/integration/tags/standard_tag_test.rb +297 -0
  76. data/test/integration/tags/statements_test.rb +113 -0
  77. data/test/integration/tags/table_row_test.rb +63 -0
  78. data/test/integration/tags/unless_else_tag_test.rb +26 -0
  79. data/test/integration/template_test.rb +216 -0
  80. data/test/integration/variable_test.rb +82 -0
  81. data/test/test_helper.rb +83 -0
  82. data/test/unit/block_unit_test.rb +55 -0
  83. data/test/unit/condition_unit_test.rb +149 -0
  84. data/test/unit/context_unit_test.rb +482 -0
  85. data/test/unit/file_system_unit_test.rb +35 -0
  86. data/test/unit/i18n_unit_test.rb +37 -0
  87. data/test/unit/lexer_unit_test.rb +51 -0
  88. data/test/unit/module_ex_unit_test.rb +87 -0
  89. data/test/unit/parser_unit_test.rb +82 -0
  90. data/test/unit/regexp_unit_test.rb +44 -0
  91. data/test/unit/strainer_unit_test.rb +71 -0
  92. data/test/unit/tag_unit_test.rb +16 -0
  93. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  94. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  95. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  96. data/test/unit/template_unit_test.rb +70 -0
  97. data/test/unit/tokenizer_unit_test.rb +38 -0
  98. data/test/unit/variable_unit_test.rb +150 -0
  99. metadata +144 -15
  100. data/lib/extras/liquid_view.rb +0 -51
  101. data/lib/liquid/htmltags.rb +0 -74
  102. data/lib/liquid/tags/default_content.rb +0 -21
  103. data/lib/locomotivecms-liquid.rb +0 -1
@@ -0,0 +1,149 @@
1
+ require 'test_helper'
2
+
3
+ class ConditionUnitTest < Minitest::Test
4
+ include Liquid
5
+
6
+ def test_basic_condition
7
+ assert_equal false, Condition.new(1, '==', 2).evaluate
8
+ assert_equal true, Condition.new(1, '==', 1).evaluate
9
+ end
10
+
11
+ def test_default_operators_evalute_true
12
+ assert_evalutes_true 1, '==', 1
13
+ assert_evalutes_true 1, '!=', 2
14
+ assert_evalutes_true 1, '<>', 2
15
+ assert_evalutes_true 1, '<', 2
16
+ assert_evalutes_true 2, '>', 1
17
+ assert_evalutes_true 1, '>=', 1
18
+ assert_evalutes_true 2, '>=', 1
19
+ assert_evalutes_true 1, '<=', 2
20
+ assert_evalutes_true 1, '<=', 1
21
+ # negative numbers
22
+ assert_evalutes_true 1, '>', -1
23
+ assert_evalutes_true -1, '<', 1
24
+ assert_evalutes_true 1.0, '>', -1.0
25
+ assert_evalutes_true -1.0, '<', 1.0
26
+ end
27
+
28
+ def test_default_operators_evalute_false
29
+ assert_evalutes_false 1, '==', 2
30
+ assert_evalutes_false 1, '!=', 1
31
+ assert_evalutes_false 1, '<>', 1
32
+ assert_evalutes_false 1, '<', 0
33
+ assert_evalutes_false 2, '>', 4
34
+ assert_evalutes_false 1, '>=', 3
35
+ assert_evalutes_false 2, '>=', 4
36
+ assert_evalutes_false 1, '<=', 0
37
+ assert_evalutes_false 1, '<=', 0
38
+ end
39
+
40
+ def test_contains_works_on_strings
41
+ assert_evalutes_true 'bob', 'contains', 'o'
42
+ assert_evalutes_true 'bob', 'contains', 'b'
43
+ assert_evalutes_true 'bob', 'contains', 'bo'
44
+ assert_evalutes_true 'bob', 'contains', 'ob'
45
+ assert_evalutes_true 'bob', 'contains', 'bob'
46
+
47
+ assert_evalutes_false 'bob', 'contains', 'bob2'
48
+ assert_evalutes_false 'bob', 'contains', 'a'
49
+ assert_evalutes_false 'bob', 'contains', '---'
50
+ end
51
+
52
+ def test_invalid_comparation_operator
53
+ assert_evaluates_argument_error 1, '~~', 0
54
+ end
55
+
56
+ def test_comparation_of_int_and_str
57
+ assert_evaluates_argument_error '1', '>', 0
58
+ assert_evaluates_argument_error '1', '<', 0
59
+ assert_evaluates_argument_error '1', '>=', 0
60
+ assert_evaluates_argument_error '1', '<=', 0
61
+ end
62
+
63
+ def test_contains_works_on_arrays
64
+ @context = Liquid::Context.new
65
+ @context['array'] = [1,2,3,4,5]
66
+ array_expr = VariableLookup.new("array")
67
+
68
+ assert_evalutes_false array_expr, 'contains', 0
69
+ assert_evalutes_true array_expr, 'contains', 1
70
+ assert_evalutes_true array_expr, 'contains', 2
71
+ assert_evalutes_true array_expr, 'contains', 3
72
+ assert_evalutes_true array_expr, 'contains', 4
73
+ assert_evalutes_true array_expr, 'contains', 5
74
+ assert_evalutes_false array_expr, 'contains', 6
75
+ assert_evalutes_false array_expr, 'contains', "1"
76
+ end
77
+
78
+ def test_contains_returns_false_for_nil_operands
79
+ @context = Liquid::Context.new
80
+ assert_evalutes_false VariableLookup.new('not_assigned'), 'contains', '0'
81
+ assert_evalutes_false 0, 'contains', VariableLookup.new('not_assigned')
82
+ end
83
+
84
+ def test_contains_return_false_on_wrong_data_type
85
+ assert_evalutes_false 1, 'contains', 0
86
+ end
87
+
88
+ def test_or_condition
89
+ condition = Condition.new(1, '==', 2)
90
+
91
+ assert_equal false, condition.evaluate
92
+
93
+ condition.or Condition.new(2, '==', 1)
94
+
95
+ assert_equal false, condition.evaluate
96
+
97
+ condition.or Condition.new(1, '==', 1)
98
+
99
+ assert_equal true, condition.evaluate
100
+ end
101
+
102
+ def test_and_condition
103
+ condition = Condition.new(1, '==', 1)
104
+
105
+ assert_equal true, condition.evaluate
106
+
107
+ condition.and Condition.new(2, '==', 2)
108
+
109
+ assert_equal true, condition.evaluate
110
+
111
+ condition.and Condition.new(2, '==', 1)
112
+
113
+ assert_equal false, condition.evaluate
114
+ end
115
+
116
+ def test_should_allow_custom_proc_operator
117
+ Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}} }
118
+
119
+ assert_evalutes_true 'bob', 'starts_with', 'b'
120
+ assert_evalutes_false 'bob', 'starts_with', 'o'
121
+ ensure
122
+ Condition.operators.delete 'starts_with'
123
+ end
124
+
125
+ def test_left_or_right_may_contain_operators
126
+ @context = Liquid::Context.new
127
+ @context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
128
+
129
+ assert_evalutes_true VariableLookup.new("one"), '==', VariableLookup.new("another")
130
+ end
131
+
132
+ private
133
+ def assert_evalutes_true(left, op, right)
134
+ assert Condition.new(left, op, right).evaluate(@context || Liquid::Context.new),
135
+ "Evaluated false: #{left} #{op} #{right}"
136
+ end
137
+
138
+ def assert_evalutes_false(left, op, right)
139
+ assert !Condition.new(left, op, right).evaluate(@context || Liquid::Context.new),
140
+ "Evaluated true: #{left} #{op} #{right}"
141
+ end
142
+
143
+ def assert_evaluates_argument_error(left, op, right)
144
+ assert_raises(Liquid::ArgumentError) do
145
+ Condition.new(left, op, right).evaluate(@context || Liquid::Context.new)
146
+ end
147
+ end
148
+
149
+ end # ConditionTest
@@ -0,0 +1,482 @@
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 teardown
74
+ Spy.teardown
75
+ end
76
+
77
+ def test_variables
78
+ @context['string'] = 'string'
79
+ assert_equal 'string', @context['string']
80
+
81
+ @context['num'] = 5
82
+ assert_equal 5, @context['num']
83
+
84
+ @context['time'] = Time.parse('2006-06-06 12:00:00')
85
+ assert_equal Time.parse('2006-06-06 12:00:00'), @context['time']
86
+
87
+ @context['date'] = Date.today
88
+ assert_equal Date.today, @context['date']
89
+
90
+ now = DateTime.now
91
+ @context['datetime'] = now
92
+ assert_equal now, @context['datetime']
93
+
94
+ @context['bool'] = true
95
+ assert_equal true, @context['bool']
96
+
97
+ @context['bool'] = false
98
+ assert_equal false, @context['bool']
99
+
100
+ @context['nil'] = nil
101
+ assert_equal nil, @context['nil']
102
+ assert_equal nil, @context['nil']
103
+ end
104
+
105
+ def test_variables_not_existing
106
+ assert_equal nil, @context['does_not_exist']
107
+ end
108
+
109
+ def test_scoping
110
+ @context.push
111
+ @context.pop
112
+
113
+ assert_raises(Liquid::ContextError) do
114
+ @context.pop
115
+ end
116
+
117
+ assert_raises(Liquid::ContextError) do
118
+ @context.push
119
+ @context.pop
120
+ @context.pop
121
+ end
122
+ end
123
+
124
+ def test_length_query
125
+
126
+ @context['numbers'] = [1,2,3,4]
127
+
128
+ assert_equal 4, @context['numbers.size']
129
+
130
+ @context['numbers'] = {1 => 1,2 => 2,3 => 3,4 => 4}
131
+
132
+ assert_equal 4, @context['numbers.size']
133
+
134
+ @context['numbers'] = {1 => 1,2 => 2,3 => 3,4 => 4, 'size' => 1000}
135
+
136
+ assert_equal 1000, @context['numbers.size']
137
+
138
+ end
139
+
140
+ def test_hyphenated_variable
141
+
142
+ @context['oh-my'] = 'godz'
143
+ assert_equal 'godz', @context['oh-my']
144
+
145
+ end
146
+
147
+ def test_add_filter
148
+
149
+ filter = Module.new do
150
+ def hi(output)
151
+ output + ' hi!'
152
+ end
153
+ end
154
+
155
+ context = Context.new
156
+ context.add_filters(filter)
157
+ assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
158
+
159
+ context = Context.new
160
+ assert_equal 'hi?', context.invoke(:hi, 'hi?')
161
+
162
+ context.add_filters(filter)
163
+ assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
164
+
165
+ end
166
+
167
+ def test_only_intended_filters_make_it_there
168
+
169
+ filter = Module.new do
170
+ def hi(output)
171
+ output + ' hi!'
172
+ end
173
+ end
174
+
175
+ context = Context.new
176
+ assert_equal "Wookie", context.invoke("hi", "Wookie")
177
+
178
+ context.add_filters(filter)
179
+ assert_equal "Wookie hi!", context.invoke("hi", "Wookie")
180
+ end
181
+
182
+ def test_add_item_in_outer_scope
183
+ @context['test'] = 'test'
184
+ @context.push
185
+ assert_equal 'test', @context['test']
186
+ @context.pop
187
+ assert_equal 'test', @context['test']
188
+ end
189
+
190
+ def test_add_item_in_inner_scope
191
+ @context.push
192
+ @context['test'] = 'test'
193
+ assert_equal 'test', @context['test']
194
+ @context.pop
195
+ assert_equal nil, @context['test']
196
+ end
197
+
198
+ def test_hierachical_data
199
+ @context['hash'] = {"name" => 'tobi'}
200
+ assert_equal 'tobi', @context['hash.name']
201
+ assert_equal 'tobi', @context['hash["name"]']
202
+ end
203
+
204
+ def test_keywords
205
+ assert_equal true, @context['true']
206
+ assert_equal false, @context['false']
207
+ end
208
+
209
+ def test_digits
210
+ assert_equal 100, @context['100']
211
+ assert_equal 100.00, @context['100.00']
212
+ end
213
+
214
+ def test_strings
215
+ assert_equal "hello!", @context['"hello!"']
216
+ assert_equal "hello!", @context["'hello!'"]
217
+ end
218
+
219
+ def test_merge
220
+ @context.merge({ "test" => "test" })
221
+ assert_equal 'test', @context['test']
222
+ @context.merge({ "test" => "newvalue", "foo" => "bar" })
223
+ assert_equal 'newvalue', @context['test']
224
+ assert_equal 'bar', @context['foo']
225
+ end
226
+
227
+ def test_array_notation
228
+ @context['test'] = [1,2,3,4,5]
229
+
230
+ assert_equal 1, @context['test[0]']
231
+ assert_equal 2, @context['test[1]']
232
+ assert_equal 3, @context['test[2]']
233
+ assert_equal 4, @context['test[3]']
234
+ assert_equal 5, @context['test[4]']
235
+ end
236
+
237
+ def test_recoursive_array_notation
238
+ @context['test'] = {'test' => [1,2,3,4,5]}
239
+
240
+ assert_equal 1, @context['test.test[0]']
241
+
242
+ @context['test'] = [{'test' => 'worked'}]
243
+
244
+ assert_equal 'worked', @context['test[0].test']
245
+ end
246
+
247
+ def test_hash_to_array_transition
248
+ @context['colors'] = {
249
+ 'Blue' => ['003366','336699', '6699CC', '99CCFF'],
250
+ 'Green' => ['003300','336633', '669966', '99CC99'],
251
+ 'Yellow' => ['CC9900','FFCC00', 'FFFF99', 'FFFFCC'],
252
+ 'Red' => ['660000','993333', 'CC6666', 'FF9999']
253
+ }
254
+
255
+ assert_equal '003366', @context['colors.Blue[0]']
256
+ assert_equal 'FF9999', @context['colors.Red[3]']
257
+ end
258
+
259
+ def test_try_first
260
+ @context['test'] = [1,2,3,4,5]
261
+
262
+ assert_equal 1, @context['test.first']
263
+ assert_equal 5, @context['test.last']
264
+
265
+ @context['test'] = {'test' => [1,2,3,4,5]}
266
+
267
+ assert_equal 1, @context['test.test.first']
268
+ assert_equal 5, @context['test.test.last']
269
+
270
+ @context['test'] = [1]
271
+ assert_equal 1, @context['test.first']
272
+ assert_equal 1, @context['test.last']
273
+ end
274
+
275
+ def test_access_hashes_with_hash_notation
276
+ @context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
277
+ @context['product'] = {'variants' => [ {'title' => 'draft151cm'}, {'title' => 'element151cm'} ]}
278
+
279
+ assert_equal 5, @context['products["count"]']
280
+ assert_equal 'deepsnow', @context['products["tags"][0]']
281
+ assert_equal 'deepsnow', @context['products["tags"].first']
282
+ assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
283
+ assert_equal 'element151cm', @context['product["variants"][1]["title"]']
284
+ assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
285
+ assert_equal 'element151cm', @context['product["variants"].last["title"]']
286
+ end
287
+
288
+ def test_access_variable_with_hash_notation
289
+ @context['foo'] = 'baz'
290
+ @context['bar'] = 'foo'
291
+
292
+ assert_equal 'baz', @context['["foo"]']
293
+ assert_equal 'baz', @context['[bar]']
294
+ end
295
+
296
+ def test_access_hashes_with_hash_access_variables
297
+
298
+ @context['var'] = 'tags'
299
+ @context['nested'] = {'var' => 'tags'}
300
+ @context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
301
+
302
+ assert_equal 'deepsnow', @context['products[var].first']
303
+ assert_equal 'freestyle', @context['products[nested.var].last']
304
+ end
305
+
306
+ def test_hash_notation_only_for_hash_access
307
+ @context['array'] = [1,2,3,4,5]
308
+ @context['hash'] = {'first' => 'Hello'}
309
+
310
+ assert_equal 1, @context['array.first']
311
+ assert_equal nil, @context['array["first"]']
312
+ assert_equal 'Hello', @context['hash["first"]']
313
+ end
314
+
315
+ def test_first_can_appear_in_middle_of_callchain
316
+
317
+ @context['product'] = {'variants' => [ {'title' => 'draft151cm'}, {'title' => 'element151cm'} ]}
318
+
319
+ assert_equal 'draft151cm', @context['product.variants[0].title']
320
+ assert_equal 'element151cm', @context['product.variants[1].title']
321
+ assert_equal 'draft151cm', @context['product.variants.first.title']
322
+ assert_equal 'element151cm', @context['product.variants.last.title']
323
+
324
+ end
325
+
326
+ def test_cents
327
+ @context.merge( "cents" => HundredCentes.new )
328
+ assert_equal 100, @context['cents']
329
+ end
330
+
331
+ def test_nested_cents
332
+ @context.merge( "cents" => { 'amount' => HundredCentes.new} )
333
+ assert_equal 100, @context['cents.amount']
334
+
335
+ @context.merge( "cents" => { 'cents' => { 'amount' => HundredCentes.new} } )
336
+ assert_equal 100, @context['cents.cents.amount']
337
+ end
338
+
339
+ def test_cents_through_drop
340
+ @context.merge( "cents" => CentsDrop.new )
341
+ assert_equal 100, @context['cents.amount']
342
+ end
343
+
344
+ def test_nested_cents_through_drop
345
+ @context.merge( "vars" => {"cents" => CentsDrop.new} )
346
+ assert_equal 100, @context['vars.cents.amount']
347
+ end
348
+
349
+ def test_drop_methods_with_question_marks
350
+ @context.merge( "cents" => CentsDrop.new )
351
+ assert @context['cents.non_zero?']
352
+ end
353
+
354
+ def test_context_from_within_drop
355
+ @context.merge( "test" => '123', "vars" => ContextSensitiveDrop.new )
356
+ assert_equal '123', @context['vars.test']
357
+ end
358
+
359
+ def test_nested_context_from_within_drop
360
+ @context.merge( "test" => '123', "vars" => {"local" => ContextSensitiveDrop.new } )
361
+ assert_equal '123', @context['vars.local.test']
362
+ end
363
+
364
+ def test_ranges
365
+ @context.merge( "test" => '5' )
366
+ assert_equal (1..5), @context['(1..5)']
367
+ assert_equal (1..5), @context['(1..test)']
368
+ assert_equal (5..5), @context['(test..test)']
369
+ end
370
+
371
+ def test_cents_through_drop_nestedly
372
+ @context.merge( "cents" => {"cents" => CentsDrop.new} )
373
+ assert_equal 100, @context['cents.cents.amount']
374
+
375
+ @context.merge( "cents" => { "cents" => {"cents" => CentsDrop.new}} )
376
+ assert_equal 100, @context['cents.cents.cents.amount']
377
+ end
378
+
379
+ def test_drop_with_variable_called_only_once
380
+ @context['counter'] = CounterDrop.new
381
+
382
+ assert_equal 1, @context['counter.count']
383
+ assert_equal 2, @context['counter.count']
384
+ assert_equal 3, @context['counter.count']
385
+ end
386
+
387
+ def test_drop_with_key_called_only_once
388
+ @context['counter'] = CounterDrop.new
389
+
390
+ assert_equal 1, @context['counter["count"]']
391
+ assert_equal 2, @context['counter["count"]']
392
+ assert_equal 3, @context['counter["count"]']
393
+ end
394
+
395
+ def test_proc_as_variable
396
+ @context['dynamic'] = Proc.new { 'Hello' }
397
+
398
+ assert_equal 'Hello', @context['dynamic']
399
+ end
400
+
401
+ def test_lambda_as_variable
402
+ @context['dynamic'] = proc { 'Hello' }
403
+
404
+ assert_equal 'Hello', @context['dynamic']
405
+ end
406
+
407
+ def test_nested_lambda_as_variable
408
+ @context['dynamic'] = { "lambda" => proc { 'Hello' } }
409
+
410
+ assert_equal 'Hello', @context['dynamic.lambda']
411
+ end
412
+
413
+ def test_array_containing_lambda_as_variable
414
+ @context['dynamic'] = [1,2, proc { 'Hello' } ,4,5]
415
+
416
+ assert_equal 'Hello', @context['dynamic[2]']
417
+ end
418
+
419
+ def test_lambda_is_called_once
420
+ @context['callcount'] = proc { @global ||= 0; @global += 1; @global.to_s }
421
+
422
+ assert_equal '1', @context['callcount']
423
+ assert_equal '1', @context['callcount']
424
+ assert_equal '1', @context['callcount']
425
+
426
+ @global = nil
427
+ end
428
+
429
+ def test_nested_lambda_is_called_once
430
+ @context['callcount'] = { "lambda" => proc { @global ||= 0; @global += 1; @global.to_s } }
431
+
432
+ assert_equal '1', @context['callcount.lambda']
433
+ assert_equal '1', @context['callcount.lambda']
434
+ assert_equal '1', @context['callcount.lambda']
435
+
436
+ @global = nil
437
+ end
438
+
439
+ def test_lambda_in_array_is_called_once
440
+ @context['callcount'] = [1,2, proc { @global ||= 0; @global += 1; @global.to_s } ,4,5]
441
+
442
+ assert_equal '1', @context['callcount[2]']
443
+ assert_equal '1', @context['callcount[2]']
444
+ assert_equal '1', @context['callcount[2]']
445
+
446
+ @global = nil
447
+ end
448
+
449
+ def test_access_to_context_from_proc
450
+ @context.registers[:magic] = 345392
451
+
452
+ @context['magic'] = proc { @context.registers[:magic] }
453
+
454
+ assert_equal 345392, @context['magic']
455
+ end
456
+
457
+ def test_to_liquid_and_context_at_first_level
458
+ @context['category'] = Category.new("foobar")
459
+ assert_kind_of CategoryDrop, @context['category']
460
+ assert_equal @context, @context['category'].context
461
+ end
462
+
463
+ def test_use_empty_instead_of_any_in_interrupt_handling_to_avoid_lots_of_unnecessary_object_allocations
464
+ mock_any = Spy.on_instance_method(Array, :any?)
465
+ mock_empty = Spy.on_instance_method(Array, :empty?)
466
+ mock_has_interrupt = Spy.on(@context, :has_interrupt?).and_call_through
467
+
468
+ @context.has_interrupt?
469
+
470
+ refute mock_any.has_been_called?
471
+ assert mock_empty.has_been_called?
472
+ end
473
+
474
+ def test_context_initialization_with_a_proc_in_environment
475
+ contx = Context.new([:test => lambda { |c| c['poutine']}], {:test => :foo})
476
+
477
+ assert contx
478
+ assert_nil contx['poutine']
479
+ end
480
+
481
+
482
+ end # ContextTest