drnic-liquid 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. data/CHANGELOG +44 -0
  2. data/History.txt +44 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +34 -0
  5. data/README.rdoc +44 -0
  6. data/Rakefile +30 -0
  7. data/example/server/example_servlet.rb +37 -0
  8. data/example/server/liquid_servlet.rb +28 -0
  9. data/example/server/server.rb +12 -0
  10. data/example/server/templates/index.liquid +6 -0
  11. data/example/server/templates/products.liquid +45 -0
  12. data/init.rb +8 -0
  13. data/lib/extras/liquid_view.rb +51 -0
  14. data/lib/liquid.rb +70 -0
  15. data/lib/liquid/block.rb +102 -0
  16. data/lib/liquid/condition.rb +120 -0
  17. data/lib/liquid/context.rb +221 -0
  18. data/lib/liquid/document.rb +17 -0
  19. data/lib/liquid/drop.rb +51 -0
  20. data/lib/liquid/errors.rb +11 -0
  21. data/lib/liquid/extensions.rb +56 -0
  22. data/lib/liquid/file_system.rb +62 -0
  23. data/lib/liquid/htmltags.rb +74 -0
  24. data/lib/liquid/module_ex.rb +62 -0
  25. data/lib/liquid/standardfilters.rb +209 -0
  26. data/lib/liquid/strainer.rb +51 -0
  27. data/lib/liquid/tag.rb +26 -0
  28. data/lib/liquid/tags/assign.rb +33 -0
  29. data/lib/liquid/tags/capture.rb +35 -0
  30. data/lib/liquid/tags/case.rb +83 -0
  31. data/lib/liquid/tags/comment.rb +9 -0
  32. data/lib/liquid/tags/cycle.rb +59 -0
  33. data/lib/liquid/tags/for.rb +136 -0
  34. data/lib/liquid/tags/if.rb +79 -0
  35. data/lib/liquid/tags/ifchanged.rb +20 -0
  36. data/lib/liquid/tags/include.rb +55 -0
  37. data/lib/liquid/tags/unless.rb +33 -0
  38. data/lib/liquid/template.rb +147 -0
  39. data/lib/liquid/variable.rb +49 -0
  40. data/liquid.gemspec +40 -0
  41. data/performance/shopify.rb +92 -0
  42. data/performance/shopify/comment_form.rb +33 -0
  43. data/performance/shopify/database.rb +45 -0
  44. data/performance/shopify/json_filter.rb +7 -0
  45. data/performance/shopify/liquid.rb +18 -0
  46. data/performance/shopify/money_filter.rb +18 -0
  47. data/performance/shopify/paginate.rb +93 -0
  48. data/performance/shopify/shop_filter.rb +98 -0
  49. data/performance/shopify/tag_filter.rb +25 -0
  50. data/performance/shopify/vision.database.yml +945 -0
  51. data/performance/shopify/weight_filter.rb +11 -0
  52. data/performance/tests/dropify/article.liquid +74 -0
  53. data/performance/tests/dropify/blog.liquid +33 -0
  54. data/performance/tests/dropify/cart.liquid +66 -0
  55. data/performance/tests/dropify/collection.liquid +22 -0
  56. data/performance/tests/dropify/index.liquid +47 -0
  57. data/performance/tests/dropify/page.liquid +8 -0
  58. data/performance/tests/dropify/product.liquid +68 -0
  59. data/performance/tests/dropify/theme.liquid +105 -0
  60. data/performance/tests/ripen/article.liquid +74 -0
  61. data/performance/tests/ripen/blog.liquid +13 -0
  62. data/performance/tests/ripen/cart.liquid +54 -0
  63. data/performance/tests/ripen/collection.liquid +29 -0
  64. data/performance/tests/ripen/index.liquid +32 -0
  65. data/performance/tests/ripen/page.liquid +4 -0
  66. data/performance/tests/ripen/product.liquid +75 -0
  67. data/performance/tests/ripen/theme.liquid +85 -0
  68. data/performance/tests/tribble/404.liquid +56 -0
  69. data/performance/tests/tribble/article.liquid +98 -0
  70. data/performance/tests/tribble/blog.liquid +41 -0
  71. data/performance/tests/tribble/cart.liquid +134 -0
  72. data/performance/tests/tribble/collection.liquid +70 -0
  73. data/performance/tests/tribble/index.liquid +94 -0
  74. data/performance/tests/tribble/page.liquid +56 -0
  75. data/performance/tests/tribble/product.liquid +116 -0
  76. data/performance/tests/tribble/search.liquid +51 -0
  77. data/performance/tests/tribble/theme.liquid +90 -0
  78. data/performance/tests/vogue/article.liquid +66 -0
  79. data/performance/tests/vogue/blog.liquid +32 -0
  80. data/performance/tests/vogue/cart.liquid +58 -0
  81. data/performance/tests/vogue/collection.liquid +19 -0
  82. data/performance/tests/vogue/index.liquid +22 -0
  83. data/performance/tests/vogue/page.liquid +3 -0
  84. data/performance/tests/vogue/product.liquid +62 -0
  85. data/performance/tests/vogue/theme.liquid +122 -0
  86. data/test/assign_test.rb +11 -0
  87. data/test/block_test.rb +58 -0
  88. data/test/condition_test.rb +109 -0
  89. data/test/context_test.rb +482 -0
  90. data/test/drop_test.rb +162 -0
  91. data/test/error_handling_test.rb +89 -0
  92. data/test/extra/breakpoint.rb +547 -0
  93. data/test/extra/caller.rb +80 -0
  94. data/test/file_system_test.rb +30 -0
  95. data/test/filter_test.rb +95 -0
  96. data/test/helper.rb +20 -0
  97. data/test/html_tag_test.rb +31 -0
  98. data/test/if_else_test.rb +131 -0
  99. data/test/include_tag_test.rb +115 -0
  100. data/test/module_ex_test.rb +89 -0
  101. data/test/output_test.rb +121 -0
  102. data/test/parsing_quirks_test.rb +41 -0
  103. data/test/regexp_test.rb +45 -0
  104. data/test/security_test.rb +41 -0
  105. data/test/standard_filter_test.rb +161 -0
  106. data/test/standard_tag_test.rb +400 -0
  107. data/test/statements_test.rb +137 -0
  108. data/test/strainer_test.rb +21 -0
  109. data/test/template_test.rb +26 -0
  110. data/test/test_helper.rb +20 -0
  111. data/test/unless_else_test.rb +27 -0
  112. data/test/variable_test.rb +172 -0
  113. metadata +187 -0
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+ class TestClassA
5
+ liquid_methods :allowedA, :chainedB
6
+ def allowedA
7
+ 'allowedA'
8
+ end
9
+ def restrictedA
10
+ 'restrictedA'
11
+ end
12
+ def chainedB
13
+ TestClassB.new
14
+ end
15
+ end
16
+
17
+ class TestClassB
18
+ liquid_methods :allowedB, :chainedC
19
+ def allowedB
20
+ 'allowedB'
21
+ end
22
+ def chainedC
23
+ TestClassC.new
24
+ end
25
+ end
26
+
27
+ class TestClassC
28
+ liquid_methods :allowedC
29
+ def allowedC
30
+ 'allowedC'
31
+ end
32
+ end
33
+
34
+ class TestClassC::LiquidDropClass
35
+ def another_allowedC
36
+ 'another_allowedC'
37
+ end
38
+ end
39
+
40
+ class ModuleExTest < Test::Unit::TestCase
41
+ include Liquid
42
+
43
+ def setup
44
+ @a = TestClassA.new
45
+ @b = TestClassB.new
46
+ @c = TestClassC.new
47
+ end
48
+
49
+ def test_should_create_LiquidDropClass
50
+ assert TestClassA::LiquidDropClass
51
+ assert TestClassB::LiquidDropClass
52
+ assert TestClassC::LiquidDropClass
53
+ end
54
+
55
+ def test_should_respond_to_liquid
56
+ assert @a.respond_to?(:to_liquid)
57
+ assert @b.respond_to?(:to_liquid)
58
+ assert @c.respond_to?(:to_liquid)
59
+ end
60
+
61
+ def test_should_return_LiquidDropClass_object
62
+ assert @a.to_liquid.is_a?(TestClassA::LiquidDropClass)
63
+ assert @b.to_liquid.is_a?(TestClassB::LiquidDropClass)
64
+ assert @c.to_liquid.is_a?(TestClassC::LiquidDropClass)
65
+ end
66
+
67
+ def test_should_respond_to_liquid_methods
68
+ assert @a.to_liquid.respond_to?(:allowedA)
69
+ assert @a.to_liquid.respond_to?(:chainedB)
70
+ assert @b.to_liquid.respond_to?(:allowedB)
71
+ assert @b.to_liquid.respond_to?(:chainedC)
72
+ assert @c.to_liquid.respond_to?(:allowedC)
73
+ assert @c.to_liquid.respond_to?(:another_allowedC)
74
+ end
75
+
76
+ def test_should_not_respond_to_restricted_methods
77
+ assert ! @a.to_liquid.respond_to?(:restricted)
78
+ end
79
+
80
+ def test_should_use_regular_objects_as_drops
81
+ assert_equal 'allowedA', Liquid::Template.parse("{{ a.allowedA }}").render('a'=>@a)
82
+ assert_equal 'allowedB', Liquid::Template.parse("{{ a.chainedB.allowedB }}").render('a'=>@a)
83
+ assert_equal 'allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.allowedC }}").render('a'=>@a)
84
+ assert_equal 'another_allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.another_allowedC }}").render('a'=>@a)
85
+ assert_equal '', Liquid::Template.parse("{{ a.restricted }}").render('a'=>@a)
86
+ assert_equal '', Liquid::Template.parse("{{ a.unknown }}").render('a'=>@a)
87
+ end
88
+
89
+ end
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+ module FunnyFilter
5
+
6
+ def make_funny(input)
7
+ 'LOL'
8
+ end
9
+
10
+ def cite_funny(input)
11
+ "LOL: #{input}"
12
+ end
13
+
14
+ def add_smiley(input, smiley = ":-)")
15
+ "#{input} #{smiley}"
16
+ end
17
+
18
+ def add_tag(input, tag = "p", id = "foo")
19
+ %|<#{tag} id="#{id}">#{input}</#{tag}>|
20
+ end
21
+
22
+ def paragraph(input)
23
+ "<p>#{input}</p>"
24
+ end
25
+
26
+ def link_to(name, url)
27
+ %|<a href="#{url}">#{name}</a>|
28
+ end
29
+ end
30
+
31
+
32
+ class OutputTest < Test::Unit::TestCase
33
+ include Liquid
34
+
35
+ def setup
36
+ @assigns = {
37
+ 'best_cars' => 'bmw',
38
+ 'car' => {'bmw' => 'good', 'gm' => 'bad'}
39
+ }
40
+
41
+ end
42
+
43
+ def test_variable
44
+ text = %| {{best_cars}} |
45
+
46
+ expected = %| bmw |
47
+ assert_equal expected, Template.parse(text).render(@assigns)
48
+ end
49
+
50
+ def test_variable_traversing
51
+ text = %| {{car.bmw}} {{car.gm}} {{car.bmw}} |
52
+
53
+ expected = %| good bad good |
54
+ assert_equal expected, Template.parse(text).render(@assigns)
55
+ end
56
+
57
+ def test_variable_piping
58
+ text = %( {{ car.gm | make_funny }} )
59
+ expected = %| LOL |
60
+
61
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
62
+ end
63
+
64
+ def test_variable_piping_with_input
65
+ text = %( {{ car.gm | cite_funny }} )
66
+ expected = %| LOL: bad |
67
+
68
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
69
+ end
70
+
71
+ def test_variable_piping_with_args
72
+ text = %! {{ car.gm | add_smiley : ':-(' }} !
73
+ expected = %| bad :-( |
74
+
75
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
76
+ end
77
+
78
+ def test_variable_piping_with_no_args
79
+ text = %! {{ car.gm | add_smiley }} !
80
+ expected = %| bad :-) |
81
+
82
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
83
+ end
84
+
85
+ def test_multiple_variable_piping_with_args
86
+ text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
87
+ expected = %| bad :-( :-( |
88
+
89
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
90
+ end
91
+
92
+ def test_variable_piping_with_args
93
+ text = %! {{ car.gm | add_tag : 'span', 'bar'}} !
94
+ expected = %| <span id="bar">bad</span> |
95
+
96
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
97
+ end
98
+
99
+ def test_variable_piping_with_variable_args
100
+ text = %! {{ car.gm | add_tag : 'span', car.bmw}} !
101
+ expected = %| <span id="good">bad</span> |
102
+
103
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
104
+ end
105
+
106
+ def test_multiple_pipings
107
+ text = %( {{ best_cars | cite_funny | paragraph }} )
108
+ expected = %| <p>LOL: bmw</p> |
109
+
110
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
111
+ end
112
+
113
+ def test_link_to
114
+ text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
115
+ expected = %| <a href="http://typo.leetsoft.com">Typo</a> |
116
+
117
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
118
+ end
119
+
120
+
121
+ end
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+ class ParsingQuirksTest < Test::Unit::TestCase
5
+ include Liquid
6
+
7
+ def test_error_with_css
8
+ text = %| div { font-weight: bold; } |
9
+ template = Template.parse(text)
10
+
11
+ assert_equal text, template.render
12
+ assert_equal [String], template.root.nodelist.collect {|i| i.class}
13
+ end
14
+
15
+ def test_raise_on_single_close_bracet
16
+ assert_raise(SyntaxError) do
17
+ Template.parse("text {{method} oh nos!")
18
+ end
19
+ end
20
+
21
+ def test_raise_on_label_and_no_close_bracets
22
+ assert_raise(SyntaxError) do
23
+ Template.parse("TEST {{ ")
24
+ end
25
+ end
26
+
27
+ def test_raise_on_label_and_no_close_bracets_percent
28
+ assert_raise(SyntaxError) do
29
+ Template.parse("TEST {% ")
30
+ end
31
+ end
32
+
33
+ def test_error_on_empty_filter
34
+ assert_nothing_raised do
35
+ Template.parse("{{test |a|b|}}")
36
+ Template.parse("{{test}}")
37
+ Template.parse("{{|test|}}")
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,45 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class RegexpTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_empty
7
+ assert_equal [], ''.scan(QuotedFragment)
8
+ end
9
+
10
+ def test_quote
11
+ assert_equal ['"arg 1"'], '"arg 1"'.scan(QuotedFragment)
12
+ end
13
+
14
+ def test_words
15
+ assert_equal ['arg1', 'arg2'], 'arg1 arg2'.scan(QuotedFragment)
16
+ end
17
+
18
+ def test_tags
19
+ assert_equal ['<tr>', '</tr>'], '<tr> </tr>'.scan(QuotedFragment)
20
+ assert_equal ['<tr></tr>'], '<tr></tr>'.scan(QuotedFragment)
21
+ assert_equal ['<style', 'class="hello">', '</style>'], %|<style class="hello">' </style>|.scan(QuotedFragment)
22
+ end
23
+
24
+ def test_quoted_words
25
+ assert_equal ['arg1', 'arg2', '"arg 3"'], 'arg1 arg2 "arg 3"'.scan(QuotedFragment)
26
+ end
27
+
28
+ def test_quoted_words
29
+ assert_equal ['arg1', 'arg2', "'arg 3'"], 'arg1 arg2 \'arg 3\''.scan(QuotedFragment)
30
+ end
31
+
32
+ def test_quoted_words_in_the_middle
33
+ assert_equal ['arg1', 'arg2', '"arg 3"', 'arg4'], 'arg1 arg2 "arg 3" arg4 '.scan(QuotedFragment)
34
+ end
35
+
36
+ def test_variable_parser
37
+ assert_equal ['var'], 'var'.scan(VariableParser)
38
+ assert_equal ['var', 'method'], 'var.method'.scan(VariableParser)
39
+ assert_equal ['var', '[method]'], 'var[method]'.scan(VariableParser)
40
+ assert_equal ['var', '[method]', '[0]'], 'var[method][0]'.scan(VariableParser)
41
+ assert_equal ['var', '["method"]', '[0]'], 'var["method"][0]'.scan(VariableParser)
42
+ assert_equal ['var', '[method]', '[0]', 'method'], 'var[method][0].method'.scan(VariableParser)
43
+ end
44
+
45
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ module SecurityFilter
4
+ def add_one(input)
5
+ "#{input} + 1"
6
+ end
7
+ end
8
+
9
+ class SecurityTest < Test::Unit::TestCase
10
+ include Liquid
11
+
12
+ def test_no_instance_eval
13
+ text = %( {{ '1+1' | instance_eval }} )
14
+ expected = %! Liquid error: Error - filter 'instance_eval' in ''1+1' | instance_eval' could not be found. !
15
+
16
+ assert_equal expected, Template.parse(text).render(@assigns)
17
+ end
18
+
19
+ def test_no_existing_instance_eval
20
+ text = %( {{ '1+1' | __instance_eval__ }} )
21
+ expected = %! Liquid error: Error - filter '__instance_eval__' in ''1+1' | __instance_eval__' could not be found. !
22
+
23
+ assert_equal expected, Template.parse(text).render(@assigns)
24
+ end
25
+
26
+
27
+ def test_no_instance_eval_after_mixing_in_new_filter
28
+ text = %( {{ '1+1' | instance_eval }} )
29
+ expected = %! Liquid error: Error - filter 'instance_eval' in ''1+1' | instance_eval' could not be found. !
30
+
31
+ assert_equal expected, Template.parse(text).render(@assigns)
32
+ end
33
+
34
+
35
+ def test_no_instance_eval_later_in_chain
36
+ text = %( {{ '1+1' | add_one | instance_eval }} )
37
+ expected = %! Liquid error: Error - filter 'instance_eval' in ''1+1' | add_one | instance_eval' could not be found. !
38
+
39
+ assert_equal expected, Template.parse(text).render(@assigns, :filters => SecurityFilter)
40
+ end
41
+ end
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+
5
+ class Filters
6
+ include Liquid::StandardFilters
7
+ end
8
+
9
+
10
+ class StandardFiltersTest < Test::Unit::TestCase
11
+ include Liquid
12
+
13
+ def setup
14
+ @filters = Filters.new
15
+ end
16
+
17
+ def test_size
18
+ assert_equal 3, @filters.size([1,2,3])
19
+ assert_equal 0, @filters.size([])
20
+ assert_equal 0, @filters.size(nil)
21
+ end
22
+
23
+ def test_downcase
24
+ assert_equal 'testing', @filters.downcase("Testing")
25
+ assert_equal '', @filters.downcase(nil)
26
+ end
27
+
28
+ def test_upcase
29
+ assert_equal 'TESTING', @filters.upcase("Testing")
30
+ assert_equal '', @filters.upcase(nil)
31
+ end
32
+
33
+ def test_upcase
34
+ assert_equal 'TESTING', @filters.upcase("Testing")
35
+ assert_equal '', @filters.upcase(nil)
36
+ end
37
+
38
+ def test_truncate
39
+ assert_equal '1234...', @filters.truncate('1234567890', 7)
40
+ assert_equal '1234567890', @filters.truncate('1234567890', 20)
41
+ assert_equal '...', @filters.truncate('1234567890', 0)
42
+ assert_equal '1234567890', @filters.truncate('1234567890')
43
+ end
44
+
45
+ def test_escape
46
+ assert_equal '&lt;strong&gt;', @filters.escape('<strong>')
47
+ assert_equal '&lt;strong&gt;', @filters.h('<strong>')
48
+ end
49
+
50
+ def test_truncatewords
51
+ assert_equal 'one two three', @filters.truncatewords('one two three', 4)
52
+ assert_equal 'one two...', @filters.truncatewords('one two three', 2)
53
+ assert_equal 'one two three', @filters.truncatewords('one two three')
54
+ assert_equal 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...', @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15)
55
+ end
56
+
57
+ def test_strip_html
58
+ assert_equal 'test', @filters.strip_html("<div>test</div>")
59
+ assert_equal 'test', @filters.strip_html("<div id='test'>test</div>")
60
+ assert_equal '', @filters.strip_html(nil)
61
+ end
62
+
63
+ def test_join
64
+ assert_equal '1 2 3 4', @filters.join([1,2,3,4])
65
+ assert_equal '1 - 2 - 3 - 4', @filters.join([1,2,3,4], ' - ')
66
+ end
67
+
68
+ def test_sort
69
+ assert_equal [1,2,3,4], @filters.sort([4,3,2,1])
70
+ assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
71
+ end
72
+
73
+ def test_map
74
+ assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
75
+ assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
76
+ 'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
77
+ end
78
+
79
+ def test_date
80
+ assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
81
+ assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
82
+ assert_equal 'July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B")
83
+
84
+ assert_equal 'May', @filters.date("2006-05-05 10:00:00", "%B")
85
+ assert_equal 'June', @filters.date("2006-06-05 10:00:00", "%B")
86
+ assert_equal 'July', @filters.date("2006-07-05 10:00:00", "%B")
87
+
88
+ assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
89
+ assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
90
+ assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")
91
+ assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil)
92
+
93
+ assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
94
+
95
+ assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
96
+
97
+ assert_equal nil, @filters.date(nil, "%B")
98
+ end
99
+
100
+
101
+ def test_first_last
102
+ assert_equal 1, @filters.first([1,2,3])
103
+ assert_equal 3, @filters.last([1,2,3])
104
+ assert_equal nil, @filters.first([])
105
+ assert_equal nil, @filters.last([])
106
+ end
107
+
108
+ def test_replace
109
+ assert_equal 'b b b b', @filters.replace("a a a a", 'a', 'b')
110
+ assert_equal 'b a a a', @filters.replace_first("a a a a", 'a', 'b')
111
+ assert_template_result 'b a a a', "{{ 'a a a a' | replace_first: 'a', 'b' }}"
112
+ end
113
+
114
+ def test_remove
115
+ assert_equal ' ', @filters.remove("a a a a", 'a')
116
+ assert_equal 'a a a', @filters.remove_first("a a a a", 'a ')
117
+ assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
118
+ end
119
+
120
+ def test_strip_newlines
121
+ assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc"
122
+ end
123
+
124
+ def test_newlines_to_br
125
+ assert_template_result "a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc"
126
+ end
127
+
128
+ def test_plus
129
+ assert_template_result "2", "{{ 1 | plus:1 }}"
130
+ assert_template_result "11", "{{ '1' | plus:'1' }}"
131
+ end
132
+
133
+ def test_minus
134
+ assert_template_result "4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1
135
+ end
136
+
137
+ def test_times
138
+ assert_template_result "12", "{{ 3 | times:4 }}"
139
+ assert_template_result "foofoofoofoo", "{{ 'foo' | times:4 }}"
140
+ end
141
+
142
+ def test_append
143
+ assigns = {'a' => 'bc', 'b' => 'd' }
144
+ assert_template_result('bcd',"{{ a | append: 'd'}}",assigns)
145
+ assert_template_result('bcd',"{{ a | append: b}}",assigns)
146
+ end
147
+
148
+ def test_prepend
149
+ assigns = {'a' => 'bc', 'b' => 'a' }
150
+ assert_template_result('abc',"{{ a | prepend: 'a'}}",assigns)
151
+ assert_template_result('abc',"{{ a | prepend: b}}",assigns)
152
+ end
153
+
154
+ def test_divided_by
155
+ assert_template_result "4", "{{ 12 | divided_by:3 }}"
156
+ assert_template_result "4", "{{ 14 | divided_by:3 }}"
157
+ assert_template_result "5", "{{ 15 | divided_by:3 }}"
158
+ end
159
+
160
+ end
161
+