spinto-liquid 2.3.0.1

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 (62) hide show
  1. data/History.md +56 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +44 -0
  4. data/lib/extras/liquid_view.rb +51 -0
  5. data/lib/liquid/block.rb +101 -0
  6. data/lib/liquid/condition.rb +120 -0
  7. data/lib/liquid/context.rb +245 -0
  8. data/lib/liquid/document.rb +17 -0
  9. data/lib/liquid/drop.rb +49 -0
  10. data/lib/liquid/errors.rb +11 -0
  11. data/lib/liquid/extensions.rb +62 -0
  12. data/lib/liquid/file_system.rb +62 -0
  13. data/lib/liquid/htmltags.rb +75 -0
  14. data/lib/liquid/module_ex.rb +62 -0
  15. data/lib/liquid/standardfilters.rb +241 -0
  16. data/lib/liquid/strainer.rb +54 -0
  17. data/lib/liquid/tag.rb +26 -0
  18. data/lib/liquid/tags/assign.rb +33 -0
  19. data/lib/liquid/tags/capture.rb +35 -0
  20. data/lib/liquid/tags/case.rb +79 -0
  21. data/lib/liquid/tags/comment.rb +9 -0
  22. data/lib/liquid/tags/cycle.rb +59 -0
  23. data/lib/liquid/tags/decrement.rb +39 -0
  24. data/lib/liquid/tags/for.rb +190 -0
  25. data/lib/liquid/tags/if.rb +79 -0
  26. data/lib/liquid/tags/ifchanged.rb +20 -0
  27. data/lib/liquid/tags/include.rb +65 -0
  28. data/lib/liquid/tags/increment.rb +35 -0
  29. data/lib/liquid/tags/raw.rb +21 -0
  30. data/lib/liquid/tags/unless.rb +33 -0
  31. data/lib/liquid/template.rb +150 -0
  32. data/lib/liquid/variable.rb +50 -0
  33. data/lib/liquid.rb +66 -0
  34. data/test/liquid/assign_test.rb +21 -0
  35. data/test/liquid/block_test.rb +58 -0
  36. data/test/liquid/capture_test.rb +40 -0
  37. data/test/liquid/condition_test.rb +127 -0
  38. data/test/liquid/context_test.rb +478 -0
  39. data/test/liquid/drop_test.rb +162 -0
  40. data/test/liquid/error_handling_test.rb +81 -0
  41. data/test/liquid/file_system_test.rb +29 -0
  42. data/test/liquid/filter_test.rb +106 -0
  43. data/test/liquid/module_ex_test.rb +87 -0
  44. data/test/liquid/output_test.rb +116 -0
  45. data/test/liquid/parsing_quirks_test.rb +52 -0
  46. data/test/liquid/regexp_test.rb +44 -0
  47. data/test/liquid/security_test.rb +41 -0
  48. data/test/liquid/standard_filter_test.rb +195 -0
  49. data/test/liquid/strainer_test.rb +25 -0
  50. data/test/liquid/tags/for_tag_test.rb +215 -0
  51. data/test/liquid/tags/html_tag_test.rb +39 -0
  52. data/test/liquid/tags/if_else_tag_test.rb +160 -0
  53. data/test/liquid/tags/include_tag_test.rb +139 -0
  54. data/test/liquid/tags/increment_tag_test.rb +24 -0
  55. data/test/liquid/tags/raw_tag_test.rb +15 -0
  56. data/test/liquid/tags/standard_tag_test.rb +295 -0
  57. data/test/liquid/tags/statements_test.rb +134 -0
  58. data/test/liquid/tags/unless_else_tag_test.rb +26 -0
  59. data/test/liquid/template_test.rb +74 -0
  60. data/test/liquid/variable_test.rb +170 -0
  61. data/test/test_helper.rb +29 -0
  62. metadata +136 -0
