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,80 @@
1
+ class Continuation # :nodoc:
2
+ def self.create(*args, &block) # :nodoc:
3
+ cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
4
+ result ||= args
5
+ return *[cc, *result]
6
+ end
7
+ end
8
+
9
+ class Binding; end # for RDoc
10
+ # This method returns the binding of the method that called your
11
+ # method. It will raise an Exception when you're not inside a method.
12
+ #
13
+ # It's used like this:
14
+ # def inc_counter(amount = 1)
15
+ # Binding.of_caller do |binding|
16
+ # # Create a lambda that will increase the variable 'counter'
17
+ # # in the caller of this method when called.
18
+ # inc = eval("lambda { |arg| counter += arg }", binding)
19
+ # # We can refer to amount from inside this block safely.
20
+ # inc.call(amount)
21
+ # end
22
+ # # No other statements can go here. Put them inside the block.
23
+ # end
24
+ # counter = 0
25
+ # 2.times { inc_counter }
26
+ # counter # => 2
27
+ #
28
+ # Binding.of_caller must be the last statement in the method.
29
+ # This means that you will have to put everything you want to
30
+ # do after the call to Binding.of_caller into the block of it.
31
+ # This should be no problem however, because Ruby has closures.
32
+ # If you don't do this an Exception will be raised. Because of
33
+ # the way that Binding.of_caller is implemented it has to be
34
+ # done this way.
35
+ def Binding.of_caller(&block)
36
+ old_critical = Thread.critical
37
+ Thread.critical = true
38
+ count = 0
39
+ cc, result, error, extra_data = Continuation.create(nil, nil)
40
+ error.call if error
41
+
42
+ tracer = lambda do |*args|
43
+ type, context, extra_data = args[0], args[4], args
44
+ if type == "return"
45
+ count += 1
46
+ # First this method and then calling one will return --
47
+ # the trace event of the second event gets the context
48
+ # of the method which called the method that called this
49
+ # method.
50
+ if count == 2
51
+ # It would be nice if we could restore the trace_func
52
+ # that was set before we swapped in our own one, but
53
+ # this is impossible without overloading set_trace_func
54
+ # in current Ruby.
55
+ set_trace_func(nil)
56
+ cc.call(eval("binding", context), nil, extra_data)
57
+ end
58
+ elsif type == "line" then
59
+ nil
60
+ elsif type == "c-return" and extra_data[3] == :set_trace_func then
61
+ nil
62
+ else
63
+ set_trace_func(nil)
64
+ error_msg = "Binding.of_caller used in non-method context or " +
65
+ "trailing statements of method using it aren't in the block."
66
+ cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
67
+ end
68
+ end
69
+
70
+ unless result
71
+ set_trace_func(tracer)
72
+ return nil
73
+ else
74
+ Thread.critical = old_critical
75
+ case block.arity
76
+ when 1 then yield(result)
77
+ else yield(result, extra_data)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+ class FileSystemTest < Test::Unit::TestCase
5
+ include Liquid
6
+
7
+ def test_default
8
+ assert_raise(FileSystemError) do
9
+ BlankFileSystem.new.read_template_file("dummy")
10
+ end
11
+ end
12
+
13
+ def test_local
14
+ file_system = Liquid::LocalFileSystem.new("/some/path")
15
+ assert_equal "/some/path/_mypartial.liquid" , file_system.full_path("mypartial")
16
+ assert_equal "/some/path/dir/_mypartial.liquid", file_system.full_path("dir/mypartial")
17
+
18
+ assert_raise(FileSystemError) do
19
+ file_system.full_path("../dir/mypartial")
20
+ end
21
+
22
+ assert_raise(FileSystemError) do
23
+ file_system.full_path("/dir/../../dir/mypartial")
24
+ end
25
+
26
+ assert_raise(FileSystemError) do
27
+ file_system.full_path("/etc/passwd")
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+ module MoneyFilter
5
+ def money(input)
6
+ sprintf(' %d$ ', input)
7
+ end
8
+
9
+ def money_with_underscore(input)
10
+ sprintf(' %d$ ', input)
11
+ end
12
+ end
13
+
14
+ module CanadianMoneyFilter
15
+ def money(input)
16
+ sprintf(' %d$ CAD ', input)
17
+ end
18
+ end
19
+
20
+ class FiltersTest < Test::Unit::TestCase
21
+ include Liquid
22
+
23
+ def setup
24
+ @context = Context.new
25
+ end
26
+
27
+ def test_local_filter
28
+ @context['var'] = 1000
29
+ @context.add_filters(MoneyFilter)
30
+ assert_equal ' 1000$ ', Variable.new("var | money").render(@context)
31
+ end
32
+
33
+ def test_underscore_in_filter_name
34
+ @context['var'] = 1000
35
+ @context.add_filters(MoneyFilter)
36
+ assert_equal ' 1000$ ', Variable.new("var | money_with_underscore").render(@context)
37
+ end
38
+
39
+ def test_second_filter_overwrites_first
40
+ @context['var'] = 1000
41
+ @context.add_filters(MoneyFilter)
42
+ @context.add_filters(CanadianMoneyFilter)
43
+ assert_equal ' 1000$ CAD ', Variable.new("var | money").render(@context)
44
+ end
45
+
46
+ def test_size
47
+ @context['var'] = 'abcd'
48
+ @context.add_filters(MoneyFilter)
49
+ assert_equal 4, Variable.new("var | size").render(@context)
50
+ end
51
+
52
+ def test_join
53
+ @context['var'] = [1,2,3,4]
54
+ assert_equal "1 2 3 4", Variable.new("var | join").render(@context)
55
+ end
56
+
57
+ def test_sort
58
+ @context['value'] = 3
59
+ @context['numbers'] = [2,1,4,3]
60
+ @context['words'] = ['expected', 'as', 'alphabetic']
61
+ @context['arrays'] = [['flattened'], ['are']]
62
+ assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context)
63
+ assert_equal ['alphabetic', 'as', 'expected'],
64
+ Variable.new("words | sort").render(@context)
65
+ assert_equal [3], Variable.new("value | sort").render(@context)
66
+ assert_equal ['are', 'flattened'], Variable.new("arrays | sort").render(@context)
67
+ end
68
+
69
+ def test_strip_html
70
+ @context['var'] = "<b>bla blub</a>"
71
+ assert_equal "bla blub", Variable.new("var | strip_html").render(@context)
72
+ end
73
+
74
+ def test_capitalize
75
+ @context['var'] = "blub"
76
+ assert_equal "Blub", Variable.new("var | capitalize").render(@context)
77
+ end
78
+ end
79
+
80
+ class FiltersInTemplate < Test::Unit::TestCase
81
+ include Liquid
82
+
83
+ def test_local_global
84
+ Template.register_filter(MoneyFilter)
85
+
86
+ assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render(nil, nil)
87
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, :filters => CanadianMoneyFilter)
88
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, :filters => [CanadianMoneyFilter])
89
+ end
90
+
91
+ def test_local_filter_with_deprecated_syntax
92
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, CanadianMoneyFilter)
93
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, [CanadianMoneyFilter])
94
+ end
95
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+ '/extra')
3
+
4
+ require 'test/unit'
5
+ require 'test/unit/assertions'
6
+ require 'caller'
7
+ require 'breakpoint'
8
+ require File.dirname(__FILE__) + '/../lib/liquid'
9
+
10
+
11
+ module Test
12
+ module Unit
13
+ module Assertions
14
+ include Liquid
15
+ def assert_template_result(expected, template, assigns={}, message=nil)
16
+ assert_equal expected, Template.parse(template).render(assigns)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/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}} {% end %}',
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}} {% end %}',
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}} {% end %}',
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}}{% end %}',
27
+ 'numbers' => [1,2,3,4,5,6])
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,131 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class IfElseTest < 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 {% end %} ')
8
+ assert_template_result(' this text should go into the output ',
9
+ ' {% if true %} this text should go into the output {% end %} ')
10
+ assert_template_result(' you rock ?','{% if false %} you suck {% end %} {% if true %} you rock {% end %}?')
11
+ end
12
+
13
+ def test_if_else
14
+ assert_template_result(' YES ','{% if false %} NO {% else %} YES {% end %}')
15
+ assert_template_result(' YES ','{% if true %} YES {% else %} NO {% end %}')
16
+ assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% end %}')
17
+ end
18
+
19
+ def test_if_boolean
20
+ assert_template_result(' YES ','{% if var %} YES {% end %}', 'var' => true)
21
+ end
22
+
23
+ def test_if_or
24
+ assert_template_result(' YES ','{% if a or b %} YES {% end %}', 'a' => true, 'b' => true)
25
+ assert_template_result(' YES ','{% if a or b %} YES {% end %}', 'a' => true, 'b' => false)
26
+ assert_template_result(' YES ','{% if a or b %} YES {% end %}', 'a' => false, 'b' => true)
27
+ assert_template_result('', '{% if a or b %} YES {% end %}', 'a' => false, 'b' => false)
28
+
29
+ assert_template_result(' YES ','{% if a or b or c %} YES {% end %}', 'a' => false, 'b' => false, 'c' => true)
30
+ assert_template_result('', '{% if a or b or c %} YES {% end %}', '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 {% end %}', 'a' => true, 'b' => true)
35
+ assert_template_result(' YES ','{% if a == true or b == false %} YES {% end %}', 'a' => true, 'b' => true)
36
+ assert_template_result('','{% if a == false or b == false %} YES {% end %}', 'a' => true, 'b' => true)
37
+ end
38
+
39
+ def test_if_and
40
+ assert_template_result(' YES ','{% if true and true %} YES {% end %}')
41
+ assert_template_result('','{% if false and true %} YES {% end %}')
42
+ assert_template_result('','{% if false and true %} YES {% end %}')
43
+ end
44
+
45
+
46
+ def test_hash_miss_generates_false
47
+ assert_template_result('','{% if foo.bar %} NO {% end %}', 'foo' => {})
48
+ end
49
+
50
+ def test_if_from_variable
51
+ assert_template_result('','{% if var %} NO {% end %}', 'var' => false)
52
+ assert_template_result('','{% if var %} NO {% end %}', 'var' => nil)
53
+ assert_template_result('','{% if foo.bar %} NO {% end %}', 'foo' => {'bar' => false})
54
+ assert_template_result('','{% if foo.bar %} NO {% end %}', 'foo' => {})
55
+ assert_template_result('','{% if foo.bar %} NO {% end %}', 'foo' => nil)
56
+ assert_template_result('','{% if foo.bar %} NO {% end %}', 'foo' => true)
57
+
58
+ assert_template_result(' YES ','{% if var %} YES {% end %}', 'var' => "text")
59
+ assert_template_result(' YES ','{% if var %} YES {% end %}', 'var' => true)
60
+ assert_template_result(' YES ','{% if var %} YES {% end %}', 'var' => 1)
61
+ assert_template_result(' YES ','{% if var %} YES {% end %}', 'var' => {})
62
+ assert_template_result(' YES ','{% if var %} YES {% end %}', 'var' => [])
63
+ assert_template_result(' YES ','{% if "foo" %} YES {% end %}')
64
+ assert_template_result(' YES ','{% if foo.bar %} YES {% end %}', 'foo' => {'bar' => true})
65
+ assert_template_result(' YES ','{% if foo.bar %} YES {% end %}', 'foo' => {'bar' => "text"})
66
+ assert_template_result(' YES ','{% if foo.bar %} YES {% end %}', 'foo' => {'bar' => 1 })
67
+ assert_template_result(' YES ','{% if foo.bar %} YES {% end %}', 'foo' => {'bar' => {} })
68
+ assert_template_result(' YES ','{% if foo.bar %} YES {% end %}', 'foo' => {'bar' => [] })
69
+
70
+ assert_template_result(' YES ','{% if var %} NO {% else %} YES {% end %}', 'var' => false)
71
+ assert_template_result(' YES ','{% if var %} NO {% else %} YES {% end %}', 'var' => nil)
72
+ assert_template_result(' YES ','{% if var %} YES {% else %} NO {% end %}', 'var' => true)
73
+ assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% end %}', 'var' => "text")
74
+
75
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% end %}', 'foo' => {'bar' => false})
76
+ assert_template_result(' YES ','{% if foo.bar %} YES {% else %} NO {% end %}', 'foo' => {'bar' => true})
77
+ assert_template_result(' YES ','{% if foo.bar %} YES {% else %} NO {% end %}', 'foo' => {'bar' => "text"})
78
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% end %}', 'foo' => {'notbar' => true})
79
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% end %}', 'foo' => {})
80
+ assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% end %}', 'notfoo' => {'bar' => true})
81
+ end
82
+
83
+ def test_nested_if
84
+ assert_template_result('', '{% if false %}{% if false %} NO {% end %}{% end %}')
85
+ assert_template_result('', '{% if false %}{% if true %} NO {% end %}{% end %}')
86
+ assert_template_result('', '{% if true %}{% if false %} NO {% end %}{% end %}')
87
+ assert_template_result(' YES ', '{% if true %}{% if true %} YES {% end %}{% end %}')
88
+
89
+ assert_template_result(' YES ', '{% if true %}{% if true %} YES {% else %} NO {% end %}{% else %} NO {% end %}')
90
+ assert_template_result(' YES ', '{% if true %}{% if false %} NO {% else %} YES {% end %}{% else %} NO {% end %}')
91
+ assert_template_result(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% end %}{% else %} YES {% end %}')
92
+
93
+ end
94
+
95
+ def test_comparisons_on_null
96
+ assert_template_result('','{% if null < 10 %} NO {% end %}')
97
+ assert_template_result('','{% if null <= 10 %} NO {% end %}')
98
+ assert_template_result('','{% if null >= 10 %} NO {% end %}')
99
+ assert_template_result('','{% if null > 10 %} NO {% end %}')
100
+
101
+ assert_template_result('','{% if 10 < null %} NO {% end %}')
102
+ assert_template_result('','{% if 10 <= null %} NO {% end %}')
103
+ assert_template_result('','{% if 10 >= null %} NO {% end %}')
104
+ assert_template_result('','{% if 10 > null %} NO {% end %}')
105
+ end
106
+
107
+ def test_else_if
108
+ assert_template_result('0','{% if 0 == 0 %}0{% elsif 1 == 1%}1{% else %}2{% end %}')
109
+ assert_template_result('1','{% if 0 != 0 %}0{% elsif 1 == 1%}1{% else %}2{% end %}')
110
+ assert_template_result('2','{% if 0 != 0 %}0{% elsif 1 != 1%}1{% else %}2{% end %}')
111
+
112
+ assert_template_result('elsif','{% if false %}if{% elsif true %}elsif{% end %}')
113
+ end
114
+
115
+ def test_syntax_error_no_variable
116
+ assert_raise(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')}
117
+ end
118
+
119
+ def test_syntax_error_no_expression
120
+ assert_raise(SyntaxError) { assert_template_result('', '{% if %}') }
121
+ end
122
+
123
+ def test_if_with_custom_condition
124
+ Condition.operators['contains'] = :[]
125
+
126
+ assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% end %}))
127
+ assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% end %}))
128
+ ensure
129
+ Condition.operators.delete 'contains'
130
+ end
131
+ end
@@ -0,0 +1,115 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestFileSystem
4
+ def read_template_file(template_path)
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
+ else
28
+ template_path
29
+ end
30
+ end
31
+ end
32
+
33
+ class IncludeTagTest < Test::Unit::TestCase
34
+ include Liquid
35
+
36
+ def setup
37
+ Liquid::Template.file_system = TestFileSystem.new
38
+ end
39
+
40
+
41
+ def test_include_tag_with
42
+ assert_equal "Product: Draft 151cm ",
43
+ Template.parse("{% include 'product' with products[0] %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
44
+ end
45
+
46
+ def test_include_tag_with_default_name
47
+ assert_equal "Product: Draft 151cm ",
48
+ Template.parse("{% include 'product' %}").render( "product" => {'title' => 'Draft 151cm'} )
49
+ end
50
+
51
+ def test_include_tag_for
52
+
53
+ assert_equal "Product: Draft 151cm Product: Element 155cm ",
54
+ Template.parse("{% include 'product' for products %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ] )
55
+ end
56
+
57
+ def test_include_tag_with_local_variables
58
+ assert_equal "Locale: test123 ",
59
+ Template.parse("{% include 'locale_variables' echo1: 'test123' %}").render
60
+ end
61
+
62
+ def test_include_tag_with_multiple_local_variables
63
+ assert_equal "Locale: test123 test321",
64
+ Template.parse("{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}").render
65
+ end
66
+
67
+ def test_include_tag_with_multiple_local_variables_from_context
68
+ assert_equal "Locale: test123 test321",
69
+ Template.parse("{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}").render('echo1' => 'test123', 'more_echos' => { "echo2" => 'test321'})
70
+ end
71
+
72
+ def test_nested_include_tag
73
+ assert_equal "body body_detail",
74
+ Template.parse("{% include 'body' %}").render
75
+
76
+ assert_equal "header body body_detail footer",
77
+ Template.parse("{% include 'nested_template' %}").render
78
+ end
79
+
80
+ def test_nested_include_with_variable
81
+
82
+ assert_equal "Product: Draft 151cm details ",
83
+ Template.parse("{% include 'nested_product_template' with product %}").render("product" => {"title" => 'Draft 151cm'})
84
+
85
+ assert_equal "Product: Draft 151cm details Product: Element 155cm details ",
86
+ Template.parse("{% include 'nested_product_template' for products %}").render("products" => [{"title" => 'Draft 151cm'}, {"title" => 'Element 155cm'}])
87
+
88
+ end
89
+
90
+ def test_recursively_included_template_does_not_produce_endless_loop
91
+
92
+ infinite_file_system = Class.new do
93
+ def read_template_file(template_path)
94
+ "-{% include 'loop' %}"
95
+ end
96
+ end
97
+
98
+ Liquid::Template.file_system = infinite_file_system.new
99
+
100
+ assert_raise(Liquid::StackLevelError) do
101
+ Template.parse("{% include 'loop' %}").render!
102
+ end
103
+
104
+ end
105
+
106
+ def test_dynamically_choosen_template
107
+
108
+ assert_equal "Test123", Template.parse("{% include template %}").render("template" => 'Test123')
109
+ assert_equal "Test321", Template.parse("{% include template %}").render("template" => 'Test321')
110
+
111
+ assert_equal "Product: Draft 151cm ", Template.parse("{% include template for product %}").render("template" => 'product', 'product' => { 'title' => 'Draft 151cm'})
112
+
113
+ end
114
+
115
+ end