liquid 2.6.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +46 -13
  3. data/README.md +27 -2
  4. data/lib/liquid/block.rb +85 -51
  5. data/lib/liquid/block_body.rb +123 -0
  6. data/lib/liquid/condition.rb +26 -15
  7. data/lib/liquid/context.rb +106 -140
  8. data/lib/liquid/document.rb +3 -3
  9. data/lib/liquid/drop.rb +17 -1
  10. data/lib/liquid/errors.rb +50 -2
  11. data/lib/liquid/expression.rb +33 -0
  12. data/lib/liquid/file_system.rb +17 -6
  13. data/lib/liquid/i18n.rb +39 -0
  14. data/lib/liquid/interrupts.rb +1 -1
  15. data/lib/liquid/lexer.rb +51 -0
  16. data/lib/liquid/locales/en.yml +22 -0
  17. data/lib/liquid/parser.rb +90 -0
  18. data/lib/liquid/parser_switching.rb +31 -0
  19. data/lib/liquid/profiler/hooks.rb +23 -0
  20. data/lib/liquid/profiler.rb +159 -0
  21. data/lib/liquid/range_lookup.rb +22 -0
  22. data/lib/liquid/standardfilters.rb +143 -55
  23. data/lib/liquid/strainer.rb +14 -4
  24. data/lib/liquid/tag.rb +25 -9
  25. data/lib/liquid/tags/assign.rb +12 -9
  26. data/lib/liquid/tags/break.rb +1 -1
  27. data/lib/liquid/tags/capture.rb +10 -8
  28. data/lib/liquid/tags/case.rb +13 -13
  29. data/lib/liquid/tags/comment.rb +9 -2
  30. data/lib/liquid/tags/continue.rb +1 -4
  31. data/lib/liquid/tags/cycle.rb +5 -7
  32. data/lib/liquid/tags/decrement.rb +3 -4
  33. data/lib/liquid/tags/for.rb +69 -36
  34. data/lib/liquid/tags/if.rb +52 -25
  35. data/lib/liquid/tags/ifchanged.rb +3 -3
  36. data/lib/liquid/tags/include.rb +19 -8
  37. data/lib/liquid/tags/increment.rb +4 -8
  38. data/lib/liquid/tags/raw.rb +4 -7
  39. data/lib/liquid/tags/table_row.rb +73 -0
  40. data/lib/liquid/tags/unless.rb +2 -4
  41. data/lib/liquid/template.rb +124 -14
  42. data/lib/liquid/token.rb +18 -0
  43. data/lib/liquid/utils.rb +13 -4
  44. data/lib/liquid/variable.rb +103 -25
  45. data/lib/liquid/variable_lookup.rb +78 -0
  46. data/lib/liquid/version.rb +1 -1
  47. data/lib/liquid.rb +19 -11
  48. data/test/fixtures/en_locale.yml +9 -0
  49. data/test/{liquid → integration}/assign_test.rb +18 -1
  50. data/test/integration/blank_test.rb +106 -0
  51. data/test/{liquid → integration}/capture_test.rb +3 -3
  52. data/test/integration/context_test.rb +32 -0
  53. data/test/integration/drop_test.rb +271 -0
  54. data/test/integration/error_handling_test.rb +207 -0
  55. data/test/{liquid → integration}/filter_test.rb +11 -11
  56. data/test/integration/hash_ordering_test.rb +23 -0
  57. data/test/{liquid → integration}/output_test.rb +13 -13
  58. data/test/integration/parsing_quirks_test.rb +116 -0
  59. data/test/integration/render_profiling_test.rb +154 -0
  60. data/test/{liquid → integration}/security_test.rb +10 -10
  61. data/test/{liquid → integration}/standard_filter_test.rb +148 -32
  62. data/test/{liquid → integration}/tags/break_tag_test.rb +1 -1
  63. data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -1
  64. data/test/{liquid → integration}/tags/for_tag_test.rb +80 -2
  65. data/test/{liquid → integration}/tags/if_else_tag_test.rb +24 -21
  66. data/test/integration/tags/include_tag_test.rb +234 -0
  67. data/test/{liquid → integration}/tags/increment_tag_test.rb +1 -1
  68. data/test/{liquid → integration}/tags/raw_tag_test.rb +2 -1
  69. data/test/{liquid → integration}/tags/standard_tag_test.rb +28 -26
  70. data/test/integration/tags/statements_test.rb +113 -0
  71. data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +5 -5
  72. data/test/{liquid → integration}/tags/unless_else_tag_test.rb +1 -1
  73. data/test/{liquid → integration}/template_test.rb +81 -45
  74. data/test/integration/variable_test.rb +82 -0
  75. data/test/test_helper.rb +73 -20
  76. data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +2 -5
  77. data/test/{liquid/condition_test.rb → unit/condition_unit_test.rb} +23 -1
  78. data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +39 -25
  79. data/test/{liquid/file_system_test.rb → unit/file_system_unit_test.rb} +11 -5
  80. data/test/unit/i18n_unit_test.rb +37 -0
  81. data/test/unit/lexer_unit_test.rb +48 -0
  82. data/test/{liquid/module_ex_test.rb → unit/module_ex_unit_test.rb} +7 -7
  83. data/test/unit/parser_unit_test.rb +82 -0
  84. data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +3 -3
  85. data/test/{liquid/strainer_test.rb → unit/strainer_unit_test.rb} +20 -1
  86. data/test/unit/tag_unit_test.rb +16 -0
  87. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  88. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  89. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  90. data/test/unit/template_unit_test.rb +69 -0
  91. data/test/unit/tokenizer_unit_test.rb +38 -0
  92. data/test/unit/variable_unit_test.rb +139 -0
  93. metadata +135 -67
  94. data/lib/extras/liquid_view.rb +0 -51
  95. data/lib/liquid/htmltags.rb +0 -73
  96. data/test/liquid/drop_test.rb +0 -180
  97. data/test/liquid/error_handling_test.rb +0 -81
  98. data/test/liquid/hash_ordering_test.rb +0 -25
  99. data/test/liquid/parsing_quirks_test.rb +0 -52
  100. data/test/liquid/tags/include_tag_test.rb +0 -166
  101. data/test/liquid/tags/statements_test.rb +0 -134
  102. data/test/liquid/variable_test.rb +0 -186
