drnic-liquid 2.1.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 (113) hide show
  1. data/CHANGELOG +44 -0
  2. data/History.txt +44 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +34 -0
  5. data/README.rdoc +44 -0
  6. data/Rakefile +30 -0
  7. data/example/server/example_servlet.rb +37 -0
  8. data/example/server/liquid_servlet.rb +28 -0
  9. data/example/server/server.rb +12 -0
  10. data/example/server/templates/index.liquid +6 -0
  11. data/example/server/templates/products.liquid +45 -0
  12. data/init.rb +8 -0
  13. data/lib/extras/liquid_view.rb +51 -0
  14. data/lib/liquid.rb +70 -0
  15. data/lib/liquid/block.rb +102 -0
  16. data/lib/liquid/condition.rb +120 -0
  17. data/lib/liquid/context.rb +221 -0
  18. data/lib/liquid/document.rb +17 -0
  19. data/lib/liquid/drop.rb +51 -0
  20. data/lib/liquid/errors.rb +11 -0
  21. data/lib/liquid/extensions.rb +56 -0
  22. data/lib/liquid/file_system.rb +62 -0
  23. data/lib/liquid/htmltags.rb +74 -0
  24. data/lib/liquid/module_ex.rb +62 -0
  25. data/lib/liquid/standardfilters.rb +209 -0
  26. data/lib/liquid/strainer.rb +51 -0
  27. data/lib/liquid/tag.rb +26 -0
  28. data/lib/liquid/tags/assign.rb +33 -0
  29. data/lib/liquid/tags/capture.rb +35 -0
  30. data/lib/liquid/tags/case.rb +83 -0
  31. data/lib/liquid/tags/comment.rb +9 -0
  32. data/lib/liquid/tags/cycle.rb +59 -0
  33. data/lib/liquid/tags/for.rb +136 -0
  34. data/lib/liquid/tags/if.rb +79 -0
  35. data/lib/liquid/tags/ifchanged.rb +20 -0
  36. data/lib/liquid/tags/include.rb +55 -0
  37. data/lib/liquid/tags/unless.rb +33 -0
  38. data/lib/liquid/template.rb +147 -0
  39. data/lib/liquid/variable.rb +49 -0
  40. data/liquid.gemspec +40 -0
  41. data/performance/shopify.rb +92 -0
  42. data/performance/shopify/comment_form.rb +33 -0
  43. data/performance/shopify/database.rb +45 -0
  44. data/performance/shopify/json_filter.rb +7 -0
  45. data/performance/shopify/liquid.rb +18 -0
  46. data/performance/shopify/money_filter.rb +18 -0
  47. data/performance/shopify/paginate.rb +93 -0
  48. data/performance/shopify/shop_filter.rb +98 -0
  49. data/performance/shopify/tag_filter.rb +25 -0
  50. data/performance/shopify/vision.database.yml +945 -0
  51. data/performance/shopify/weight_filter.rb +11 -0
  52. data/performance/tests/dropify/article.liquid +74 -0
  53. data/performance/tests/dropify/blog.liquid +33 -0
  54. data/performance/tests/dropify/cart.liquid +66 -0
  55. data/performance/tests/dropify/collection.liquid +22 -0
  56. data/performance/tests/dropify/index.liquid +47 -0
  57. data/performance/tests/dropify/page.liquid +8 -0
  58. data/performance/tests/dropify/product.liquid +68 -0
  59. data/performance/tests/dropify/theme.liquid +105 -0
  60. data/performance/tests/ripen/article.liquid +74 -0
  61. data/performance/tests/ripen/blog.liquid +13 -0
  62. data/performance/tests/ripen/cart.liquid +54 -0
  63. data/performance/tests/ripen/collection.liquid +29 -0
  64. data/performance/tests/ripen/index.liquid +32 -0
  65. data/performance/tests/ripen/page.liquid +4 -0
  66. data/performance/tests/ripen/product.liquid +75 -0
  67. data/performance/tests/ripen/theme.liquid +85 -0
  68. data/performance/tests/tribble/404.liquid +56 -0
  69. data/performance/tests/tribble/article.liquid +98 -0
  70. data/performance/tests/tribble/blog.liquid +41 -0
  71. data/performance/tests/tribble/cart.liquid +134 -0
  72. data/performance/tests/tribble/collection.liquid +70 -0
  73. data/performance/tests/tribble/index.liquid +94 -0
  74. data/performance/tests/tribble/page.liquid +56 -0
  75. data/performance/tests/tribble/product.liquid +116 -0
  76. data/performance/tests/tribble/search.liquid +51 -0
  77. data/performance/tests/tribble/theme.liquid +90 -0
  78. data/performance/tests/vogue/article.liquid +66 -0
  79. data/performance/tests/vogue/blog.liquid +32 -0
  80. data/performance/tests/vogue/cart.liquid +58 -0
  81. data/performance/tests/vogue/collection.liquid +19 -0
  82. data/performance/tests/vogue/index.liquid +22 -0
  83. data/performance/tests/vogue/page.liquid +3 -0
  84. data/performance/tests/vogue/product.liquid +62 -0
  85. data/performance/tests/vogue/theme.liquid +122 -0
  86. data/test/assign_test.rb +11 -0
  87. data/test/block_test.rb +58 -0
  88. data/test/condition_test.rb +109 -0
  89. data/test/context_test.rb +482 -0
  90. data/test/drop_test.rb +162 -0
  91. data/test/error_handling_test.rb +89 -0
  92. data/test/extra/breakpoint.rb +547 -0
  93. data/test/extra/caller.rb +80 -0
  94. data/test/file_system_test.rb +30 -0
  95. data/test/filter_test.rb +95 -0
  96. data/test/helper.rb +20 -0
  97. data/test/html_tag_test.rb +31 -0
  98. data/test/if_else_test.rb +131 -0
  99. data/test/include_tag_test.rb +115 -0
  100. data/test/module_ex_test.rb +89 -0
  101. data/test/output_test.rb +121 -0
  102. data/test/parsing_quirks_test.rb +41 -0
  103. data/test/regexp_test.rb +45 -0
  104. data/test/security_test.rb +41 -0
  105. data/test/standard_filter_test.rb +161 -0
  106. data/test/standard_tag_test.rb +400 -0
  107. data/test/statements_test.rb +137 -0
  108. data/test/strainer_test.rb +21 -0
  109. data/test/template_test.rb +26 -0
  110. data/test/test_helper.rb +20 -0
  111. data/test/unless_else_test.rb +27 -0
  112. data/test/variable_test.rb +172 -0
  113. metadata +187 -0
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class AssignTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_assigned_variable
7
+ assert_template_result('.foo.','{% assign foo = values %}.{{ foo[0] }}.', 'values' => %w{foo bar baz})
8
+ assert_template_result('.bar.','{% assign foo = values %}.{{ foo[1] }}.', 'values' => %w{foo bar baz})
9
+ end
10
+
11
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class VariableTest < Test::Unit::TestCase
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], block_types(template.root.nodelist)
37
+ end
38
+
39
+ def test_with_block
40
+ template = Liquid::Template.parse(" {% comment %} {% end %} ")
41
+ assert_equal [String, Comment, String], block_types(template.root.nodelist)
42
+ assert_equal 3, template.root.nodelist.size
43
+ end
44
+
45
+ def test_with_custom_tag
46
+ Liquid::Template.register_tag("testtag", Block)
47
+
48
+ assert_nothing_thrown do
49
+ template = Liquid::Template.parse( "{% testtag %} {% end %}")
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def block_types(nodelist)
56
+ nodelist.collect { |node| node.class }
57
+ end
58
+ end
@@ -0,0 +1,109 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class ConditionTest < Test::Unit::TestCase
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
+ end
22
+
23
+ def test_default_operators_evalute_false
24
+ assert_evalutes_false '1', '==', '2'
25
+ assert_evalutes_false '1', '!=', '1'
26
+ assert_evalutes_false '1', '<>', '1'
27
+ assert_evalutes_false '1', '<', '0'
28
+ assert_evalutes_false '2', '>', '4'
29
+ assert_evalutes_false '1', '>=', '3'
30
+ assert_evalutes_false '2', '>=', '4'
31
+ assert_evalutes_false '1', '<=', '0'
32
+ assert_evalutes_false '1', '<=', '0'
33
+ end
34
+
35
+ def test_contains_works_on_strings
36
+ assert_evalutes_true "'bob'", 'contains', "'o'"
37
+ assert_evalutes_true "'bob'", 'contains', "'b'"
38
+ assert_evalutes_true "'bob'", 'contains', "'bo'"
39
+ assert_evalutes_true "'bob'", 'contains', "'ob'"
40
+ assert_evalutes_true "'bob'", 'contains', "'bob'"
41
+
42
+ assert_evalutes_false "'bob'", 'contains', "'bob2'"
43
+ assert_evalutes_false "'bob'", 'contains', "'a'"
44
+ assert_evalutes_false "'bob'", 'contains', "'---'"
45
+ end
46
+
47
+ def test_contains_works_on_arrays
48
+ @context = Liquid::Context.new
49
+ @context['array'] = [1,2,3,4,5]
50
+
51
+ assert_evalutes_false "array", 'contains', '0'
52
+ assert_evalutes_true "array", 'contains', '1'
53
+ assert_evalutes_true "array", 'contains', '2'
54
+ assert_evalutes_true "array", 'contains', '3'
55
+ assert_evalutes_true "array", 'contains', '4'
56
+ assert_evalutes_true "array", 'contains', '5'
57
+ assert_evalutes_false "array", 'contains', '6'
58
+
59
+ assert_evalutes_false "array", 'contains', '"1"'
60
+
61
+ end
62
+
63
+ def test_or_condition
64
+ condition = Condition.new('1', '==', '2')
65
+
66
+ assert_equal false, condition.evaluate
67
+
68
+ condition.or Condition.new('2', '==', '1')
69
+
70
+ assert_equal false, condition.evaluate
71
+
72
+ condition.or Condition.new('1', '==', '1')
73
+
74
+ assert_equal true, condition.evaluate
75
+ end
76
+
77
+ def test_and_condition
78
+ condition = Condition.new('1', '==', '1')
79
+
80
+ assert_equal true, condition.evaluate
81
+
82
+ condition.and Condition.new('2', '==', '2')
83
+
84
+ assert_equal true, condition.evaluate
85
+
86
+ condition.and Condition.new('2', '==', '1')
87
+
88
+ assert_equal false, condition.evaluate
89
+ end
90
+
91
+
92
+ def test_should_allow_custom_proc_operator
93
+ Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}}}
94
+
95
+ assert_evalutes_true "'bob'", 'starts_with', "'b'"
96
+ assert_evalutes_false "'bob'", 'starts_with', "'o'"
97
+ ensure
98
+ Condition.operators.delete 'starts_with'
99
+ end
100
+
101
+ private
102
+ def assert_evalutes_true(left, op, right)
103
+ assert Condition.new(left, op, right).evaluate(@context || Liquid::Context.new), "Evaluated false: #{left} #{op} #{right}"
104
+ end
105
+
106
+ def assert_evalutes_false(left, op, right)
107
+ assert !Condition.new(left, op, right).evaluate(@context || Liquid::Context.new), "Evaluated true: #{left} #{op} #{right}"
108
+ end
109
+ end
@@ -0,0 +1,482 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ class HundredCentes
3
+ def to_liquid
4
+ 100
5
+ end
6
+ end
7
+
8
+ class CentsDrop < Liquid::Drop
9
+ def amount
10
+ HundredCentes.new
11
+ end
12
+
13
+ def non_zero?
14
+ true
15
+ end
16
+ end
17
+
18
+ class ContextSensitiveDrop < Liquid::Drop
19
+ def test
20
+ @context['test']
21
+ end
22
+ end
23
+
24
+ class Category < Liquid::Drop
25
+ attr_accessor :name
26
+
27
+ def initialize(name)
28
+ @name = name
29
+ end
30
+
31
+ def to_liquid
32
+ CategoryDrop.new(self)
33
+ end
34
+ end
35
+
36
+ class CategoryDrop
37
+ attr_accessor :category, :context
38
+ def initialize(category)
39
+ @category = category
40
+ end
41
+ end
42
+
43
+ class CounterDrop < Liquid::Drop
44
+ def count
45
+ @count ||= 0
46
+ @count += 1
47
+ end
48
+ end
49
+
50
+ class ArrayLike
51
+ def fetch(index)
52
+ end
53
+
54
+ def [](index)
55
+ @counts ||= []
56
+ @counts[index] ||= 0
57
+ @counts[index] += 1
58
+ end
59
+
60
+ def to_liquid
61
+ self
62
+ end
63
+ end
64
+
65
+
66
+ class ContextTest < Test::Unit::TestCase
67
+ include Liquid
68
+
69
+ def setup
70
+ @template = Liquid::Template.new
71
+ @context = Liquid::Context.new(@template.assigns, @template.registers)
72
+ end
73
+
74
+ def test_variables
75
+ @context['string'] = 'string'
76
+ assert_equal 'string', @context['string']
77
+
78
+ @context['num'] = 5
79
+ assert_equal 5, @context['num']
80
+
81
+ @context['time'] = Time.parse('2006-06-06 12:00:00')
82
+ assert_equal Time.parse('2006-06-06 12:00:00'), @context['time']
83
+
84
+ @context['date'] = Date.today
85
+ assert_equal Date.today, @context['date']
86
+
87
+ now = DateTime.now
88
+ @context['datetime'] = now
89
+ assert_equal now, @context['datetime']
90
+
91
+ @context['bool'] = true
92
+ assert_equal true, @context['bool']
93
+
94
+ @context['bool'] = false
95
+ assert_equal false, @context['bool']
96
+
97
+ @context['nil'] = nil
98
+ assert_equal nil, @context['nil']
99
+ assert_equal nil, @context['nil']
100
+ end
101
+
102
+ def test_variables_not_existing
103
+ assert_equal nil, @context['does_not_exist']
104
+ end
105
+
106
+ def test_scoping
107
+ assert_nothing_raised do
108
+ @context.push
109
+ @context.pop
110
+ end
111
+
112
+ assert_raise(Liquid::ContextError) do
113
+ @context.pop
114
+ end
115
+
116
+ assert_raise(Liquid::ContextError) do
117
+ @context.push
118
+ @context.pop
119
+ @context.pop
120
+ end
121
+ end
122
+
123
+ def test_length_query
124
+
125
+ @context['numbers'] = [1,2,3,4]
126
+
127
+ assert_equal 4, @context['numbers.size']
128
+
129
+ @context['numbers'] = {1 => 1,2 => 2,3 => 3,4 => 4}
130
+
131
+ assert_equal 4, @context['numbers.size']
132
+
133
+ @context['numbers'] = {1 => 1,2 => 2,3 => 3,4 => 4, 'size' => 1000}
134
+
135
+ assert_equal 1000, @context['numbers.size']
136
+
137
+ end
138
+
139
+ def test_hyphenated_variable
140
+
141
+ @context['oh-my'] = 'godz'
142
+ assert_equal 'godz', @context['oh-my']
143
+
144
+ end
145
+
146
+ def test_add_filter
147
+
148
+ filter = Module.new do
149
+ def hi(output)
150
+ output + ' hi!'
151
+ end
152
+ end
153
+
154
+ context = Context.new(@template)
155
+ context.add_filters(filter)
156
+ assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
157
+
158
+ context = Context.new(@template)
159
+ assert_raises(FilterNotFound) {
160
+ context.invoke(:hi, 'hi?')
161
+ }
162
+
163
+ context.add_filters(filter)
164
+ assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
165
+
166
+ end
167
+
168
+ def test_override_global_filter
169
+ global = Module.new do
170
+ def notice(output)
171
+ "Global #{output}"
172
+ end
173
+ end
174
+
175
+ local = Module.new do
176
+ def notice(output)
177
+ "Local #{output}"
178
+ end
179
+ end
180
+
181
+ Template.register_filter(global)
182
+ assert_equal 'Global test', Template.parse("{{'test' | notice }}").render
183
+ assert_equal 'Local test', Template.parse("{{'test' | notice }}").render({}, :filters => [local])
184
+ end
185
+
186
+ def test_only_intended_filters_make_it_there
187
+
188
+ filter = Module.new do
189
+ def hi(output)
190
+ output + ' hi!'
191
+ end
192
+ end
193
+
194
+ context = Context.new(@template)
195
+ methods_before = context.strainer.methods.map { |method| method.to_s }
196
+ context.add_filters(filter)
197
+ methods_after = context.strainer.methods.map { |method| method.to_s }
198
+ assert_equal (methods_before + ["hi"]).sort, methods_after.sort
199
+ end
200
+
201
+ def test_add_item_in_outer_scope
202
+ @context['test'] = 'test'
203
+ @context.push
204
+ assert_equal 'test', @context['test']
205
+ @context.pop
206
+ assert_equal 'test', @context['test']
207
+ end
208
+
209
+ def test_add_item_in_inner_scope
210
+ @context.push
211
+ @context['test'] = 'test'
212
+ assert_equal 'test', @context['test']
213
+ @context.pop
214
+ assert_equal nil, @context['test']
215
+ end
216
+
217
+ def test_hierachical_data
218
+ @context['hash'] = {"name" => 'tobi'}
219
+ assert_equal 'tobi', @context['hash.name']
220
+ assert_equal 'tobi', @context['hash["name"]']
221
+ end
222
+
223
+ def test_keywords
224
+ assert_equal true, @context['true']
225
+ assert_equal false, @context['false']
226
+ end
227
+
228
+ def test_digits
229
+ assert_equal 100, @context['100']
230
+ assert_equal 100.00, @context['100.00']
231
+ end
232
+
233
+ def test_strings
234
+ assert_equal "hello!", @context['"hello!"']
235
+ assert_equal "hello!", @context["'hello!'"]
236
+ end
237
+
238
+ def test_merge
239
+ @context.merge({ "test" => "test" })
240
+ assert_equal 'test', @context['test']
241
+ @context.merge({ "test" => "newvalue", "foo" => "bar" })
242
+ assert_equal 'newvalue', @context['test']
243
+ assert_equal 'bar', @context['foo']
244
+ end
245
+
246
+ def test_array_notation
247
+ @context['test'] = [1,2,3,4,5]
248
+
249
+ assert_equal 1, @context['test[0]']
250
+ assert_equal 2, @context['test[1]']
251
+ assert_equal 3, @context['test[2]']
252
+ assert_equal 4, @context['test[3]']
253
+ assert_equal 5, @context['test[4]']
254
+ end
255
+
256
+ def test_recoursive_array_notation
257
+ @context['test'] = {'test' => [1,2,3,4,5]}
258
+
259
+ assert_equal 1, @context['test.test[0]']
260
+
261
+ @context['test'] = [{'test' => 'worked'}]
262
+
263
+ assert_equal 'worked', @context['test[0].test']
264
+ end
265
+
266
+ def test_hash_to_array_transition
267
+ @context['colors'] = {
268
+ 'Blue' => ['003366','336699', '6699CC', '99CCFF'],
269
+ 'Green' => ['003300','336633', '669966', '99CC99'],
270
+ 'Yellow' => ['CC9900','FFCC00', 'FFFF99', 'FFFFCC'],
271
+ 'Red' => ['660000','993333', 'CC6666', 'FF9999']
272
+ }
273
+
274
+ assert_equal '003366', @context['colors.Blue[0]']
275
+ assert_equal 'FF9999', @context['colors.Red[3]']
276
+ end
277
+
278
+ def test_try_first
279
+ @context['test'] = [1,2,3,4,5]
280
+
281
+ assert_equal 1, @context['test.first']
282
+ assert_equal 5, @context['test.last']
283
+
284
+ @context['test'] = {'test' => [1,2,3,4,5]}
285
+
286
+ assert_equal 1, @context['test.test.first']
287
+ assert_equal 5, @context['test.test.last']
288
+
289
+ @context['test'] = [1]
290
+ assert_equal 1, @context['test.first']
291
+ assert_equal 1, @context['test.last']
292
+ end
293
+
294
+ def test_access_hashes_with_hash_notation
295
+ @context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
296
+ @context['product'] = {'variants' => [ {'title' => 'draft151cm'}, {'title' => 'element151cm'} ]}
297
+
298
+ assert_equal 5, @context['products["count"]']
299
+ assert_equal 'deepsnow', @context['products["tags"][0]']
300
+ assert_equal 'deepsnow', @context['products["tags"].first']
301
+ assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
302
+ assert_equal 'element151cm', @context['product["variants"][1]["title"]']
303
+ assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
304
+ assert_equal 'element151cm', @context['product["variants"].last["title"]']
305
+ end
306
+
307
+ def test_access_variable_with_hash_notation
308
+ @context['foo'] = 'baz'
309
+ @context['bar'] = 'foo'
310
+
311
+ assert_equal 'baz', @context['["foo"]']
312
+ assert_equal 'baz', @context['[bar]']
313
+ end
314
+
315
+ def test_access_hashes_with_hash_access_variables
316
+
317
+ @context['var'] = 'tags'
318
+ @context['nested'] = {'var' => 'tags'}
319
+ @context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
320
+
321
+ assert_equal 'deepsnow', @context['products[var].first']
322
+ assert_equal 'freestyle', @context['products[nested.var].last']
323
+ end
324
+
325
+ def test_hash_notation_only_for_hash_access
326
+ @context['array'] = [1,2,3,4,5]
327
+ @context['hash'] = {'first' => 'Hello'}
328
+
329
+ assert_equal 1, @context['array.first']
330
+ assert_equal nil, @context['array["first"]']
331
+ assert_equal 'Hello', @context['hash["first"]']
332
+ end
333
+
334
+ def test_first_can_appear_in_middle_of_callchain
335
+
336
+ @context['product'] = {'variants' => [ {'title' => 'draft151cm'}, {'title' => 'element151cm'} ]}
337
+
338
+ assert_equal 'draft151cm', @context['product.variants[0].title']
339
+ assert_equal 'element151cm', @context['product.variants[1].title']
340
+ assert_equal 'draft151cm', @context['product.variants.first.title']
341
+ assert_equal 'element151cm', @context['product.variants.last.title']
342
+
343
+ end
344
+
345
+ def test_cents
346
+ @context.merge( "cents" => HundredCentes.new )
347
+ assert_equal 100, @context['cents']
348
+ end
349
+
350
+ def test_nested_cents
351
+ @context.merge( "cents" => { 'amount' => HundredCentes.new} )
352
+ assert_equal 100, @context['cents.amount']
353
+
354
+ @context.merge( "cents" => { 'cents' => { 'amount' => HundredCentes.new} } )
355
+ assert_equal 100, @context['cents.cents.amount']
356
+ end
357
+
358
+ def test_cents_through_drop
359
+ @context.merge( "cents" => CentsDrop.new )
360
+ assert_equal 100, @context['cents.amount']
361
+ end
362
+
363
+ def test_nested_cents_through_drop
364
+ @context.merge( "vars" => {"cents" => CentsDrop.new} )
365
+ assert_equal 100, @context['vars.cents.amount']
366
+ end
367
+
368
+ def test_drop_methods_with_question_marks
369
+ @context.merge( "cents" => CentsDrop.new )
370
+ assert @context['cents.non_zero?']
371
+ end
372
+
373
+ def test_context_from_within_drop
374
+ @context.merge( "test" => '123', "vars" => ContextSensitiveDrop.new )
375
+ assert_equal '123', @context['vars.test']
376
+ end
377
+
378
+ def test_nested_context_from_within_drop
379
+ @context.merge( "test" => '123', "vars" => {"local" => ContextSensitiveDrop.new } )
380
+ assert_equal '123', @context['vars.local.test']
381
+ end
382
+
383
+ def test_ranges
384
+ @context.merge( "test" => '5' )
385
+ assert_equal (1..5), @context['(1..5)']
386
+ assert_equal (1..5), @context['(1..test)']
387
+ assert_equal (5..5), @context['(test..test)']
388
+ end
389
+
390
+ def test_cents_through_drop_nestedly
391
+ @context.merge( "cents" => {"cents" => CentsDrop.new} )
392
+ assert_equal 100, @context['cents.cents.amount']
393
+
394
+ @context.merge( "cents" => { "cents" => {"cents" => CentsDrop.new}} )
395
+ assert_equal 100, @context['cents.cents.cents.amount']
396
+ end
397
+
398
+ def test_drop_with_variable_called_only_once
399
+ @context['counter'] = CounterDrop.new
400
+
401
+ assert_equal 1, @context['counter.count']
402
+ assert_equal 2, @context['counter.count']
403
+ assert_equal 3, @context['counter.count']
404
+ end
405
+
406
+ def test_drop_with_key_called_only_once
407
+ @context['counter'] = CounterDrop.new
408
+
409
+ assert_equal 1, @context['counter["count"]']
410
+ assert_equal 2, @context['counter["count"]']
411
+ assert_equal 3, @context['counter["count"]']
412
+ end
413
+
414
+ def test_proc_as_variable
415
+ @context['dynamic'] = Proc.new { 'Hello' }
416
+
417
+ assert_equal 'Hello', @context['dynamic']
418
+ end
419
+
420
+ def test_lambda_as_variable
421
+ @context['dynamic'] = proc { 'Hello' }
422
+
423
+ assert_equal 'Hello', @context['dynamic']
424
+ end
425
+
426
+ def test_nested_lambda_as_variable
427
+ @context['dynamic'] = { "lambda" => proc { 'Hello' } }
428
+
429
+ assert_equal 'Hello', @context['dynamic.lambda']
430
+ end
431
+
432
+ def test_array_containing_lambda_as_variable
433
+ @context['dynamic'] = [1,2, proc { 'Hello' } ,4,5]
434
+
435
+ assert_equal 'Hello', @context['dynamic[2]']
436
+ end
437
+
438
+ def test_lambda_is_called_once
439
+ @context['callcount'] = proc { @global ||= 0; @global += 1; @global.to_s }
440
+
441
+ assert_equal '1', @context['callcount']
442
+ assert_equal '1', @context['callcount']
443
+ assert_equal '1', @context['callcount']
444
+
445
+ @global = nil
446
+ end
447
+
448
+ def test_nested_lambda_is_called_once
449
+ @context['callcount'] = { "lambda" => proc { @global ||= 0; @global += 1; @global.to_s } }
450
+
451
+ assert_equal '1', @context['callcount.lambda']
452
+ assert_equal '1', @context['callcount.lambda']
453
+ assert_equal '1', @context['callcount.lambda']
454
+
455
+ @global = nil
456
+ end
457
+
458
+ def test_lambda_in_array_is_called_once
459
+ @context['callcount'] = [1,2, proc { @global ||= 0; @global += 1; @global.to_s } ,4,5]
460
+
461
+ assert_equal '1', @context['callcount[2]']
462
+ assert_equal '1', @context['callcount[2]']
463
+ assert_equal '1', @context['callcount[2]']
464
+
465
+ @global = nil
466
+ end
467
+
468
+ def test_access_to_context_from_proc
469
+ @context.registers[:magic] = 345392
470
+
471
+ @context['magic'] = proc { @context.registers[:magic] }
472
+
473
+ assert_equal 345392, @context['magic']
474
+ end
475
+
476
+ def test_to_liquid_and_context_at_first_level
477
+ @context['category'] = Category.new("foobar")
478
+ assert_kind_of CategoryDrop, @context['category']
479
+ assert_equal @context, @context['category'].context
480
+ end
481
+
482
+ end