liquid 2.6.3 → 3.0.0.rc1

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 (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