@@ -6,21 +6,21 @@ module SecurityFilter
6
6
  end
7
7
  end
8
8
 
9
- class SecurityTest < Test::Unit::TestCase
9
+ class SecurityTest < Minitest::Test
10
10
  include Liquid
11
11
 
12
12
  def test_no_instance_eval
13
13
  text = %( {{ '1+1' | instance_eval }} )
14
14
  expected = %| 1+1 |
15
15
 
16
- assert_equal expected, Template.parse(text).render(@assigns)
16
+ assert_equal expected, Template.parse(text).render!(@assigns)
17
17
  end
18
18
 
19
19
  def test_no_existing_instance_eval
20
20
  text = %( {{ '1+1' | __instance_eval__ }} )
21
21
  expected = %| 1+1 |
22
22
 
23
- assert_equal expected, Template.parse(text).render(@assigns)
23
+ assert_equal expected, Template.parse(text).render!(@assigns)
24
24
  end
25
25
 
26
26
 
@@ -28,7 +28,7 @@ class SecurityTest < Test::Unit::TestCase
28
28
  text = %( {{ '1+1' | instance_eval }} )
29
29
  expected = %| 1+1 |
30
30
 
31
- assert_equal expected, Template.parse(text).render(@assigns)
31
+ assert_equal expected, Template.parse(text).render!(@assigns)
32
32
  end
33
33
 
34
34
 
@@ -36,7 +36,7 @@ class SecurityTest < Test::Unit::TestCase
36
36
  text = %( {{ '1+1' | add_one | instance_eval }} )
37
37
  expected = %| 1+1 + 1 |
38
38
 
39
- assert_equal expected, Template.parse(text).render(@assigns, :filters => SecurityFilter)
39
+ assert_equal expected, Template.parse(text).render!(@assigns, :filters => SecurityFilter)
40
40
  end