@@ -0,0 +1,162 @@
1
+ require 'test_helper'
2
+
3
+ class ContextDrop < Liquid::Drop
4
+ def scopes
5
+ @context.scopes.size
6
+ end
7
+
8
+ def scopes_as_array
9
+ (1..@context.scopes.size).to_a
10
+ end
11
+
12
+ def loop_pos
13
+ @context['forloop.index']
14
+ end
15
+
16
+ def before_method(method)
17
+ return @context[method]
18
+ end
19
+ end
20
+
21
+ class ProductDrop < Liquid::Drop
22
+
23
+ class TextDrop < Liquid::Drop
24
+ def array
25
+ ['text1', 'text2']
26
+ end
27
+
28
+ def text
29
+ 'text1'
30
+ end
31
+ end
32
+
33
+ class CatchallDrop < Liquid::Drop
34
+ def before_method(method)
35
+ return 'method: ' << method.to_s
36
+ end
37
+ end
38
+
39
+ def texts
40
+ TextDrop.new
41
+ end
42
+
43
+ def catchall
44
+ CatchallDrop.new
45
+ end
46
+
47
+ def context
48
+ ContextDrop.new
49
+ end
50
+
51
+ protected
52
+ def callmenot
53
+ "protected"
54
+ end
55
+ end
56
+
57
+ class EnumerableDrop < Liquid::Drop
58
+
59
+ def size
60
+ 3
61
+ end
62
+
63
+ def each
64
+ yield 1
65
+ yield 2
66
+ yield 3
67
+ end
68
+ end
69
+
70
+ class DropsTest < Test::Unit::TestCase
71
+ include Liquid
72
+
73
+ def test_product_drop
74
+
75
+ assert_nothing_raised do
76
+ tpl = Liquid::Template.parse( ' ' )
77
+ tpl.render('product' => ProductDrop.new)
78
+ end
79
+ end
80
+
81
+ def test_text_drop
82
+ output = Liquid::Template.parse( ' {{ product.texts.text }} ' ).render('product' => ProductDrop.new)
83
+ assert_equal ' text1 ', output
84
+
85
+ end
86
+
87
+ def test_unknown_method
88
+ output = Liquid::Template.parse( ' {{ product.catchall.unknown }} ' ).render('product' => ProductDrop.new)
89
+ assert_equal ' method: unknown ', output
90
+
91
+ end
92
+
93
+ def test_integer_argument_drop
94
+ output = Liquid::Template.parse( ' {{ product.catchall[8] }} ' ).render('product' => ProductDrop.new)
95
+ assert_equal ' method: 8 ', output
96
+ end
97
+
98
+ def test_text_array_drop
99
+ output = Liquid::Template.parse( '{% for text in product.texts.array %} {{text}} {% endfor %}' ).render('product' => ProductDrop.new)
100
+ assert_equal ' text1 text2 ', output
101
+ end
102
+
103
+ def test_context_drop
104
+ output = Liquid::Template.parse( ' {{ context.bar }} ' ).render('context' => ContextDrop.new, 'bar' => "carrot")
105
+ assert_equal ' carrot ', output
106
+ end
107
+
108
+ def test_nested_context_drop
109
+ output = Liquid::Template.parse( ' {{ product.context.foo }} ' ).render('product' => ProductDrop.new, 'foo' => "monkey")
110
+ assert_equal ' monkey ', output
111
+ end
112
+
113
+ def test_protected
114
+ output = Liquid::Template.parse( ' {{ product.callmenot }} ' ).render('product' => ProductDrop.new)
115
+ assert_equal ' ', output
116
+ end
117
+
118
+ def test_scope
119
+ assert_equal '1', Liquid::Template.parse( '{{ context.scopes }}' ).render('context' => ContextDrop.new)
120
+ assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ context.scopes }}{%endfor%}' ).render('context' => ContextDrop.new, 'dummy' => [1])
121
+ assert_equal '3', Liquid::Template.parse( '{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}' ).render('context' => ContextDrop.new, 'dummy' => [1])
122
+ end
123
+
124
+ def test_scope_though_proc
125
+ assert_equal '1', Liquid::Template.parse( '{{ s }}' ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] })
126
+ assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ s }}{%endfor%}' ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] }, 'dummy' => [1])
127
+ assert_equal '3', Liquid::Template.parse( '{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}' ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] }, 'dummy' => [1])
128
+ end
129
+
130
+ def test_scope_with_assigns
131
+ assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{{a}}' ).render('context' => ContextDrop.new)
132
+ assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}' ).render('context' => ContextDrop.new, 'dummy' => [1])
133
+ assert_equal 'test', Liquid::Template.parse( '{% assign header_gif = "test"%}{{header_gif}}' ).render('context' => ContextDrop.new)
134
+ assert_equal 'test', Liquid::Template.parse( "{% assign header_gif = 'test'%}{{header_gif}}" ).render('context' => ContextDrop.new)
135
+ end
136
+
137
+ def test_scope_from_tags
138
+ assert_equal '1', Liquid::Template.parse( '{% for i in context.scopes_as_array %}{{i}}{% endfor %}' ).render('context' => ContextDrop.new, 'dummy' => [1])
139
+ assert_equal '12', Liquid::Template.parse( '{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}' ).render('context' => ContextDrop.new, 'dummy' => [1])
140
+ assert_equal '123', Liquid::Template.parse( '{%for a in dummy%}{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}{% endfor %}' ).render('context' => ContextDrop.new, 'dummy' => [1])
141
+ end
142
+
143
+ def test_access_context_from_drop
144
+ assert_equal '123', Liquid::Template.parse( '{%for a in dummy%}{{ context.loop_pos }}{% endfor %}' ).render('context' => ContextDrop.new, 'dummy' => [1,2,3])
145
+ end
146
+
147
+ def test_enumerable_drop
148
+ assert_equal '123', Liquid::Template.parse( '{% for c in collection %}{{c}}{% endfor %}').render('collection' => EnumerableDrop.new)
149
+ end
150
+
151
+ def test_enumerable_drop_size
152
+ assert_equal '3', Liquid::Template.parse( '{{collection.size}}').render('collection' => EnumerableDrop.new)
153
+ end
154
+
155
+ def test_empty_string_value_access
156
+ assert_equal '', Liquid::Template.parse('{{ product[value] }}').render('product' => ProductDrop.new, 'value' => '')
157
+ end
158
+
159
+ def test_nil_value_access
160
+ assert_equal '', Liquid::Template.parse('{{ product[value] }}').render('product' => ProductDrop.new, 'value' => nil)
161
+ end
162
+ end # DropsTest
@@ -0,0 +1,81 @@
1
+ require 'test_helper'
2
+
3
+ class ErrorDrop < Liquid::Drop
4
+ def standard_error
5
+ raise Liquid::StandardError, 'standard error'
6
+ end
7
+
8
+ def argument_error
9
+ raise Liquid::ArgumentError, 'argument error'
10
+ end
11
+
12
+ def syntax_error
13
+ raise Liquid::SyntaxError, 'syntax error'
14
+ end
15
+
16
+ def exception
17
+ raise Exception, 'exception'
18
+ end
19
+
20
+ end
21
+
22
+ class ErrorHandlingTest < Test::Unit::TestCase
23
+ include Liquid
24
+
25
+ def test_standard_error
26
+ assert_nothing_raised do
27
+ template = Liquid::Template.parse( ' {{ errors.standard_error }} ' )
28
+ assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
29
+
30
+ assert_equal 1, template.errors.size
31
+ assert_equal StandardError, template.errors.first.class
32
+ end
33
+ end
34
+
35
+ def test_syntax
36
+
37
+ assert_nothing_raised do
38
+
39
+ template = Liquid::Template.parse( ' {{ errors.syntax_error }} ' )
40
+ assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
41
+
42
+ assert_equal 1, template.errors.size
43
+ assert_equal SyntaxError, template.errors.first.class
44
+
45
+ end
46
+ end
47
+
48
+ def test_argument
49
+ assert_nothing_raised do
50
+
51
+ template = Liquid::Template.parse( ' {{ errors.argument_error }} ' )
52
+ assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
53
+
54
+ assert_equal 1, template.errors.size
55
+ assert_equal ArgumentError, template.errors.first.class
56
+ end
57
+ end
58
+
59
+ def test_missing_endtag_parse_time_error
60
+ assert_raise(Liquid::SyntaxError) do
61
+ template = Liquid::Template.parse(' {% for a in b %} ... ')
62
+ end
63
+ end
64
+
65
+ def test_unrecognized_operator
66
+ assert_nothing_raised do
67
+ template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
68
+ assert_equal ' Liquid error: Unknown operator =! ', template.render
69
+ assert_equal 1, template.errors.size
70
+ assert_equal Liquid::ArgumentError, template.errors.first.class
71
+ end
72
+ end
73
+
74
+ # Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
75
+ def test_exceptions_propagate
76
+ assert_raise Exception do
77
+ template = Liquid::Template.parse( ' {{ errors.exception }} ' )
78
+ template.render('errors' => ErrorDrop.new)
79
+ end
80
+ end
81
+ end # ErrorHandlingTest
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class FileSystemTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_default
7
+ assert_raise(FileSystemError) do
8
+ BlankFileSystem.new.read_template_file("dummy", {'dummy'=>'smarty'})
9
+ end
10
+ end
11
+
12
+ def test_local
13
+ file_system = Liquid::LocalFileSystem.new("/some/path")
14
+ assert_equal "/some/path/_mypartial.liquid" , file_system.full_path("mypartial")
15
+ assert_equal "/some/path/dir/_mypartial.liquid", file_system.full_path("dir/mypartial")
16
+
17
+ assert_raise(FileSystemError) do
18
+ file_system.full_path("../dir/mypartial")
19
+ end
20
+
21
+ assert_raise(FileSystemError) do
22
+ file_system.full_path("/dir/../../dir/mypartial")
23
+ end
24
+
25
+ assert_raise(FileSystemError) do
26
+ file_system.full_path("/etc/passwd")
27
+ end
28
+ end
29
+ end # FileSystemTest
@@ -0,0 +1,106 @@
1
+ require 'test_helper'
2
+
3
+ module MoneyFilter
4
+ def money(input)
5
+ sprintf(' %d$ ', input)
6
+ end
7
+
8
+ def money_with_underscore(input)
9
+ sprintf(' %d$ ', input)
10
+ end
11
+ end
12
+
13
+ module CanadianMoneyFilter
14
+ def money(input)
15
+ sprintf(' %d$ CAD ', input)
16
+ end
17
+ end
18
+
19
+ class FiltersTest < Test::Unit::TestCase
20
+ include Liquid
21
+
22
+ def setup
23
+ @context = Context.new
24
+ end
25
+
26
+ def test_local_filter
27
+ @context['var'] = 1000
28
+ @context.add_filters(MoneyFilter)
29
+
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
+
44
+ assert_equal ' 1000$ CAD ', Variable.new("var | money").render(@context)
45
+ end
46
+
47
+ def test_size
48
+ @context['var'] = 'abcd'
49
+ @context.add_filters(MoneyFilter)
50
+
51
+ assert_equal 4, Variable.new("var | size").render(@context)
52
+ end
53
+
54
+ def test_join
55
+ @context['var'] = [1,2,3,4]
56
+
57
+ assert_equal "1 2 3 4", Variable.new("var | join").render(@context)
58
+ end
59
+
60
+ def test_sort
61
+ @context['value'] = 3
62
+ @context['numbers'] = [2,1,4,3]
63
+ @context['words'] = ['expected', 'as', 'alphabetic']
64
+ @context['arrays'] = [['flattened'], ['are']]
65
+
66
+ assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context)
67
+ assert_equal ['alphabetic', 'as', 'expected'], Variable.new("words | sort").render(@context)
68
+ assert_equal [3], Variable.new("value | sort").render(@context)
69
+ assert_equal ['are', 'flattened'], Variable.new("arrays | sort").render(@context)
70
+ end
71
+
72
+ def test_strip_html
73
+ @context['var'] = "<b>bla blub</a>"
74
+
75
+ assert_equal "bla blub", Variable.new("var | strip_html").render(@context)
76
+ end
77
+
78
+ def test_capitalize
79
+ @context['var'] = "blub"
80
+
81
+ assert_equal "Blub", Variable.new("var | capitalize").render(@context)
82
+ end
83
+
84
+ def test_nonexistent_filter_is_ignored
85
+ @context['var'] = 1000
86
+
87
+ assert_equal 1000, Variable.new("var | xyzzy").render(@context)
88
+ end
89
+ end
90
+
91
+ class FiltersInTemplate < Test::Unit::TestCase
92
+ include Liquid
93
+
94
+ def test_local_global
95
+ Template.register_filter(MoneyFilter)
96
+
97
+ assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render(nil, nil)
98
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, :filters => CanadianMoneyFilter)
99
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, :filters => [CanadianMoneyFilter])
100
+ end
101
+
102
+ def test_local_filter_with_deprecated_syntax
103
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, CanadianMoneyFilter)
104
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, [CanadianMoneyFilter])
105
+ end
106
+ end # FiltersTest
@@ -0,0 +1,87 @@
1
+ require 'test_helper'
2
+
3
+ class TestClassA
4
+ liquid_methods :allowedA, :chainedB
5
+ def allowedA
6
+ 'allowedA'
7
+ end
8
+ def restrictedA
9
+ 'restrictedA'
10
+ end
11
+ def chainedB
12
+ TestClassB.new
13
+ end
14
+ end
15
+
16
+ class TestClassB
17
+ liquid_methods :allowedB, :chainedC
18
+ def allowedB
19
+ 'allowedB'
20
+ end
21
+ def chainedC
22
+ TestClassC.new
23
+ end
24
+ end
25
+
26
+ class TestClassC
27
+ liquid_methods :allowedC
28
+ def allowedC
29
+ 'allowedC'
30
+ end
31
+ end
32
+
33
+ class TestClassC::LiquidDropClass
34
+ def another_allowedC
35
+ 'another_allowedC'
36
+ end
37
+ end
38
+
39
+ class ModuleExTest < Test::Unit::TestCase
40
+ include Liquid
41
+
42
+ def setup
43
+ @a = TestClassA.new
44
+ @b = TestClassB.new
45
+ @c = TestClassC.new
46
+ end
47
+
48
+ def test_should_create_LiquidDropClass
49
+ assert TestClassA::LiquidDropClass
50
+ assert TestClassB::LiquidDropClass
51
+ assert TestClassC::LiquidDropClass
52
+ end
53
+
54
+ def test_should_respond_to_liquid
55
+ assert @a.respond_to?(:to_liquid)
56
+ assert @b.respond_to?(:to_liquid)
57
+ assert @c.respond_to?(:to_liquid)
58
+ end
59
+
60
+ def test_should_return_LiquidDropClass_object
61
+ assert @a.to_liquid.is_a?(TestClassA::LiquidDropClass)
62
+ assert @b.to_liquid.is_a?(TestClassB::LiquidDropClass)
63
+ assert @c.to_liquid.is_a?(TestClassC::LiquidDropClass)
64
+ end
65
+
66
+ def test_should_respond_to_liquid_methods
67
+ assert @a.to_liquid.respond_to?(:allowedA)
68
+ assert @a.to_liquid.respond_to?(:chainedB)
69
+ assert @b.to_liquid.respond_to?(:allowedB)
70
+ assert @b.to_liquid.respond_to?(:chainedC)
71
+ assert @c.to_liquid.respond_to?(:allowedC)
72
+ assert @c.to_liquid.respond_to?(:another_allowedC)
73
+ end
74
+
75
+ def test_should_not_respond_to_restricted_methods
76
+ assert ! @a.to_liquid.respond_to?(:restricted)
77
+ end
78
+
79
+ def test_should_use_regular_objects_as_drops
80
+ assert_equal 'allowedA', Liquid::Template.parse("{{ a.allowedA }}").render('a'=>@a)
81
+ assert_equal 'allowedB', Liquid::Template.parse("{{ a.chainedB.allowedB }}").render('a'=>@a)
82
+ assert_equal 'allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.allowedC }}").render('a'=>@a)
83
+ assert_equal 'another_allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.another_allowedC }}").render('a'=>@a)
84
+ assert_equal '', Liquid::Template.parse("{{ a.restricted }}").render('a'=>@a)
85
+ assert_equal '', Liquid::Template.parse("{{ a.unknown }}").render('a'=>@a)
86
+ end
87
+ end # ModuleExTest