liquid 2.6.3 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +42 -13
  3. data/README.md +27 -2
  4. data/lib/liquid.rb +11 -11
  5. data/lib/liquid/block.rb +75 -45
  6. data/lib/liquid/condition.rb +15 -11
  7. data/lib/liquid/context.rb +68 -29
  8. data/lib/liquid/document.rb +3 -3
  9. data/lib/liquid/drop.rb +17 -1
  10. data/lib/liquid/file_system.rb +17 -6
  11. data/lib/liquid/i18n.rb +39 -0
  12. data/lib/liquid/interrupts.rb +1 -1
  13. data/lib/liquid/lexer.rb +51 -0
  14. data/lib/liquid/locales/en.yml +22 -0
  15. data/lib/liquid/parser.rb +90 -0
  16. data/lib/liquid/standardfilters.rb +115 -52
  17. data/lib/liquid/strainer.rb +14 -4
  18. data/lib/liquid/tag.rb +42 -7
  19. data/lib/liquid/tags/assign.rb +10 -8
  20. data/lib/liquid/tags/break.rb +1 -1
  21. data/lib/liquid/tags/capture.rb +10 -8
  22. data/lib/liquid/tags/case.rb +13 -13
  23. data/lib/liquid/tags/comment.rb +9 -2
  24. data/lib/liquid/tags/continue.rb +1 -4
  25. data/lib/liquid/tags/cycle.rb +5 -7
  26. data/lib/liquid/tags/decrement.rb +3 -4
  27. data/lib/liquid/tags/for.rb +69 -36
  28. data/lib/liquid/tags/if.rb +52 -25
  29. data/lib/liquid/tags/ifchanged.rb +2 -2
  30. data/lib/liquid/tags/include.rb +8 -7
  31. data/lib/liquid/tags/increment.rb +4 -8
  32. data/lib/liquid/tags/raw.rb +3 -3
  33. data/lib/liquid/tags/table_row.rb +73 -0
  34. data/lib/liquid/tags/unless.rb +2 -4
  35. data/lib/liquid/template.rb +69 -10
  36. data/lib/liquid/utils.rb +13 -4
  37. data/lib/liquid/variable.rb +59 -8
  38. data/lib/liquid/version.rb +1 -1
  39. data/test/fixtures/en_locale.yml +9 -0
  40. data/test/{liquid → integration}/assign_test.rb +6 -0
  41. data/test/integration/blank_test.rb +106 -0
  42. data/test/{liquid → integration}/capture_test.rb +2 -2
  43. data/test/integration/context_test.rb +33 -0
  44. data/test/integration/drop_test.rb +245 -0
  45. data/test/{liquid → integration}/error_handling_test.rb +31 -2
  46. data/test/{liquid → integration}/filter_test.rb +7 -7
  47. data/test/{liquid → integration}/hash_ordering_test.rb +0 -0
  48. data/test/{liquid → integration}/output_test.rb +12 -12
  49. data/test/integration/parsing_quirks_test.rb +94 -0
  50. data/test/{liquid → integration}/security_test.rb +9 -9
  51. data/test/{liquid → integration}/standard_filter_test.rb +103 -33
  52. data/test/{liquid → integration}/tags/break_tag_test.rb +0 -0
  53. data/test/{liquid → integration}/tags/continue_tag_test.rb +0 -0
  54. data/test/{liquid → integration}/tags/for_tag_test.rb +78 -0
  55. data/test/{liquid → integration}/tags/if_else_tag_test.rb +1 -1
  56. data/test/integration/tags/include_tag_test.rb +212 -0
  57. data/test/{liquid → integration}/tags/increment_tag_test.rb +0 -0
  58. data/test/{liquid → integration}/tags/raw_tag_test.rb +1 -0
  59. data/test/{liquid → integration}/tags/standard_tag_test.rb +24 -22
  60. data/test/integration/tags/statements_test.rb +113 -0
  61. data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +5 -5
  62. data/test/{liquid → integration}/tags/unless_else_tag_test.rb +0 -0
  63. data/test/{liquid → integration}/template_test.rb +66 -42
  64. data/test/integration/variable_test.rb +72 -0
  65. data/test/test_helper.rb +32 -7
  66. data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +1 -1
  67. data/test/{liquid/condition_test.rb → unit/condition_unit_test.rb} +19 -1
  68. data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +27 -19
  69. data/test/{liquid/file_system_test.rb → unit/file_system_unit_test.rb} +7 -1
  70. data/test/unit/i18n_unit_test.rb +37 -0
  71. data/test/unit/lexer_unit_test.rb +48 -0
  72. data/test/{liquid/module_ex_test.rb → unit/module_ex_unit_test.rb} +7 -7
  73. data/test/unit/parser_unit_test.rb +82 -0
  74. data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +3 -3
  75. data/test/{liquid/strainer_test.rb → unit/strainer_unit_test.rb} +19 -1
  76. data/test/unit/tag_unit_test.rb +11 -0
  77. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  78. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  79. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  80. data/test/unit/template_unit_test.rb +69 -0
  81. data/test/unit/tokenizer_unit_test.rb +29 -0
  82. data/test/{liquid/variable_test.rb → unit/variable_unit_test.rb} +17 -67
  83. metadata +117 -73
  84. data/lib/extras/liquid_view.rb +0 -51
  85. data/lib/liquid/htmltags.rb +0 -73
  86. data/test/liquid/drop_test.rb +0 -180
  87. data/test/liquid/parsing_quirks_test.rb +0 -52
  88. data/test/liquid/tags/include_tag_test.rb +0 -166
  89. data/test/liquid/tags/statements_test.rb +0 -134