41
41
 
42
42
  def test_does_not_add_filters_to_symbol_table
@@ -47,17 +47,17 @@ class SecurityTest < Test::Unit::TestCase
47
47
  template = Template.parse(test)
48
48
  assert_equal [], (Symbol.all_symbols - current_symbols)
49
49
 
50
- template.render
50
+ template.render!
51
51
  assert_equal [], (Symbol.all_symbols - current_symbols)
52
52
  end
53
53
 
54
54
  def test_does_not_add_drop_methods_to_symbol_table
55
55
  current_symbols = Symbol.all_symbols
56
56
 
57
- drop = Drop.new
58
- drop.invoke_drop("custom_method_1")
59
- drop.invoke_drop("custom_method_2")
60
- drop.invoke_drop("custom_method_3")
57
+ assigns = { 'drop' => Drop.new }
58
+ assert_equal "", Template.parse("{{ drop.custom_method_1 }}", assigns).render!
59
+ assert_equal "", Template.parse("{{ drop.custom_method_2 }}", assigns).render!
60
+ assert_equal "", Template.parse("{{ drop.custom_method_3 }}", assigns).render!
61
61
 
62
62
  assert_equal [], (Symbol.all_symbols - current_symbols)
63
63
  end
@@ -7,6 +7,8 @@ class Filters
7
7
  end
8
8
 
9
9
  class TestThing
10
+ attr_reader :foo
11
+
10
12
  def initialize
11
13
  @foo = 0
12
14
  end
@@ -15,6 +17,10 @@ class TestThing
15
17
  "woot: #{@foo}"
16
18
  end
17
19
 
20
+ def [](whatever)
21
+ to_s
22
+ end
23
+
18
24
  def to_liquid
19
25
  @foo += 1
20
26
  self
@@ -27,7 +33,15 @@ class TestDrop < Liquid::Drop
27
33
  end
28
34
  end
29
35
 
