liquid 2.2.2 → 2.3.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 (51) hide show
  1. data/{History.txt → History.md} +26 -23
  2. data/README.md +18 -16
  3. data/lib/liquid.rb +1 -4
  4. data/lib/liquid/block.rb +2 -2
  5. data/lib/liquid/context.rb +29 -33
  6. data/lib/liquid/drop.rb +11 -13
  7. data/lib/liquid/extensions.rb +13 -7
  8. data/lib/liquid/file_system.rb +2 -2
  9. data/lib/liquid/htmltags.rb +5 -4
  10. data/lib/liquid/standardfilters.rb +12 -1
  11. data/lib/liquid/strainer.rb +1 -1
  12. data/lib/liquid/tags/capture.rb +1 -1
  13. data/lib/liquid/tags/case.rb +4 -8
  14. data/lib/liquid/tags/decrement.rb +39 -0
  15. data/lib/liquid/tags/for.rb +20 -5
  16. data/lib/liquid/tags/include.rb +21 -12
  17. data/lib/liquid/tags/increment.rb +35 -0
  18. data/lib/liquid/tags/raw.rb +21 -0
  19. data/lib/liquid/tags/unless.rb +5 -5
  20. data/lib/liquid/template.rb +3 -2
  21. data/lib/liquid/variable.rb +1 -1
  22. data/test/liquid/assign_test.rb +15 -0
  23. data/test/liquid/block_test.rb +58 -0
  24. data/test/liquid/capture_test.rb +40 -0
  25. data/test/liquid/condition_test.rb +122 -0
  26. data/test/liquid/context_test.rb +478 -0
  27. data/test/liquid/drop_test.rb +162 -0
  28. data/test/liquid/error_handling_test.rb +81 -0
  29. data/test/liquid/file_system_test.rb +29 -0
  30. data/test/liquid/filter_test.rb +106 -0
  31. data/test/liquid/module_ex_test.rb +87 -0
  32. data/test/liquid/output_test.rb +116 -0
  33. data/test/liquid/parsing_quirks_test.rb +52 -0
  34. data/test/liquid/regexp_test.rb +44 -0
  35. data/test/liquid/security_test.rb +41 -0
  36. data/test/liquid/standard_filter_test.rb +191 -0
  37. data/test/liquid/strainer_test.rb +25 -0
  38. data/test/liquid/tags/html_tag_test.rb +29 -0
  39. data/test/liquid/tags/if_else_tag_test.rb +160 -0
  40. data/test/liquid/tags/include_tag_test.rb +139 -0
  41. data/test/liquid/tags/increment_tag_test.rb +24 -0
  42. data/test/liquid/tags/raw_tag_test.rb +15 -0
  43. data/test/liquid/tags/standard_tag_test.rb +461 -0
  44. data/test/liquid/tags/statements_test.rb +134 -0
  45. data/test/liquid/tags/unless_else_tag_test.rb +26 -0
  46. data/test/liquid/template_test.rb +74 -0
  47. data/test/liquid/variable_test.rb +170 -0
  48. data/test/test_helper.rb +29 -0
  49. metadata +67 -16
  50. data/Manifest.txt +0 -34
  51. data/lib/liquid/tags/literal.rb +0 -42
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class HtmlTagTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_html_table
7
+
8
+ assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
9
+ '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
10
+ 'numbers' => [1,2,3,4,5,6])
11
+
12
+ assert_template_result("<tr class=\"row1\">\n</tr>\n",
13
+ '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
14
+ 'numbers' => [])
15
+ end
16
+
17
+ def test_html_table_with_different_cols
18
+ assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td><td class=\"col4\"> 4 </td><td class=\"col5\"> 5 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 6 </td></tr>\n",
19
+ '{% tablerow n in numbers cols:5%} {{n}} {% endtablerow %}',
20
+ 'numbers' => [1,2,3,4,5,6])
21
+
22
+ end
23
+
24
+ def test_html_col_counter
25
+ assert_template_result("<tr class=\"row1\">\n<td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row2\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row3\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n",
26
+ '{% tablerow n in numbers cols:2%}{{tablerowloop.col}}{% endtablerow %}',
27
+ 'numbers' => [1,2,3,4,5,6])
28
+ end
29
+ end # HtmlTagTest
@@ -0,0 +1,160 @@
1
+ require 'test_helper'
2
+
3
+ class IfElseTagTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_if
7
+ assert_template_result(' ',' {% if false %} this text should not go into the output {% endif %} ')
8
+ assert_template_result(' this text should go into the output ',
9
+ ' {% if true %} this text should go into the output {% endif %} ')
10
+ assert_template_result(' you rock ?','{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
11
+ end
12
+
13
+ def test_if_else
14
+ assert_template_result(' YES ','{% if false %} NO {% else %} YES {% endif %}')
15
+ assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}')
16
+ assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% endif %}')
17
+ end
18
+
19
+ def test_if_boolean
20
+ assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => true)
21
+ end
22
+
23
+ def test_if_or
24
+ assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => true)
25
+ assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => false)
26
+ assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => false, 'b' => true)
27
+ assert_template_result('', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => false)
28
+
29
+ assert_template_result(' YES ','{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => true)
30
+ assert_template_result('', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => false)
31
+ end
32
+
33
+ def test_if_or_with_operators
34
+ assert_template_result(' YES ','{% if a == true or b == true %} YES {% endif %}', 'a' => true, 'b' => true)
35
+ assert_template_result(' YES ','{% if a == true or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
36
+ assert_template_result('','{% if a == false or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
37
+ end
38
+
39
+ 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
+ end
46
+
47
+ def test_comparison_of_expressions_starting_with_and_or_or
48
+ 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
59
+ end
60
+
61
+ def test_if_and
62
+ assert_template_result(' YES ','{% if true and true %} YES {% endif %}')
63
+ assert_template_result('','{% if false and true %} YES {% endif %}')
64
+ assert_template_result('','{% if false and true %} YES {% endif %}')
65
+ end
66
+
67
+
68
+ def test_hash_miss_generates_false
69
+ assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {})
70
+ end
71
+
72
+ def test_if_from_variable
73
+ assert_template_result('','{% if var %} NO {% endif %}', 'var' => false)
74
+ assert_template_result('','{% if var %} NO {% endif %}', 'var' => nil)
75
+ assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {'bar' => false})
76
+ assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {})
77
+ assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => nil)
78
+ assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => true)
79
+
80
+ assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => "text")
81
+ assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => true)
82
+ assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => 1)
83
+ assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => {})
84
+ assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => [])
85
+ assert_template_result(' YES ','{% if "foo" %} YES {% endif %}')
86
+ assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => true})
87
+ assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => "text"})
88
+ assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => 1 })
89
+ assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => {} })
90
+ assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => [] })
91
+
92
+ assert_template_result(' YES ','{% if var %} NO {% else %} YES {% endif %}', 'var' => false)
93
+ assert_template_result(' YES ','{% if var %} NO {% else %} YES {% endif %}', 'var' => nil)
94
+ assert_template_result(' YES ','{% if var %} YES {% else %} NO {% endif %}', 'var' => true)
95
+ assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% endif %}', 'var' => "text")
96
+
97
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {'bar' => false})
98
+ assert_template_result(' YES ','{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => {'bar' => true})
99
+ assert_template_result(' YES ','{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => {'bar' => "text"})
100
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {'notbar' => true})
101
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {})
102
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'notfoo' => {'bar' => true})
103
+ end
104
+
105
+ def test_nested_if
106
+ assert_template_result('', '{% if false %}{% if false %} NO {% endif %}{% endif %}')
107
+ assert_template_result('', '{% if false %}{% if true %} NO {% endif %}{% endif %}')
108
+ assert_template_result('', '{% if true %}{% if false %} NO {% endif %}{% endif %}')
109
+ assert_template_result(' YES ', '{% if true %}{% if true %} YES {% endif %}{% endif %}')
110
+
111
+ assert_template_result(' YES ', '{% if true %}{% if true %} YES {% else %} NO {% endif %}{% else %} NO {% endif %}')
112
+ assert_template_result(' YES ', '{% if true %}{% if false %} NO {% else %} YES {% endif %}{% else %} NO {% endif %}')
113
+ assert_template_result(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% endif %}{% else %} YES {% endif %}')
114
+
115
+ end
116
+
117
+ def test_comparisons_on_null
118
+ assert_template_result('','{% if null < 10 %} NO {% endif %}')
119
+ assert_template_result('','{% if null <= 10 %} NO {% endif %}')
120
+ assert_template_result('','{% if null >= 10 %} NO {% endif %}')
121
+ assert_template_result('','{% if null > 10 %} NO {% endif %}')
122
+
123
+ assert_template_result('','{% if 10 < null %} NO {% endif %}')
124
+ assert_template_result('','{% if 10 <= null %} NO {% endif %}')
125
+ assert_template_result('','{% if 10 >= null %} NO {% endif %}')
126
+ assert_template_result('','{% if 10 > null %} NO {% endif %}')
127
+ end
128
+
129
+ def test_else_if
130
+ assert_template_result('0','{% if 0 == 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
131
+ assert_template_result('1','{% if 0 != 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
132
+ assert_template_result('2','{% if 0 != 0 %}0{% elsif 1 != 1%}1{% else %}2{% endif %}')
133
+
134
+ assert_template_result('elsif','{% if false %}if{% elsif true %}elsif{% endif %}')
135
+ end
136
+
137
+ def test_syntax_error_no_variable
138
+ assert_raise(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')}
139
+ end
140
+
141
+ def test_syntax_error_no_expression
142
+ assert_raise(SyntaxError) { assert_template_result('', '{% if %}') }
143
+ end
144
+
145
+ def test_if_with_custom_condition
146
+ Condition.operators['contains'] = :[]
147
+
148
+ assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %}))
149
+ assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %}))
150
+ ensure
151
+ Condition.operators.delete 'contains'
152
+ end
153
+
154
+ def test_operators_are_ignored_unless_isolated
155
+ Condition.operators['contains'] = :[]
156
+
157
+ assert_template_result('yes',
158
+ %({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
159
+ end
160
+ end # IfElseTest
@@ -0,0 +1,139 @@
1
+ require 'test_helper'
2
+
3
+ class TestFileSystem
4
+ def read_template_file(template_path, context)
5
+ case template_path
6
+ when "product"
7
+ "Product: {{ product.title }} "
8
+
9
+ when "locale_variables"
10
+ "Locale: {{echo1}} {{echo2}}"
11
+
12
+ when "variant"
13
+ "Variant: {{ variant.title }}"
14
+
15
+ when "nested_template"
16
+ "{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
17
+
18
+ when "body"
19
+ "body {% include 'body_detail' %}"
20
+
21
+ when "nested_product_template"
22
+ "Product: {{ nested_product_template.title }} {%include 'details'%} "
23
+
24
+ when "recursively_nested_template"
25
+ "-{% include 'recursively_nested_template' %}"
26
+
27
+ when "pick_a_source"
28
+ "from TestFileSystem"
29
+
30
+ else
31
+ template_path
32
+ end
33
+ end
34
+ end
35
+
36
+ class OtherFileSystem
37
+ def read_template_file(template_path, context)
38
+ 'from OtherFileSystem'
39
+ end
40
+ end
41
+
42
+ class IncludeTagTest < Test::Unit::TestCase
43
+ include Liquid
44
+
45
+ def setup
46
+ Liquid::Template.file_system = TestFileSystem.new
47
+ end
48
+
49
+ def test_include_tag_looks_for_file_system_in_registers_first
50
+ assert_equal 'from OtherFileSystem',
51
+ Template.parse("{% include 'pick_a_source' %}").render({}, :registers => {:file_system => OtherFileSystem.new})
52
+ end
53
+
54
+
55
+ def test_include_tag_with
56
+ assert_equal "Product: Draft 151cm ",
57
+ Template.parse("{% include 'product' with products[0] %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
58
+ end
59
+
60
+ def test_include_tag_with_default_name
61
+ assert_equal "Product: Draft 151cm ",
62
+ Template.parse("{% include 'product' %}").render( "product" => {'title' => 'Draft 151cm'} )
63
+ end
64
+
65
+ def test_include_tag_for
66
+
67
+ assert_equal "Product: Draft 151cm Product: Element 155cm ",
68
+ Template.parse("{% include 'product' for products %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
69
+ end
70
+
71
+ def test_include_tag_with_local_variables
72
+ assert_equal "Locale: test123 ",
73
+ Template.parse("{% include 'locale_variables' echo1: 'test123' %}").render
74
+ end
75
+
76
+ def test_include_tag_with_multiple_local_variables
77
+ assert_equal "Locale: test123 test321",
78
+ Template.parse("{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}").render
79
+ end
80
+
81
+ def test_include_tag_with_multiple_local_variables_from_context
82
+ assert_equal "Locale: test123 test321",
83
+ Template.parse("{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}").render('echo1' => 'test123', 'more_echos' => { "echo2" => 'test321'})
84
+ end
85
+
86
+ def test_nested_include_tag
87
+ assert_equal "body body_detail",
88
+ Template.parse("{% include 'body' %}").render
89
+
90
+ assert_equal "header body body_detail footer",
91
+ Template.parse("{% include 'nested_template' %}").render
92
+ end
93
+
94
+ def test_nested_include_with_variable
95
+
96
+ assert_equal "Product: Draft 151cm details ",
97
+ Template.parse("{% include 'nested_product_template' with product %}").render("product" => {"title" => 'Draft 151cm'})
98
+
99
+ assert_equal "Product: Draft 151cm details Product: Element 155cm details ",
100
+ Template.parse("{% include 'nested_product_template' for products %}").render("products" => [{"title" => 'Draft 151cm'}, {"title" => 'Element 155cm'}])
101
+
102
+ end
103
+
104
+ def test_recursively_included_template_does_not_produce_endless_loop
105
+
106
+ infinite_file_system = Class.new do
107
+ def read_template_file(template_path, context)
108
+ "-{% include 'loop' %}"
109
+ end
110
+ end
111
+
112
+ Liquid::Template.file_system = infinite_file_system.new
113
+
114
+ assert_raise(Liquid::StackLevelError) do
115
+ Template.parse("{% include 'loop' %}").render!
116
+ end
117
+
118
+ end
119
+
120
+ def test_backwards_compatability_support_for_overridden_read_template_file
121
+ infinite_file_system = Class.new do
122
+ def read_template_file(template_path) # testing only one argument here.
123
+ "- hi mom"
124
+ end
125
+ end
126
+
127
+ Liquid::Template.file_system = infinite_file_system.new
128
+
129
+ Template.parse("{% include 'hi_mom' %}").render!
130
+ end
131
+
132
+ def test_dynamically_choosen_template
133
+
134
+ assert_equal "Test123", Template.parse("{% include template %}").render("template" => 'Test123')
135
+ assert_equal "Test321", Template.parse("{% include template %}").render("template" => 'Test321')
136
+
137
+ assert_equal "Product: Draft 151cm ", Template.parse("{% include template for product %}").render("template" => 'product', 'product' => { 'title' => 'Draft 151cm'})
138
+ end
139
+ end # IncludeTagTest
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class IncrementTagTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_inc
7
+ assert_template_result('0','{%increment port %}', {})
8
+ assert_template_result('0 1','{%increment port %} {%increment port%}', {})
9
+ assert_template_result('0 0 1 2 1',
10
+ '{%increment port %} {%increment starboard%} ' +
11
+ '{%increment port %} {%increment port%} ' +
12
+ '{%increment starboard %}', {})
13
+ end
14
+
15
+ def test_dec
16
+ assert_template_result('9','{%decrement port %}', { 'port' => 10})
17
+ assert_template_result('-1 -2','{%decrement port %} {%decrement port%}', {})
18
+ assert_template_result('1 5 2 2 5',
19
+ '{%increment port %} {%increment starboard%} ' +
20
+ '{%increment port %} {%decrement port%} ' +
21
+ '{%decrement starboard %}', { 'port' => 1, 'starboard' => 5 })
22
+ end
23
+
24
+ end
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+
3
+ class RawTagTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_tag_in_raw
7
+ assert_template_result '{% comment %} test {% endcomment %}',
8
+ '{% raw %}{% comment %} test {% endcomment %}{% endraw %}'
9
+ end
10
+
11
+ def test_output_in_raw
12
+ assert_template_result '{{ test }}',
13
+ '{% raw %}{{ test }}{% endraw %}'
14
+ end
15
+ end
@@ -0,0 +1,461 @@
1
+ require 'test_helper'
2
+
3
+ class StandardTagTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_tag
7
+ tag = Tag.new('tag', [], [])
8
+ assert_equal 'liquid::tag', tag.name
9
+ assert_equal '', tag.render(Context.new)
10
+ end
11
+
12
+ def test_no_transform
13
+ assert_template_result('this text should come out of the template without change...',
14
+ 'this text should come out of the template without change...')
15
+
16
+ assert_template_result('blah','blah')
17
+ assert_template_result('<blah>','<blah>')
18
+ assert_template_result('|,.:','|,.:')
19
+ assert_template_result('','')
20
+
21
+ text = %|this shouldnt see any transformation either but has multiple lines
22
+ as you can clearly see here ...|
23
+ assert_template_result(text,text)
24
+ end
25
+
26
+ def test_has_a_block_which_does_nothing
27
+ assert_template_result(%|the comment block should be removed .. right?|,
28
+ %|the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?|)
29
+
30
+ assert_template_result('','{%comment%}{%endcomment%}')
31
+ assert_template_result('','{%comment%}{% endcomment %}')
32
+ assert_template_result('','{% comment %}{%endcomment%}')
33
+ assert_template_result('','{% comment %}{% endcomment %}')
34
+ assert_template_result('','{%comment%}comment{%endcomment%}')
35
+ assert_template_result('','{% comment %}comment{% endcomment %}')
36
+
37
+ assert_template_result('foobar','foo{%comment%}comment{%endcomment%}bar')
38
+ assert_template_result('foobar','foo{% comment %}comment{% endcomment %}bar')
39
+ assert_template_result('foobar','foo{%comment%} comment {%endcomment%}bar')
40
+ assert_template_result('foobar','foo{% comment %} comment {% endcomment %}bar')
41
+
42
+ assert_template_result('foo bar','foo {%comment%} {%endcomment%} bar')
43
+ assert_template_result('foo bar','foo {%comment%}comment{%endcomment%} bar')
44
+ assert_template_result('foo bar','foo {%comment%} comment {%endcomment%} bar')
45
+
46
+ assert_template_result('foobar','foo{%comment%}
47
+ {%endcomment%}bar')
48
+ end
49
+
50
+ def test_for
51
+ assert_template_result(' yo yo yo yo ','{%for item in array%} yo {%endfor%}','array' => [1,2,3,4])
52
+ assert_template_result('yoyo','{%for item in array%}yo{%endfor%}','array' => [1,2])
53
+ assert_template_result(' yo ','{%for item in array%} yo {%endfor%}','array' => [1])
54
+ assert_template_result('','{%for item in array%}{%endfor%}','array' => [1,2])
55
+ expected = <<HERE
56
+
57
+ yo
58
+
59
+ yo
60
+
61
+ yo
62
+
63
+ HERE
64
+ template = <<HERE
65
+ {%for item in array%}
66
+ yo
67
+ {%endfor%}
68
+ HERE
69
+ assert_template_result(expected,template,'array' => [1,2,3])
70
+ end
71
+
72
+ def test_for_with_range
73
+ assert_template_result(' 1 2 3 ','{%for item in (1..3) %} {{item}} {%endfor%}')
74
+ end
75
+
76
+ def test_for_with_variable
77
+ assert_template_result(' 1 2 3 ','{%for item in array%} {{item}} {%endfor%}','array' => [1,2,3])
78
+ assert_template_result('123','{%for item in array%}{{item}}{%endfor%}','array' => [1,2,3])
79
+ assert_template_result('123','{% for item in array %}{{item}}{% endfor %}','array' => [1,2,3])
80
+ assert_template_result('abcd','{%for item in array%}{{item}}{%endfor%}','array' => ['a','b','c','d'])
81
+ assert_template_result('a b c','{%for item in array%}{{item}}{%endfor%}','array' => ['a',' ','b',' ','c'])
82
+ assert_template_result('abc','{%for item in array%}{{item}}{%endfor%}','array' => ['a','','b','','c'])
83
+ end
84
+
85
+ def test_for_helpers
86
+ assigns = {'array' => [1,2,3] }
87
+ assert_template_result(' 1/3 2/3 3/3 ',
88
+ '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',
89
+ assigns)
90
+ assert_template_result(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', assigns)
91
+ assert_template_result(' 0 1 2 ', '{%for item in array%} {{forloop.index0}} {%endfor%}', assigns)
92
+ assert_template_result(' 2 1 0 ', '{%for item in array%} {{forloop.rindex0}} {%endfor%}', assigns)
93
+ assert_template_result(' 3 2 1 ', '{%for item in array%} {{forloop.rindex}} {%endfor%}', assigns)
94
+ assert_template_result(' true false false ', '{%for item in array%} {{forloop.first}} {%endfor%}', assigns)
95
+ assert_template_result(' false false true ', '{%for item in array%} {{forloop.last}} {%endfor%}', assigns)
96
+ end
97
+
98
+ def test_for_and_if
99
+ assigns = {'array' => [1,2,3] }
100
+ assert_template_result('+--',
101
+ '{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}',
102
+ assigns)
103
+ end
104
+
105
+ def test_for_else
106
+ assert_template_result('+++', '{%for item in array%}+{%else%}-{%endfor%}', 'array'=>[1,2,3])
107
+ assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array'=>[])
108
+ assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array'=>nil)
109
+ end
110
+
111
+ def test_limiting
112
+ assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
113
+ assert_template_result('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', assigns)
114
+ assert_template_result('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', assigns)
115
+ assert_template_result('3456', '{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}', assigns)
116
+ assert_template_result('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', assigns)
117
+ end
118
+
119
+ def test_dynamic_variable_limiting
120
+ assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
121
+ assigns['limit'] = 2
122
+ assigns['offset'] = 2
123
+
124
+ assert_template_result('34', '{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}', assigns)
125
+ end
126
+
127
+ def test_nested_for
128
+ assigns = {'array' => [[1,2],[3,4],[5,6]] }
129
+ assert_template_result('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', assigns)
130
+ end
131
+
132
+ def test_offset_only
133
+ assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
134
+ assert_template_result('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', assigns)
135
+ end
136
+
137
+ def test_pause_resume
138
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
139
+ markup = <<-MKUP
140
+ {%for i in array.items limit: 3 %}{{i}}{%endfor%}
141
+ next
142
+ {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
143
+ next
144
+ {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
145
+ MKUP
146
+ expected = <<-XPCTD
147
+ 123
148
+ next
149
+ 456
150
+ next
151
+ 789
152
+ XPCTD
153
+ assert_template_result(expected,markup,assigns)
154
+ end
155
+
156
+ def test_pause_resume_limit
157
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
158
+ markup = <<-MKUP
159
+ {%for i in array.items limit:3 %}{{i}}{%endfor%}
160
+ next
161
+ {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
162
+ next
163
+ {%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
164
+ MKUP
165
+ expected = <<-XPCTD
166
+ 123
167
+ next
168
+ 456
169
+ next
170
+ 7
171
+ XPCTD
172
+ assert_template_result(expected,markup,assigns)
173
+ end
174
+
175
+ def test_pause_resume_BIG_limit
176
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
177
+ markup = <<-MKUP
178
+ {%for i in array.items limit:3 %}{{i}}{%endfor%}
179
+ next
180
+ {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
181
+ next
182
+ {%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
183
+ MKUP
184
+ expected = <<-XPCTD
185
+ 123
186
+ next
187
+ 456
188
+ next
189
+ 7890
190
+ XPCTD
191
+ assert_template_result(expected,markup,assigns)
192
+ end
193
+
194
+
195
+ def test_pause_resume_BIG_offset
196
+ assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
197
+ markup = %q({%for i in array.items limit:3 %}{{i}}{%endfor%}
198
+ next
199
+ {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
200
+ next
201
+ {%for i in array.items offset:continue limit:3 offset:1000 %}{{i}}{%endfor%})
202
+ expected = %q(123
203
+ next
204
+ 456
205
+ next
206
+ )
207
+ assert_template_result(expected,markup,assigns)
208
+ end
209
+
210
+ def test_assign
211
+ assigns = {'var' => 'content' }
212
+ assert_template_result('var2: var2:content', 'var2:{{var2}} {%assign var2 = var%} var2:{{var2}}', assigns)
213
+
214
+ end
215
+
216
+ def test_hyphenated_assign
217
+ assigns = {'a-b' => '1' }
218
+ assert_template_result('a-b:1 a-b:2', 'a-b:{{a-b}} {%assign a-b = 2 %}a-b:{{a-b}}', assigns)
219
+
220
+ end
221
+
222
+ def test_assign_with_colon_and_spaces
223
+ assigns = {'var' => {'a:b c' => {'paged' => '1' }}}
224
+ assert_template_result('var2: 1', '{%assign var2 = var["a:b c"].paged %}var2: {{var2}}', assigns)
225
+ end
226
+
227
+ def test_capture
228
+ assigns = {'var' => 'content' }
229
+ assert_template_result('content foo content foo ',
230
+ '{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
231
+ assigns)
232
+ end
233
+
234
+ def test_capture_detects_bad_syntax
235
+ assert_raise(SyntaxError) do
236
+ assert_template_result('content foo content foo ',
237
+ '{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
238
+ {'var' => 'content' })
239
+ end
240
+ end
241
+
242
+ def test_case
243
+ assigns = {'condition' => 2 }
244
+ assert_template_result(' its 2 ',
245
+ '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
246
+ assigns)
247
+
248
+ assigns = {'condition' => 1 }
249
+ assert_template_result(' its 1 ',
250
+ '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
251
+ assigns)
252
+
253
+ assigns = {'condition' => 3 }
254
+ assert_template_result('',
255
+ '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}',
256
+ assigns)
257
+
258
+ assigns = {'condition' => "string here" }
259
+ assert_template_result(' hit ',
260
+ '{% case condition %}{% when "string here" %} hit {% endcase %}',
261
+ assigns)
262
+
263
+ assigns = {'condition' => "bad string here" }
264
+ assert_template_result('',
265
+ '{% case condition %}{% when "string here" %} hit {% endcase %}',\
266
+ assigns)
267
+ end
268
+
269
+ def test_case_with_else
270
+ assigns = {'condition' => 5 }
271
+ assert_template_result(' hit ',
272
+ '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
273
+ assigns)
274
+
275
+ assigns = {'condition' => 6 }
276
+ assert_template_result(' else ',
277
+ '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}',
278
+ assigns)
279
+
280
+ assigns = {'condition' => 6 }
281
+ assert_template_result(' else ',
282
+ '{% case condition %} {% when 5 %} hit {% else %} else {% endcase %}',
283
+ assigns)
284
+ end
285
+
286
+ def test_case_on_size
287
+ assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [])
288
+ assert_template_result('1', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1])
289
+ assert_template_result('2', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1])
290
+ assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1])
291
+ assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1])
292
+ assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1, 1])
293
+ end
294
+
295
+ def test_case_on_size_with_else
296
+ assert_template_result('else',
297
+ '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
298
+ 'a' => [])
299
+
300
+ assert_template_result('1',
301
+ '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
302
+ 'a' => [1])
303
+
304
+ assert_template_result('2',
305
+ '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
306
+ 'a' => [1, 1])
307
+
308
+ assert_template_result('else',
309
+ '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
310
+ 'a' => [1, 1, 1])
311
+
312
+ assert_template_result('else',
313
+ '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
314
+ 'a' => [1, 1, 1, 1])
315
+
316
+ assert_template_result('else',
317
+ '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
318
+ 'a' => [1, 1, 1, 1, 1])
319
+ end
320
+
321
+ def test_case_on_length_with_else
322
+ assert_template_result('else',
323
+ '{% case a.empty? %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
324
+ {})
325
+
326
+ assert_template_result('false',
327
+ '{% case false %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
328
+ {})
329
+
330
+ assert_template_result('true',
331
+ '{% case true %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
332
+ {})
333
+
334
+ assert_template_result('else',
335
+ '{% case NULL %}{% when true %}true{% when false %}false{% else %}else{% endcase %}',
336
+ {})
337
+ end
338
+
339
+ def test_assign_from_case
340
+ # Example from the shopify forums
341
+ code = %q({% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }})
342
+ template = Liquid::Template.parse(code)
343
+ assert_equal "menswear", template.render("collection" => {'handle' => 'menswear-jackets'})
344
+ assert_equal "menswear", template.render("collection" => {'handle' => 'menswear-t-shirts'})
345
+ assert_equal "womenswear", template.render("collection" => {'handle' => 'x'})
346
+ assert_equal "womenswear", template.render("collection" => {'handle' => 'y'})
347
+ assert_equal "womenswear", template.render("collection" => {'handle' => 'z'})
348
+ end
349
+
350
+ def test_case_when_or
351
+ code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
352
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
353
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 2 })
354
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 3 })
355
+ assert_template_result(' its 4 ', code, {'condition' => 4 })
356
+ assert_template_result('', code, {'condition' => 5 })
357
+
358
+ code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
359
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
360
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 'string' })
361
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => nil })
362
+ assert_template_result('', code, {'condition' => 'something else' })
363
+ end
364
+
365
+ def test_case_when_comma
366
+ code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
367
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
368
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 2 })
369
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 3 })
370
+ assert_template_result(' its 4 ', code, {'condition' => 4 })
371
+ assert_template_result('', code, {'condition' => 5 })
372
+
373
+ code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
374
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
375
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 'string' })
376
+ assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => nil })
377
+ assert_template_result('', code, {'condition' => 'something else' })
378
+ end
379
+
380
+ def test_assign
381
+ assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{{a}}' ).render
382
+ end
383
+
384
+ def test_assign_an_empty_string
385
+ assert_equal '', Liquid::Template.parse( '{% assign a = ""%}{{a}}' ).render
386
+ end
387
+
388
+ def test_assign_is_global
389
+ assert_equal 'variable',
390
+ Liquid::Template.parse( '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}' ).render
391
+ end
392
+
393
+ def test_case_detects_bad_syntax
394
+ assert_raise(SyntaxError) do
395
+ assert_template_result('', '{% case false %}{% when %}true{% endcase %}', {})
396
+ end
397
+
398
+ assert_raise(SyntaxError) do
399
+ assert_template_result('', '{% case false %}{% huh %}true{% endcase %}', {})
400
+ end
401
+
402
+ end
403
+
404
+ def test_cycle
405
+ assert_template_result('one','{%cycle "one", "two"%}')
406
+ assert_template_result('one two','{%cycle "one", "two"%} {%cycle "one", "two"%}')
407
+ assert_template_result(' two','{%cycle "", "two"%} {%cycle "", "two"%}')
408
+
409
+ assert_template_result('one two one','{%cycle "one", "two"%} {%cycle "one", "two"%} {%cycle "one", "two"%}')
410
+
411
+ assert_template_result('text-align: left text-align: right',
412
+ '{%cycle "text-align: left", "text-align: right" %} {%cycle "text-align: left", "text-align: right"%}')
413
+ end
414
+
415
+ def test_multiple_cycles
416
+ assert_template_result('1 2 1 1 2 3 1',
417
+ '{%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%}')
418
+ end
419
+
420
+ def test_multiple_named_cycles
421
+ assert_template_result('one one two two one one',
422
+ '{%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %}')
423
+ end
424
+
425
+ def test_multiple_named_cycles_with_names_from_context
426
+ assigns = {"var1" => 1, "var2" => 2 }
427
+ assert_template_result('one one two two one one',
428
+ '{%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %}', assigns)
429
+ end
430
+
431
+ def test_size_of_array
432
+ assigns = {"array" => [1,2,3,4]}
433
+ assert_template_result('array has 4 elements', "array has {{ array.size }} elements", assigns)
434
+ end
435
+
436
+ def test_size_of_hash
437
+ assigns = {"hash" => {:a => 1, :b => 2, :c=> 3, :d => 4}}
438
+ assert_template_result('hash has 4 elements', "hash has {{ hash.size }} elements", assigns)
439
+ end
440
+
441
+ def test_illegal_symbols
442
+ assert_template_result('', '{% if true == empty %}?{% endif %}', {})
443
+ assert_template_result('', '{% if true == null %}?{% endif %}', {})
444
+ assert_template_result('', '{% if empty == true %}?{% endif %}', {})
445
+ assert_template_result('', '{% if null == true %}?{% endif %}', {})
446
+ end
447
+
448
+ def test_for_reversed
449
+ assigns = {'array' => [ 1, 2, 3] }
450
+ assert_template_result('321','{%for item in array reversed %}{{item}}{%endfor%}',assigns)
451
+ end
452
+
453
+
454
+ def test_ifchanged
455
+ assigns = {'array' => [ 1, 1, 2, 2, 3, 3] }
456
+ assert_template_result('123','{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}',assigns)
457
+
458
+ assigns = {'array' => [ 1, 1, 1, 1] }
459
+ assert_template_result('1','{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}',assigns)
460
+ end
461
+ end # StandardTagTest