drnic-liquid 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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