30
- class StandardFiltersTest < Test::Unit::TestCase
36
+ class TestEnumerable < Liquid::Drop
37
+ include Enumerable
38
+
39
+ def each(&block)
40
+ [ { "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 } ].each(&block)
41
+ end
42
+ end
43
+
44
+ class StandardFiltersTest < Minitest::Test
31
45
  include Liquid
32
46
 
33
47
  def setup
@@ -50,9 +64,32 @@ class StandardFiltersTest < Test::Unit::TestCase
50
64
  assert_equal '', @filters.upcase(nil)
51
65
  end
52
66
 
53
- def test_upcase
54
- assert_equal 'TESTING', @filters.upcase("Testing")
55
- assert_equal '', @filters.upcase(nil)
67
+ def test_slice
68
+ assert_equal 'oob', @filters.slice('foobar', 1, 3)
69
+ assert_equal 'oobar', @filters.slice('foobar', 1, 1000)
70
+ assert_equal '', @filters.slice('foobar', 1, 0)
71
+ assert_equal 'o', @filters.slice('foobar', 1, 1)
72
+ assert_equal 'bar', @filters.slice('foobar', 3, 3)
73
+ assert_equal 'ar', @filters.slice('foobar', -2, 2)
74
+ assert_equal 'ar', @filters.slice('foobar', -2, 1000)
75
+ assert_equal 'r', @filters.slice('foobar', -1)
76
+ assert_equal '', @filters.slice(nil, 0)
77
+ assert_equal '', @filters.slice('foobar', 100, 10)
78
+ assert_equal '', @filters.slice('foobar', -100, 10)
79
+ end
80
+
81
+ def test_slice_on_arrays
82
+ input = 'foobar'.split(//)
83
+ assert_equal %w{o o b}, @filters.slice(input, 1, 3)
84
+ assert_equal %w{o o b a r}, @filters.slice(input, 1, 1000)
85
+ assert_equal %w{}, @filters.slice(input, 1, 0)
86
+ assert_equal %w{o}, @filters.slice(input, 1, 1)
87
+ assert_equal %w{b a r}, @filters.slice(input, 3, 3)
88
+ assert_equal %w{a r}, @filters.slice(input, -2, 2)
89
+ assert_equal %w{a r}, @filters.slice(input, -2, 1000)
90
+ assert_equal %w{r}, @filters.slice(input, -1)
91
+ assert_equal %w{}, @filters.slice(input, 100, 10)
92
+ assert_equal %w{}, @filters.slice(input, -100, 10)
56
93
  end
57
94
 
58
95
  def test_truncate
@@ -63,12 +100,13 @@ class StandardFiltersTest < Test::Unit::TestCase
63
100
  assert_equal "测试...", @filters.truncate("测试测试测试测试", 5)
64
101
  end
65
102
 
66
- def test_strip
103
+ def test_split
67
104
  assert_equal ['12','34'], @filters.split('12~34', '~')
68
105
  assert_equal ['A? ',' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~')
69
106
  assert_equal ['A?Z'], @filters.split('A?Z', '~')
70
107
  # Regexp works although Liquid does not support.
71
108
  assert_equal ['A','Z'], @filters.split('AxZ', /x/)
109
+ assert_equal [], @filters.split(nil, ' ')
72
110
  end
73
111
 
74
112
  def test_escape
@@ -77,7 +115,12 @@ class StandardFiltersTest < Test::Unit::TestCase
77
115
  end
78
116
 
79
117
  def test_escape_once
80
- assert_equal '&lt;strong&gt;', @filters.escape_once(@filters.escape('<strong>'))
118
+ assert_equal '&lt;strong&gt;Hulk&lt;/strong&gt;', @filters.escape_once('&lt;strong&gt;Hulk</strong>')
119
+ end
120
+
121
+ def test_url_encode
122
+ assert_equal 'foo%2B1%40example.com', @filters.url_encode('foo+1@example.com')
123
+ assert_equal nil, @filters.url_encode(nil)
81
124
  end
82
125
 
83
126
  def test_truncatewords
@@ -108,10 +151,32 @@ class StandardFiltersTest < Test::Unit::TestCase
108
151
  assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
109
152
  end
110
153
 
154
+ def test_legacy_sort_hash
155
+ assert_equal [{a:1, b:2}], @filters.sort({a:1, b:2})
156
+ end
157
+
158
+ def test_numerical_vs_lexicographical_sort
159
+ assert_equal [2, 10], @filters.sort([10, 2])
160
+ assert_equal [{"a" => 2}, {"a" => 10}], @filters.sort([{"a" => 10}, {"a" => 2}], "a")
161
+ assert_equal ["10", "2"], @filters.sort(["10", "2"])
162
+ assert_equal [{"a" => "10"}, {"a" => "2"}], @filters.sort([{"a" => "10"}, {"a" => "2"}], "a")
163
+ end
164
+
165
+ def test_uniq
166
+ assert_equal [1,3,2,4], @filters.uniq([1,1,3,2,3,1,4,3,2,1])
167
+ assert_equal [{"a" => 1}, {"a" => 3}, {"a" => 2}], @filters.uniq([{"a" => 1}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
168
+ testdrop = TestDrop.new
169
+ assert_equal [testdrop], @filters.uniq([testdrop, TestDrop.new], 'test')
170
+ end
171
+
111
172
  def test_reverse
112
173
  assert_equal [4,3,2,1], @filters.reverse([1,2,3,4])
113
174
  end
114
175
 
176
+ def test_legacy_reverse_hash
177
+ assert_equal [{a:1, b:2}], @filters.reverse(a:1, b:2)
178
+ end
179
+
115
180
  def test_map
116
181
  assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
117
182
  assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
@@ -119,20 +184,50 @@ class StandardFiltersTest < Test::Unit::TestCase
119
184
  end
120
185
 
121
186
  def test_map_doesnt_call_arbitrary_stuff
122
- assert_equal "", Liquid::Template.parse('{{ "foo" | map: "__id__" }}').render
123
- assert_equal "", Liquid::Template.parse('{{ "foo" | map: "inspect" }}').render
187
+ assert_template_result "", '{{ "foo" | map: "__id__" }}'
188
+ assert_template_result "", '{{ "foo" | map: "inspect" }}'
124
189
  end
125
190
 
126
191
  def test_map_calls_to_liquid
127
192
  t = TestThing.new
128
- assert_equal "woot: 1", Liquid::Template.parse('{{ foo }}').render("foo" => t)
193
+ assert_template_result "woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t]
194
+ end
195
+
196
+ def test_map_on_hashes
197
+ assert_template_result "4217", '{{ thing | map: "foo" | map: "bar" }}',
198
+ "thing" => { "foo" => [ { "bar" => 42 }, { "bar" => 17 } ] }
199
+ end
200
+
201
+ def test_legacy_map_on_hashes_with_dynamic_key
202
+ template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
203
+ hash = { "foo" => { "bar" => 42 } }
204
+ assert_template_result "42", template, "thing" => hash
205
+ end
206
+
207
+ def test_sort_calls_to_liquid
208
+ t = TestThing.new
209
+ Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t])
210
+ assert t.foo > 0
129
211
  end
130
212
 
131
213
  def test_map_over_proc
132
214
  drop = TestDrop.new
133
215
  p = Proc.new{ drop }
134
216
  templ = '{{ procs | map: "test" }}'
135
- assert_equal "testfoo", Liquid::Template.parse(templ).render("procs" => [p])
217
+ assert_template_result "testfoo", templ, "procs" => [p]
218
+ end
219
+
220
+ def test_map_works_on_enumerables
221
+ assert_template_result "123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new
222
+ end
223
+
224
+ def test_sort_works_on_enumerables
225
+ assert_template_result "213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new
226
+ end
227
+
228
+ def test_first_and_last_call_to_liquid
229
+ assert_template_result 'foobar', '{{ foo | first }}', 'foo' => [ThingWithToLiquid.new]
230
+ assert_template_result 'foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new]
136
231
  end
137
232
 
138
233
  def test_date
@@ -157,13 +252,10 @@ class StandardFiltersTest < Test::Unit::TestCase
157
252
 
158
253
  assert_equal nil, @filters.date(nil, "%B")
159
254
 
160
- with_timezone("UTC") do
161
- assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y")
162
- assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
163
- end
255
+ assert_equal "07/05/2006", @filters.date(1152098955, "%m/%d/%Y")
256
+ assert_equal "07/05/2006", @filters.date("1152098955", "%m/%d/%Y")
164
257
  end
165
258
 
166
-
167
259
  def test_first_last
168
260
  assert_equal 1, @filters.first([1,2,3])
169
261
  assert_equal 3, @filters.last([1,2,3])
@@ -187,6 +279,21 @@ class StandardFiltersTest < Test::Unit::TestCase
187
279
  assert_template_result 'foobar', "{{ 'foo|bar' | remove: '|' }}"
188
280
  end
189
281
 
282
+ def test_strip
283
+ assert_template_result 'ab c', "{{ source | strip }}", 'source' => " ab c "
284
+ assert_template_result 'ab c', "{{ source | strip }}", 'source' => " \tab c \n \t"
285
+ end
286
+
287
+ def test_lstrip
288
+ assert_template_result 'ab c ', "{{ source | lstrip }}", 'source' => " ab c "
289
+ assert_template_result "ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t"
290
+ end
291
+
292
+ def test_rstrip
293
+ assert_template_result " ab c", "{{ source | rstrip }}", 'source' => " ab c "
294
+ assert_template_result " \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t"
295
+ end
296
+
190
297
  def test_strip_newlines
191
298
  assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc"
192
299
  assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc"
@@ -210,9 +317,6 @@ class StandardFiltersTest < Test::Unit::TestCase
210
317
  assert_template_result "12", "{{ 3 | times:4 }}"
211
318
  assert_template_result "0", "{{ 'foo' | times:4 }}"
212
319
 
213
- # Ruby v1.9.2-rc1, or higher, backwards compatible Float test
214
- assert_match(/(6\.3)|(6\.(0{13})1)/, Template.parse("{{ '2.1' | times:3 }}").render)
215
-
216
320
  assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
217
321
 
218
322
  assert_template_result "7.25", "{{ 0.0725 | times:100 }}"
@@ -222,11 +326,8 @@ class StandardFiltersTest < Test::Unit::TestCase
222
326
  assert_template_result "4", "{{ 12 | divided_by:3 }}"
223
327
  assert_template_result "4", "{{ 14 | divided_by:3 }}"
224
328
 
225
- # Ruby v1.9.2-rc1, or higher, backwards compatible Float test
226
- assert_match(/4\.(6{13,14})7/, Template.parse("{{ 14 | divided_by:'3.0' }}").render)
227
-
228
329
  assert_template_result "5", "{{ 15 | divided_by:3 }}"
229
- assert_template_result "Liquid error: divided by 0", "{{ 5 | divided_by:0 }}"
330
+ assert_equal "Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render
230
331
 
231
332
  assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}"
232
333
  end
@@ -235,6 +336,22 @@ class StandardFiltersTest < Test::Unit::TestCase
235
336
  assert_template_result "1", "{{ 3 | modulo:2 }}"
236
337
  end
237
338
 
339
+ def test_round
340
+ assert_template_result "5", "{{ input | round }}", 'input' => 4.6
341
+ assert_template_result "4", "{{ '4.3' | round }}"
342
+ assert_template_result "4.56", "{{ input | round: 2 }}", 'input' => 4.5612
343
+ end
344
+
345
+ def test_ceil
346
+ assert_template_result "5", "{{ input | ceil }}", 'input' => 4.6
347
+ assert_template_result "5", "{{ '4.3' | ceil }}"
348
+ end
349
+
350
+ def test_floor
351
+ assert_template_result "4", "{{ input | floor }}", 'input' => 4.6
352
+ assert_template_result "4", "{{ '4.3' | floor }}"
353
+ end
354
+
238
355
  def test_append
239
356
  assigns = {'a' => 'bc', 'b' => 'd' }
240
357
  assert_template_result('bcd',"{{ a | append: 'd'}}",assigns)
@@ -247,17 +364,16 @@ class StandardFiltersTest < Test::Unit::TestCase
247
364
  assert_template_result('abc',"{{ a | prepend: b}}",assigns)
248
365
  end
249
366
 
250
- def test_cannot_access_private_methods
251
- assert_template_result('a',"{{ 'a' | to_number }}")
367
+ def test_default
368
+ assert_equal "foo", @filters.default("foo", "bar")
369
+ assert_equal "bar", @filters.default(nil, "bar")
370
+ assert_equal "bar", @filters.default("", "bar")
371
+ assert_equal "bar", @filters.default(false, "bar")
372
+ assert_equal "bar", @filters.default([], "bar")
373
+ assert_equal "bar", @filters.default({}, "bar")
252
374
  end
253
375
 
254
- private
255
-
256
- def with_timezone(tz)
257
- old_tz = ENV['TZ']
258
- ENV['TZ'] = tz
259
- yield
260
- ensure
261
- ENV['TZ'] = old_tz
376
+ def test_cannot_access_private_methods
377
+ assert_template_result('a',"{{ 'a' | to_number }}")
262
378
  end
263
379
  end # StandardFiltersTest
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class BreakTagTest < Test::Unit::TestCase
3
+ class BreakTagTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  # tests that no weird errors are raised if break is called outside of a
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ContinueTagTest < Test::Unit::TestCase
3
+ class ContinueTagTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  # tests that no weird errors are raised if continue is called outside of a
@@ -1,6 +1,12 @@
1
1
  require 'test_helper'
2
2
 
3
- class ForTagTest < Test::Unit::TestCase
3
+ class ThingWithValue < Liquid::Drop
4
+ def value
5
+ 3
6
+ end
7
+ end
8
+
9
+ class ForTagTest < Minitest::Test
4
10
  include Liquid
5
11
 
6
12
  def test_for
@@ -34,6 +40,20 @@ HERE
34
40
  assert_template_result(' 1 2 3 ','{%for item in (1..3) %} {{item}} {%endfor%}')
35
41
  end
36
42
 
43
+ def test_for_with_variable_range
44
+ assert_template_result(' 1 2 3 ','{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
45
+ end
46
+
47
+ def test_for_with_hash_value_range
48
+ foobar = { "value" => 3 }
49
+ assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
50
+ end
51
+
52
+ def test_for_with_drop_value_range
53
+ foobar = ThingWithValue.new
54
+ assert_template_result(' 1 2 3 ','{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
55
+ end
56
+
37
57
  def test_for_with_variable
38
58
  assert_template_result(' 1 2 3 ','{%for item in array%} {{item}} {%endfor%}','array' => [1,2,3])
39
59
  assert_template_result('123','{%for item in array%}{{item}}{%endfor%}','array' => [1,2,3])
@@ -283,7 +303,7 @@ HERE
283
303
  end
284
304
 
285
305
  def test_bad_variable_naming_in_for_loop
286
- assert_raise(Liquid::SyntaxError) do
306
+ assert_raises(Liquid::SyntaxError) do
287
307
  Liquid::Template.parse('{% for a/b in x %}{% endfor %}')
288
308
  end
289
309
  end
@@ -294,4 +314,62 @@ HERE
294
314
  assigns = {'items' => [1,2,3,4,5]}
295
315
  assert_template_result(expected, template, assigns)
296
316
  end
317
+
318
+ class LoaderDrop < Liquid::Drop
319
+ attr_accessor :each_called, :load_slice_called
320
+
321
+ def initialize(data)
322
+ @data = data
323
+ end
324
+
325
+ def each
326
+ @each_called = true
327
+ @data.each { |el| yield el }
328
+ end
329
+
330
+ def load_slice(from, to)
331
+ @load_slice_called = true
332
+ @data[(from..to-1)]
333
+ end
334
+ end
335
+
336
+ def test_iterate_with_each_when_no_limit_applied
337
+ loader = LoaderDrop.new([1,2,3,4,5])
338
+ assigns = {'items' => loader}
339
+ expected = '12345'
340
+ template = '{% for item in items %}{{item}}{% endfor %}'
341
+ assert_template_result(expected, template, assigns)
342
+ assert loader.each_called
343
+ assert !loader.load_slice_called
344
+ end
345
+
346
+ def test_iterate_with_load_slice_when_limit_applied
347
+ loader = LoaderDrop.new([1,2,3,4,5])
348
+ assigns = {'items' => loader}
349
+ expected = '1'
350
+ template = '{% for item in items limit:1 %}{{item}}{% endfor %}'
351
+ assert_template_result(expected, template, assigns)
352
+ assert !loader.each_called
353
+ assert loader.load_slice_called
354
+ end
355
+
356
+ def test_iterate_with_load_slice_when_limit_and_offset_applied
357
+ loader = LoaderDrop.new([1,2,3,4,5])
358
+ assigns = {'items' => loader}
359
+ expected = '34'
360
+ template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
361
+ assert_template_result(expected, template, assigns)
362
+ assert !loader.each_called
363
+ assert loader.load_slice_called
364
+ end
365
+
366
+ def test_iterate_with_load_slice_returns_same_results_as_without
367
+ loader = LoaderDrop.new([1,2,3,4,5])
368
+ loader_assigns = {'items' => loader}
369
+ array_assigns = {'items' => [1,2,3,4,5]}
370
+ expected = '34'
371
+ template = '{% for item in items offset:2 limit:2 %}{{item}}{% endfor %}'
372
+ assert_template_result(expected, template, loader_assigns)
373
+ assert_template_result(expected, template, array_assigns)
374
+ end
297
375
  end
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class IfElseTagTest < Test::Unit::TestCase
3
+ class IfElseTagTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_if
@@ -10,6 +10,11 @@ class IfElseTagTest < Test::Unit::TestCase
10
10
  assert_template_result(' you rock ?','{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
11
11
  end
12
12
 
13
+ def test_literal_comparisons
14
+ assert_template_result(' NO ','{% assign v = false %}{% if v %} YES {% else %} NO {% endif %}')
15
+ assert_template_result(' YES ','{% assign v = nil %}{% if v == nil %} YES {% else %} NO {% endif %}')
16
+ end
17
+
13
18
  def test_if_else
14
19
  assert_template_result(' YES ','{% if false %} NO {% else %} YES {% endif %}')
15
20
  assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}')
@@ -37,25 +42,19 @@ class IfElseTagTest < Test::Unit::TestCase
37
42
  end
38
43
 
39
44
  def test_comparison_of_strings_containing_and_or_or
40
- assert_nothing_raised do
41
- awful_markup = "a == 'and' and b == 'or' and c == 'foo and bar' and d == 'bar or baz' and e == 'foo' and foo and bar"
42
- assigns = {'a' => 'and', 'b' => 'or', 'c' => 'foo and bar', 'd' => 'bar or baz', 'e' => 'foo', 'foo' => true, 'bar' => true}
43
- assert_template_result(' YES ',"{% if #{awful_markup} %} YES {% endif %}", assigns)
44
- end
45
+ awful_markup = "a == 'and' and b == 'or' and c == 'foo and bar' and d == 'bar or baz' and e == 'foo' and foo and bar"
46
+ assigns = {'a' => 'and', 'b' => 'or', 'c' => 'foo and bar', 'd' => 'bar or baz', 'e' => 'foo', 'foo' => true, 'bar' => true}
47
+ assert_template_result(' YES ',"{% if #{awful_markup} %} YES {% endif %}", assigns)
45
48
  end
46
49
 
47
50
  def test_comparison_of_expressions_starting_with_and_or_or
48
51
  assigns = {'order' => {'items_count' => 0}, 'android' => {'name' => 'Roy'}}
49
- assert_nothing_raised do
50
- assert_template_result( "YES",
51
- "{% if android.name == 'Roy' %}YES{% endif %}",
52
- assigns)
53
- end
54
- assert_nothing_raised do
55
- assert_template_result( "YES",
56
- "{% if order.items_count == 0 %}YES{% endif %}",
57
- assigns)
58
- end
52
+ assert_template_result( "YES",
53
+ "{% if android.name == 'Roy' %}YES{% endif %}",
54
+ assigns)
55
+ assert_template_result( "YES",
56
+ "{% if order.items_count == 0 %}YES{% endif %}",
57
+ assigns)
59
58
  end
60
59
 
61
60
  def test_if_and
@@ -135,32 +134,36 @@ class IfElseTagTest < Test::Unit::TestCase
135
134
  end
136
135
 
137
136
  def test_syntax_error_no_variable
138
- assert_raise(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')}
137
+ assert_raises(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')}
139
138
  end
140
139
 
141
140
  def test_syntax_error_no_expression
142
- assert_raise(SyntaxError) { assert_template_result('', '{% if %}') }
141
+ assert_raises(SyntaxError) { assert_template_result('', '{% if %}') }
143
142
  end
144
143
 
145
144
  def test_if_with_custom_condition
145
+ original_op = Condition.operators['contains']
146
146
  Condition.operators['contains'] = :[]
147
147
 
148
148
  assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %}))
149
149
  assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %}))
150
150
  ensure
151
- Condition.operators.delete 'contains'
151
+ Condition.operators['contains'] = original_op
152
152
  end
153
153
 
154
154
  def test_operators_are_ignored_unless_isolated
155
+ original_op = Condition.operators['contains']
155
156
  Condition.operators['contains'] = :[]
156
157
 
157
158
  assert_template_result('yes',
158
159
  %({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
160
+ ensure
161
+ Condition.operators['contains'] = original_op
159
162
  end
160
163
 
161
164
  def test_operators_are_whitelisted
162
- assert_raise(SyntaxError) do
165
+ assert_raises(SyntaxError) do
163
166
  assert_template_result('', %({% if 1 or throw or or 1 %}yes{% endif %}))
164
167
  end
165
168
  end
166
- end # IfElseTest
169
+ end