data/lib/liquid/utils.rb CHANGED
@@ -1,5 +1,18 @@
1
1
  module Liquid
2
2
  module Utils
3
+
4
+ def self.slice_collection(collection, from, to)
5
+ if (from != 0 || to != nil) && collection.respond_to?(:load_slice)
6
+ collection.load_slice(from, to)
7
+ else
8
+ slice_collection_using_each(collection, from, to)
9
+ end
10
+ end
11
+
12
+ def self.non_blank_string?(collection)
13
+ collection.is_a?(String) && collection != ''.freeze
14
+ end
15
+
3
16
  def self.slice_collection_using_each(collection, from, to)
4
17
  segments = []
5
18
  index = 0
@@ -22,9 +35,5 @@ module Liquid
22
35
 
23
36
  segments
24
37
  end
25
-
26
- def self.non_blank_string?(collection)
27
- collection.is_a?(String) && collection != ''
28
- end
29
38
  end
30
39
  end
@@ -12,19 +12,37 @@ module Liquid
12
12
  #
13
13
  class Variable
14
14
  FilterParser = /(?:#{FilterSeparator}|(?:\s*(?:#{QuotedFragment}|#{ArgumentSeparator})\s*)+)/o
15
- attr_accessor :filters, :name
15
+ EasyParse = /\A *(\w+(?:\.\w+)*) *\z/
16
+ attr_accessor :filters, :name, :warnings
16
17
 
17
- def initialize(markup)
18
+ def initialize(markup, options = {})
18
19
  @markup = markup
19
20
  @name = nil
21
+ @options = options || {}
22
+
23
+ case @options[:error_mode] || Template.error_mode
24
+ when :strict then strict_parse(markup)
25
+ when :lax then lax_parse(markup)
26
+ when :warn
27
+ begin
28
+ strict_parse(markup)
29
+ rescue SyntaxError => e
30
+ @warnings ||= []
31
+ @warnings << e
32
+ lax_parse(markup)
33
+ end
34
+ end
35
+ end
36
+
37
+ def lax_parse(markup)
20
38
  @filters = []
21
- if match = markup.match(/\s*(#{QuotedFragment})(.*)/o)
22
- @name = match[1]
23
- if match[2].match(/#{FilterSeparator}\s*(.*)/o)
39
+ if markup =~ /\s*(#{QuotedFragment})(.*)/om
40
+ @name = Regexp.last_match(1)
41
+ if Regexp.last_match(2) =~ /#{FilterSeparator}\s*(.*)/om
24
42
  filters = Regexp.last_match(1).scan(FilterParser)
25
43
  filters.each do |f|
26
- if matches = f.match(/\s*(\w+)/)
27
- filtername = matches[1]
44
+ if f =~ /\s*(\w+)/
45
+ filtername = Regexp.last_match(1)
28
46
  filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
29
47
  @filters << [filtername, filterargs]
30
48
  end
@@ -33,8 +51,41 @@ module Liquid
33
51
  end
34
52
  end
35
53
 
54
+ def strict_parse(markup)
55
+ # Very simple valid cases
56
+ if markup =~ EasyParse
57
+ @name = $1
58
+ @filters = []
59
+ return
60
+ end
61
+
62
+ @filters = []
63
+ p = Parser.new(markup)
64
+ # Could be just filters with no input
65
+ @name = p.look(:pipe) ? ''.freeze : p.expression
66
+ while p.consume?(:pipe)
67
+ filtername = p.consume(:id)
68
+ filterargs = p.consume?(:colon) ? parse_filterargs(p) : []
69
+ @filters << [filtername, filterargs]
70
+ end
71
+ p.consume(:end_of_string)
72
+ rescue SyntaxError => e
73
+ e.message << " in \"{{#{markup}}}\""
74
+ raise e
75
+ end
76
+
77
+ def parse_filterargs(p)
78
+ # first argument
79
+ filterargs = [p.argument]
80
+ # followed by comma separated others
81
+ while p.consume?(:comma)
82
+ filterargs << p.argument
83
+ end
84
+ filterargs
85
+ end
86
+
36
87
  def render(context)
37
- return '' if @name.nil?
88
+ return ''.freeze if @name.nil?
38
89
  @filters.inject(context[@name]) do |output, filter|
39
90
  filterargs = []
40
91
  keyword_args = {}
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Liquid
3
- VERSION = "2.6.3"
3
+ VERSION = "3.0.0.rc1"
4
4
  end
@@ -0,0 +1,9 @@
1
+ ---
2
+ simple: "less is more"
3
+ whatever: "something %{something}"
4
+ errors:
5
+ i18n:
6
+ undefined_interpolation: "undefined key %{key}"
7
+ unknown_translation: "translation '%{name}' wasn't found"
8
+ syntax:
9
+ oops: "something wasn't right"
@@ -18,4 +18,10 @@ class AssignTest < Test::Unit::TestCase
18
18
  '{% assign foo = values | split: "," %}.{{ foo[1] }}.',
19
19
  'values' => "foo,bar,baz")
20
20
  end
21
+
22
+ def test_assign_syntax_error
23
+ assert_match_syntax_error(/assign/,
24
+ '{% assign foo not values %}.',
25
+ 'values' => "foo,bar,baz")
26
+ end
21
27
  end # AssignTest
@@ -0,0 +1,106 @@
1
+ require 'test_helper'
2
+
3
+ class FoobarTag < Liquid::Tag
4
+ def render(*args)
5
+ " "
6
+ end
7
+
8
+ Liquid::Template.register_tag('foobar', FoobarTag)
9
+ end
10
+
11
+ class BlankTestFileSystem
12
+ def read_template_file(template_path, context)
13
+ template_path
14
+ end
15
+ end
16
+
17
+ class BlankTest < Test::Unit::TestCase
18
+ include Liquid
19
+ N = 10
20
+
21
+ def wrap_in_for(body)
22
+ "{% for i in (1..#{N}) %}#{body}{% endfor %}"
23
+ end
24
+
25
+ def wrap_in_if(body)
26
+ "{% if true %}#{body}{% endif %}"
27
+ end
28
+
29
+ def wrap(body)
30
+ wrap_in_for(body) + wrap_in_if(body)
31
+ end
32
+
33
+ def test_new_tags_are_not_blank_by_default
34
+ assert_template_result(" "*N, wrap_in_for("{% foobar %}"))
35
+ end
36
+
37
+ def test_loops_are_blank
38
+ assert_template_result("", wrap_in_for(" "))
39
+ end
40
+
41
+ def test_if_else_are_blank
42
+ assert_template_result("", "{% if true %} {% elsif false %} {% else %} {% endif %}")
43
+ end
44
+
45
+ def test_unless_is_blank
46
+ assert_template_result("", wrap("{% unless true %} {% endunless %}"))
47
+ end
48
+
49
+ def test_mark_as_blank_only_during_parsing
50
+ assert_template_result(" "*(N+1), wrap(" {% if false %} this never happens, but still, this block is not blank {% endif %}"))
51
+ end
52
+
53
+ def test_comments_are_blank
54
+ assert_template_result("", wrap(" {% comment %} whatever {% endcomment %} "))
55
+ end
56
+
57
+ def test_captures_are_blank
58
+ assert_template_result("", wrap(" {% capture foo %} whatever {% endcapture %} "))
59
+ end
60
+
61
+ def test_nested_blocks_are_blank_but_only_if_all_children_are
62
+ assert_template_result("", wrap(wrap(" ")))
63
+ assert_template_result("\n but this is not "*(N+1),
64
+ wrap(%q{{% if true %} {% comment %} this is blank {% endcomment %} {% endif %}
65
+ {% if true %} but this is not {% endif %}}))
66
+ end
67
+
68
+ def test_assigns_are_blank
69
+ assert_template_result("", wrap(' {% assign foo = "bar" %} '))
70
+ end
71
+
72
+ def test_whitespace_is_blank
73
+ assert_template_result("", wrap(" "))
74
+ assert_template_result("", wrap("\t"))
75
+ end
76
+
77
+ def test_whitespace_is_not_blank_if_other_stuff_is_present
78
+ body = " x "
79
+ assert_template_result(body*(N+1), wrap(body))
80
+ end
81
+
82
+ def test_increment_is_not_blank
83
+ assert_template_result(" 0"*2*(N+1), wrap("{% assign foo = 0 %} {% increment foo %} {% decrement foo %}"))
84
+ end
85
+
86
+ def test_cycle_is_not_blank
87
+ assert_template_result(" "*((N+1)/2)+" ", wrap("{% cycle ' ', ' ' %}"))
88
+ end
89
+
90
+ def test_raw_is_not_blank
91
+ assert_template_result(" "*(N+1), wrap(" {% raw %} {% endraw %}"))
92
+ end
93
+
94
+ def test_include_is_blank
95
+ Liquid::Template.file_system = BlankTestFileSystem.new
96
+ assert_template_result "foobar"*(N+1), wrap("{% include 'foobar' %}")
97
+ assert_template_result " foobar "*(N+1), wrap("{% include ' foobar ' %}")
98
+ assert_template_result " "*(N+1), wrap(" {% include ' ' %} ")
99
+ end
100
+
101
+ def test_case_is_blank
102
+ assert_template_result("", wrap(" {% assign foo = 'bar' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} "))
103
+ assert_template_result("", wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} {% endcase %} "))
104
+ assert_template_result(" x "*(N+1), wrap(" {% assign foo = 'else' %} {% case foo %} {% when 'bar' %} {% when 'whatever' %} {% else %} x {% endcase %} "))
105
+ end
106
+ end
@@ -19,7 +19,7 @@ class CaptureTest < Test::Unit::TestCase
19
19
  {{var}}
20
20
  END_TEMPLATE
21
21
  template = Template.parse(template_source)
22
- rendered = template.render
22
+ rendered = template.render!
23
23
  assert_equal "test-string", rendered.gsub(/\s/, '')
24
24
  end
25
25
 
@@ -34,7 +34,7 @@ class CaptureTest < Test::Unit::TestCase
34
34
  {{ first }}-{{ second }}
35
35
  END_TEMPLATE
36
36
  template = Template.parse(template_source)
37
- rendered = template.render
37
+ rendered = template.render!
38
38
  assert_equal "3-3", rendered.gsub(/\s/, '')
39
39
  end
40
40
  end # CaptureTest
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class ContextTest < Test::Unit::TestCase
4
+ include Liquid
5
+
6
+ def test_override_global_filter
7
+ global = Module.new do
8
+ def notice(output)
9
+ "Global #{output}"
10
+ end
11
+ end
12
+
13
+ local = Module.new do
14
+ def notice(output)
15
+ "Local #{output}"
16
+ end
17
+ end
18
+
19
+ Template.register_filter(global)
20
+ assert_equal 'Global test', Template.parse("{{'test' | notice }}").render!
21
+ assert_equal 'Local test', Template.parse("{{'test' | notice }}").render!({}, :filters => [local])
22
+ end
23
+
24
+ def test_has_key_will_not_add_an_error_for_missing_keys
25
+ Template.error_mode = :strict
26
+
27
+ context = Context.new
28
+
29
+ context.has_key?('unknown')
30
+
31
+ assert_empty context.errors
32
+ end
33
+ end
@@ -0,0 +1,245 @@
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
+ def before_method(method)
59
+ method
60
+ end
61
+
62
+ def size
63
+ 3
64
+ end
65
+
66
+ def first
67
+ 1
68
+ end
69
+
70
+ def count
71
+ 3
72
+ end
73
+
74
+ def min
75
+ 1
76
+ end
77
+
78
+ def max
79
+ 3
80
+ end
81
+
82
+ def each
83
+ yield 1
84
+ yield 2
85
+ yield 3
86
+ end
87
+ end
88
+
89
+ class RealEnumerableDrop < Liquid::Drop
90
+ include Enumerable
91
+
92
+ def before_method(method)
93
+ method
94
+ end
95
+
96
+ def each
97
+ yield 1
98
+ yield 2
99
+ yield 3
100
+ end
101
+ end
102
+
103
+ class DropsTest < Test::Unit::TestCase
104
+ include Liquid
105
+
106
+ def test_product_drop
107
+ assert_nothing_raised do
108
+ tpl = Liquid::Template.parse( ' ' )
109
+ tpl.render!('product' => ProductDrop.new)
110
+ end
111
+ end
112
+
113
+ def test_drop_does_only_respond_to_whitelisted_methods
114
+ assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new)
115
+ assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new)
116
+ assert_equal "", Liquid::Template.parse("{{ product.whatever }}").render!('product' => ProductDrop.new)
117
+ assert_equal "", Liquid::Template.parse('{{ product | map: "inspect" }}').render!('product' => ProductDrop.new)
118
+ assert_equal "", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render!('product' => ProductDrop.new)
119
+ assert_equal "", Liquid::Template.parse('{{ product | map: "whatever" }}').render!('product' => ProductDrop.new)
120
+ end
121
+
122
+ def test_drops_respond_to_to_liquid
123
+ assert_equal "text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render!('product' => ProductDrop.new)
124
+ assert_equal "text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render!('product' => ProductDrop.new)
125
+ end
126
+
127
+ def test_text_drop
128
+ output = Liquid::Template.parse( ' {{ product.texts.text }} ' ).render!('product' => ProductDrop.new)
129
+ assert_equal ' text1 ', output
130
+ end
131
+
132
+ def test_unknown_method
133
+ output = Liquid::Template.parse( ' {{ product.catchall.unknown }} ' ).render!('product' => ProductDrop.new)
134
+ assert_equal ' method: unknown ', output
135
+ end
136
+
137
+ def test_integer_argument_drop
138
+ output = Liquid::Template.parse( ' {{ product.catchall[8] }} ' ).render!('product' => ProductDrop.new)
139
+ assert_equal ' method: 8 ', output
140
+ end
141
+
142
+ def test_text_array_drop
143
+ output = Liquid::Template.parse( '{% for text in product.texts.array %} {{text}} {% endfor %}' ).render!('product' => ProductDrop.new)
144
+ assert_equal ' text1 text2 ', output
145
+ end
146
+
147
+ def test_context_drop
148
+ output = Liquid::Template.parse( ' {{ context.bar }} ' ).render!('context' => ContextDrop.new, 'bar' => "carrot")
149
+ assert_equal ' carrot ', output
150
+ end
151
+
152
+ def test_nested_context_drop
153
+ output = Liquid::Template.parse( ' {{ product.context.foo }} ' ).render!('product' => ProductDrop.new, 'foo' => "monkey")
154
+ assert_equal ' monkey ', output
155
+ end
156
+
157
+ def test_protected
158
+ output = Liquid::Template.parse( ' {{ product.callmenot }} ' ).render!('product' => ProductDrop.new)
159
+ assert_equal ' ', output
160
+ end
161
+
162
+ def test_object_methods_not_allowed
163
+ [:dup, :clone, :singleton_class, :eval, :class_eval, :inspect].each do |method|
164
+ output = Liquid::Template.parse(" {{ product.#{method} }} ").render!('product' => ProductDrop.new)
165
+ assert_equal ' ', output
166
+ end
167
+ end
168
+
169
+ def test_scope
170
+ assert_equal '1', Liquid::Template.parse( '{{ context.scopes }}' ).render!('context' => ContextDrop.new)
171
+ assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ context.scopes }}{%endfor%}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
172
+ assert_equal '3', Liquid::Template.parse( '{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
173
+ end
174
+
175
+ def test_scope_though_proc
176
+ assert_equal '1', Liquid::Template.parse( '{{ s }}' ).render!('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] })
177
+ 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])
178
+ 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])
179
+ end
180
+
181
+ def test_scope_with_assigns
182
+ assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{{a}}' ).render!('context' => ContextDrop.new)
183
+ assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
184
+ assert_equal 'test', Liquid::Template.parse( '{% assign header_gif = "test"%}{{header_gif}}' ).render!('context' => ContextDrop.new)
185
+ assert_equal 'test', Liquid::Template.parse( "{% assign header_gif = 'test'%}{{header_gif}}" ).render!('context' => ContextDrop.new)
186
+ end
187
+
188
+ def test_scope_from_tags
189
+ assert_equal '1', Liquid::Template.parse( '{% for i in context.scopes_as_array %}{{i}}{% endfor %}' ).render!('context' => ContextDrop.new, 'dummy' => [1])
190
+ 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])
191
+ 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])
192
+ end
193
+
194
+ def test_access_context_from_drop
195
+ assert_equal '123', Liquid::Template.parse( '{%for a in dummy%}{{ context.loop_pos }}{% endfor %}' ).render!('context' => ContextDrop.new, 'dummy' => [1,2,3])
196
+ end
197
+
198
+ def test_enumerable_drop
199
+ assert_equal '123', Liquid::Template.parse( '{% for c in collection %}{{c}}{% endfor %}').render!('collection' => EnumerableDrop.new)
200
+ end
201
+
202
+ def test_enumerable_drop_size
203
+ assert_equal '3', Liquid::Template.parse( '{{collection.size}}').render!('collection' => EnumerableDrop.new)
204
+ end
205
+
206
+ def test_enumerable_drop_will_invoke_before_method_for_clashing_method_names
207
+ ["select", "each", "map", "cycle"].each do |method|
208
+ assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
209
+ assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
210
+ assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
211
+ assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
212
+ end
213
+ end
214
+
215
+ def test_some_enumerable_methods_still_get_invoked
216
+ [ :count, :max ].each do |method|
217
+ assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
218
+ assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
219
+ assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
220
+ assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
221
+ end
222
+
223
+ assert_equal "yes", Liquid::Template.parse("{% if collection contains 3 %}yes{% endif %}").render!('collection' => RealEnumerableDrop.new)
224
+
225
+ [ :min, :first ].each do |method|
226
+ assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
227
+ assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
228
+ assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
229
+ assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
230
+ end
231
+ end
232
+
233
+ def test_empty_string_value_access
234
+ assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => '')
235
+ end
236
+
237
+ def test_nil_value_access
238
+ assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => nil)
239
+ end
240
+
241
+ def test_default_to_s_on_drops
242
+ assert_equal 'ProductDrop', Liquid::Template.parse("{{ product }}").render!('product' => ProductDrop.new)
243
+ assert_equal 'EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new)
244
+ end
245
+ end # DropsTest