liquid 2.6.1 → 4.0.3

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 (130) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +194 -29
  3. data/{MIT-LICENSE → LICENSE} +0 -0
  4. data/README.md +60 -2
  5. data/lib/liquid.rb +25 -14
  6. data/lib/liquid/block.rb +47 -96
  7. data/lib/liquid/block_body.rb +143 -0
  8. data/lib/liquid/condition.rb +70 -39
  9. data/lib/liquid/context.rb +116 -157
  10. data/lib/liquid/document.rb +19 -9
  11. data/lib/liquid/drop.rb +31 -14
  12. data/lib/liquid/errors.rb +54 -10
  13. data/lib/liquid/expression.rb +49 -0
  14. data/lib/liquid/extensions.rb +19 -7
  15. data/lib/liquid/file_system.rb +25 -14
  16. data/lib/liquid/forloop_drop.rb +42 -0
  17. data/lib/liquid/i18n.rb +39 -0
  18. data/lib/liquid/interrupts.rb +2 -3
  19. data/lib/liquid/lexer.rb +55 -0
  20. data/lib/liquid/locales/en.yml +26 -0
  21. data/lib/liquid/parse_context.rb +38 -0
  22. data/lib/liquid/parse_tree_visitor.rb +42 -0
  23. data/lib/liquid/parser.rb +90 -0
  24. data/lib/liquid/parser_switching.rb +31 -0
  25. data/lib/liquid/profiler.rb +158 -0
  26. data/lib/liquid/profiler/hooks.rb +23 -0
  27. data/lib/liquid/range_lookup.rb +37 -0
  28. data/lib/liquid/resource_limits.rb +23 -0
  29. data/lib/liquid/standardfilters.rb +311 -77
  30. data/lib/liquid/strainer.rb +39 -26
  31. data/lib/liquid/tablerowloop_drop.rb +62 -0
  32. data/lib/liquid/tag.rb +28 -11
  33. data/lib/liquid/tags/assign.rb +34 -10
  34. data/lib/liquid/tags/break.rb +1 -4
  35. data/lib/liquid/tags/capture.rb +11 -9
  36. data/lib/liquid/tags/case.rb +37 -22
  37. data/lib/liquid/tags/comment.rb +10 -3
  38. data/lib/liquid/tags/continue.rb +1 -4
  39. data/lib/liquid/tags/cycle.rb +20 -14
  40. data/lib/liquid/tags/decrement.rb +4 -8
  41. data/lib/liquid/tags/for.rb +121 -60
  42. data/lib/liquid/tags/if.rb +73 -30
  43. data/lib/liquid/tags/ifchanged.rb +3 -5
  44. data/lib/liquid/tags/include.rb +77 -46
  45. data/lib/liquid/tags/increment.rb +4 -8
  46. data/lib/liquid/tags/raw.rb +35 -10
  47. data/lib/liquid/tags/table_row.rb +62 -0
  48. data/lib/liquid/tags/unless.rb +6 -9
  49. data/lib/liquid/template.rb +130 -32
  50. data/lib/liquid/tokenizer.rb +31 -0
  51. data/lib/liquid/truffle.rb +5 -0
  52. data/lib/liquid/utils.rb +57 -4
  53. data/lib/liquid/variable.rb +121 -30
  54. data/lib/liquid/variable_lookup.rb +88 -0
  55. data/lib/liquid/version.rb +2 -1
  56. data/test/fixtures/en_locale.yml +9 -0
  57. data/test/integration/assign_test.rb +48 -0
  58. data/test/integration/blank_test.rb +106 -0
  59. data/test/integration/block_test.rb +12 -0
  60. data/test/{liquid → integration}/capture_test.rb +13 -3
  61. data/test/integration/context_test.rb +32 -0
  62. data/test/integration/document_test.rb +19 -0
  63. data/test/integration/drop_test.rb +273 -0
  64. data/test/integration/error_handling_test.rb +260 -0
  65. data/test/integration/filter_test.rb +178 -0
  66. data/test/integration/hash_ordering_test.rb +23 -0
  67. data/test/integration/output_test.rb +123 -0
  68. data/test/integration/parse_tree_visitor_test.rb +247 -0
  69. data/test/integration/parsing_quirks_test.rb +122 -0
  70. data/test/integration/render_profiling_test.rb +154 -0
  71. data/test/integration/security_test.rb +80 -0
  72. data/test/integration/standard_filter_test.rb +776 -0
  73. data/test/{liquid → integration}/tags/break_tag_test.rb +2 -3
  74. data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -2
  75. data/test/integration/tags/for_tag_test.rb +410 -0
  76. data/test/integration/tags/if_else_tag_test.rb +188 -0
  77. data/test/integration/tags/include_tag_test.rb +253 -0
  78. data/test/integration/tags/increment_tag_test.rb +23 -0
  79. data/test/{liquid → integration}/tags/raw_tag_test.rb +9 -2
  80. data/test/integration/tags/standard_tag_test.rb +296 -0
  81. data/test/integration/tags/statements_test.rb +111 -0
  82. data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +25 -24
  83. data/test/integration/tags/unless_else_tag_test.rb +26 -0
  84. data/test/integration/template_test.rb +332 -0
  85. data/test/integration/trim_mode_test.rb +529 -0
  86. data/test/integration/variable_test.rb +96 -0
  87. data/test/test_helper.rb +106 -19
  88. data/test/truffle/truffle_test.rb +9 -0
  89. data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +9 -9
  90. data/test/unit/condition_unit_test.rb +166 -0
  91. data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +85 -74
  92. data/test/unit/file_system_unit_test.rb +35 -0
  93. data/test/unit/i18n_unit_test.rb +37 -0
  94. data/test/unit/lexer_unit_test.rb +51 -0
  95. data/test/unit/parser_unit_test.rb +82 -0
  96. data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +4 -4
  97. data/test/unit/strainer_unit_test.rb +164 -0
  98. data/test/unit/tag_unit_test.rb +21 -0
  99. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  100. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  101. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  102. data/test/unit/template_unit_test.rb +78 -0
  103. data/test/unit/tokenizer_unit_test.rb +55 -0
  104. data/test/unit/variable_unit_test.rb +162 -0
  105. metadata +157 -77
  106. data/lib/extras/liquid_view.rb +0 -51
  107. data/lib/liquid/htmltags.rb +0 -74
  108. data/lib/liquid/module_ex.rb +0 -62
  109. data/test/liquid/assign_test.rb +0 -21
  110. data/test/liquid/condition_test.rb +0 -127
  111. data/test/liquid/drop_test.rb +0 -180
  112. data/test/liquid/error_handling_test.rb +0 -81
  113. data/test/liquid/file_system_test.rb +0 -29
  114. data/test/liquid/filter_test.rb +0 -125
  115. data/test/liquid/hash_ordering_test.rb +0 -25
  116. data/test/liquid/module_ex_test.rb +0 -87
  117. data/test/liquid/output_test.rb +0 -116
  118. data/test/liquid/parsing_quirks_test.rb +0 -52
  119. data/test/liquid/security_test.rb +0 -64
  120. data/test/liquid/standard_filter_test.rb +0 -251
  121. data/test/liquid/strainer_test.rb +0 -52
  122. data/test/liquid/tags/for_tag_test.rb +0 -297
  123. data/test/liquid/tags/if_else_tag_test.rb +0 -166
  124. data/test/liquid/tags/include_tag_test.rb +0 -166
  125. data/test/liquid/tags/increment_tag_test.rb +0 -24
  126. data/test/liquid/tags/standard_tag_test.rb +0 -295
  127. data/test/liquid/tags/statements_test.rb +0 -134
  128. data/test/liquid/tags/unless_else_tag_test.rb +0 -26
  129. data/test/liquid/template_test.rb +0 -146
  130. data/test/liquid/variable_test.rb +0 -186
@@ -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)
13
+ template_path
14
+ end
15
+ end
16
+
17
+ class BlankTest < Minitest::Test
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('{% 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
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ class BlockTest < Minitest::Test
4
+ include Liquid
5
+
6
+ def test_unexpected_end_tag
7
+ exc = assert_raises(SyntaxError) do
8
+ Template.parse("{% if true %}{% endunless %}")
9
+ end
10
+ assert_equal exc.message, "Liquid syntax error: 'endunless' is not a valid delimiter for if tags. use endif"
11
+ end
12
+ end
@@ -1,12 +1,22 @@
1
1
  require 'test_helper'
2
2
 
3
- class CaptureTest < Test::Unit::TestCase
3
+ class CaptureTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_captures_block_content_in_variable
7
7
  assert_template_result("test string", "{% capture 'var' %}test string{% endcapture %}{{var}}", {})
8
8
  end
9
9
 
10
+ def test_capture_with_hyphen_in_variable_name
11
+ template_source = <<-END_TEMPLATE
12
+ {% capture this-thing %}Print this-thing{% endcapture %}
13
+ {{ this-thing }}
14
+ END_TEMPLATE
15
+ template = Template.parse(template_source)
16
+ rendered = template.render!
17
+ assert_equal "Print this-thing", rendered.strip
18
+ end
19
+
10
20
  def test_capture_to_variable_from_outer_scope_if_existing
11
21
  template_source = <<-END_TEMPLATE
12
22
  {% assign var = '' %}
@@ -19,7 +29,7 @@ class CaptureTest < Test::Unit::TestCase
19
29
  {{var}}
20
30
  END_TEMPLATE
21
31
  template = Template.parse(template_source)
22
- rendered = template.render
32
+ rendered = template.render!
23
33
  assert_equal "test-string", rendered.gsub(/\s/, '')
24
34
  end
25
35
 
@@ -34,7 +44,7 @@ class CaptureTest < Test::Unit::TestCase
34
44
  {{ first }}-{{ second }}
35
45
  END_TEMPLATE
36
46
  template = Template.parse(template_source)
37
- rendered = template.render
47
+ rendered = template.render!
38
48
  assert_equal "3-3", rendered.gsub(/\s/, '')
39
49
  end
40
50
  end # CaptureTest
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class ContextTest < Minitest::Test
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
+ with_global_filter(global) do
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
+ end
24
+
25
+ def test_has_key_will_not_add_an_error_for_missing_keys
26
+ with_error_mode :strict do
27
+ context = Context.new
28
+ context.key?('unknown')
29
+ assert_empty context.errors
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ class DocumentTest < Minitest::Test
4
+ include Liquid
5
+
6
+ def test_unexpected_outer_tag
7
+ exc = assert_raises(SyntaxError) do
8
+ Template.parse("{% else %}")
9
+ end
10
+ assert_equal exc.message, "Liquid syntax error: Unexpected outer 'else' tag"
11
+ end
12
+
13
+ def test_unknown_tag
14
+ exc = assert_raises(SyntaxError) do
15
+ Template.parse("{% foo %}")
16
+ end
17
+ assert_equal exc.message, "Liquid syntax error: Unknown tag 'foo'"
18
+ end
19
+ end
@@ -0,0 +1,273 @@
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 liquid_method_missing(method)
17
+ @context[method]
18
+ end
19
+ end
20
+
21
+ class ProductDrop < Liquid::Drop
22
+ class TextDrop < Liquid::Drop
23
+ def array
24
+ ['text1', 'text2']
25
+ end
26
+
27
+ def text
28
+ 'text1'
29
+ end
30
+ end
31
+
32
+ class CatchallDrop < Liquid::Drop
33
+ def liquid_method_missing(method)
34
+ 'catchall_method: ' << method.to_s
35
+ end
36
+ end
37
+
38
+ def texts
39
+ TextDrop.new
40
+ end
41
+
42
+ def catchall
43
+ CatchallDrop.new
44
+ end
45
+
46
+ def context
47
+ ContextDrop.new
48
+ end
49
+
50
+ def user_input
51
+ "foo".taint
52
+ end
53
+
54
+ protected
55
+
56
+ def callmenot
57
+ "protected"
58
+ end
59
+ end
60
+
61
+ class EnumerableDrop < Liquid::Drop
62
+ def liquid_method_missing(method)
63
+ method
64
+ end
65
+
66
+ def size
67
+ 3
68
+ end
69
+
70
+ def first
71
+ 1
72
+ end
73
+
74
+ def count
75
+ 3
76
+ end
77
+
78
+ def min
79
+ 1
80
+ end
81
+
82
+ def max
83
+ 3
84
+ end
85
+
86
+ def each
87
+ yield 1
88
+ yield 2
89
+ yield 3
90
+ end
91
+ end
92
+
93
+ class RealEnumerableDrop < Liquid::Drop
94
+ include Enumerable
95
+
96
+ def liquid_method_missing(method)
97
+ method
98
+ end
99
+
100
+ def each
101
+ yield 1
102
+ yield 2
103
+ yield 3
104
+ end
105
+ end
106
+
107
+ class DropsTest < Minitest::Test
108
+ include Liquid
109
+
110
+ def test_product_drop
111
+ tpl = Liquid::Template.parse(' ')
112
+ assert_equal ' ', tpl.render!('product' => ProductDrop.new)
113
+ end
114
+
115
+ def test_rendering_raises_on_tainted_attr
116
+ with_taint_mode(:error) do
117
+ tpl = Liquid::Template.parse('{{ product.user_input }}')
118
+ assert_raises TaintedError do
119
+ tpl.render!('product' => ProductDrop.new)
120
+ end
121
+ end
122
+ end
123
+
124
+ def test_rendering_warns_on_tainted_attr
125
+ with_taint_mode(:warn) do
126
+ tpl = Liquid::Template.parse('{{ product.user_input }}')
127
+ context = Context.new('product' => ProductDrop.new)
128
+ tpl.render!(context)
129
+ assert_equal [Liquid::TaintedError], context.warnings.map(&:class)
130
+ assert_equal "variable 'product.user_input' is tainted and was not escaped", context.warnings.first.to_s(false)
131
+ end
132
+ end
133
+
134
+ def test_rendering_doesnt_raise_on_escaped_tainted_attr
135
+ with_taint_mode(:error) do
136
+ tpl = Liquid::Template.parse('{{ product.user_input | escape }}')
137
+ tpl.render!('product' => ProductDrop.new)
138
+ end
139
+ end
140
+
141
+ def test_drop_does_only_respond_to_whitelisted_methods
142
+ assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new)
143
+ assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new)
144
+ assert_equal "", Liquid::Template.parse("{{ product.whatever }}").render!('product' => ProductDrop.new)
145
+ assert_equal "", Liquid::Template.parse('{{ product | map: "inspect" }}').render!('product' => ProductDrop.new)
146
+ assert_equal "", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render!('product' => ProductDrop.new)
147
+ assert_equal "", Liquid::Template.parse('{{ product | map: "whatever" }}').render!('product' => ProductDrop.new)
148
+ end
149
+
150
+ def test_drops_respond_to_to_liquid
151
+ assert_equal "text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render!('product' => ProductDrop.new)
152
+ assert_equal "text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render!('product' => ProductDrop.new)
153
+ end
154
+
155
+ def test_text_drop
156
+ output = Liquid::Template.parse(' {{ product.texts.text }} ').render!('product' => ProductDrop.new)
157
+ assert_equal ' text1 ', output
158
+ end
159
+
160
+ def test_catchall_unknown_method
161
+ output = Liquid::Template.parse(' {{ product.catchall.unknown }} ').render!('product' => ProductDrop.new)
162
+ assert_equal ' catchall_method: unknown ', output
163
+ end
164
+
165
+ def test_catchall_integer_argument_drop
166
+ output = Liquid::Template.parse(' {{ product.catchall[8] }} ').render!('product' => ProductDrop.new)
167
+ assert_equal ' catchall_method: 8 ', output
168
+ end
169
+
170
+ def test_text_array_drop
171
+ output = Liquid::Template.parse('{% for text in product.texts.array %} {{text}} {% endfor %}').render!('product' => ProductDrop.new)
172
+ assert_equal ' text1 text2 ', output
173
+ end
174
+
175
+ def test_context_drop
176
+ output = Liquid::Template.parse(' {{ context.bar }} ').render!('context' => ContextDrop.new, 'bar' => "carrot")
177
+ assert_equal ' carrot ', output
178
+ end
179
+
180
+ def test_nested_context_drop
181
+ output = Liquid::Template.parse(' {{ product.context.foo }} ').render!('product' => ProductDrop.new, 'foo' => "monkey")
182
+ assert_equal ' monkey ', output
183
+ end
184
+
185
+ def test_protected
186
+ output = Liquid::Template.parse(' {{ product.callmenot }} ').render!('product' => ProductDrop.new)
187
+ assert_equal ' ', output
188
+ end
189
+
190
+ def test_object_methods_not_allowed
191
+ [:dup, :clone, :singleton_class, :eval, :class_eval, :inspect].each do |method|
192
+ output = Liquid::Template.parse(" {{ product.#{method} }} ").render!('product' => ProductDrop.new)
193
+ assert_equal ' ', output
194
+ end
195
+ end
196
+
197
+ def test_scope
198
+ assert_equal '1', Liquid::Template.parse('{{ context.scopes }}').render!('context' => ContextDrop.new)
199
+ assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ context.scopes }}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1])
200
+ assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1])
201
+ end
202
+
203
+ def test_scope_though_proc
204
+ assert_equal '1', Liquid::Template.parse('{{ s }}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] })
205
+ assert_equal '2', Liquid::Template.parse('{%for i in dummy%}{{ s }}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] }, 'dummy' => [1])
206
+ assert_equal '3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc{ |c| c['context.scopes'] }, 'dummy' => [1])
207
+ end
208
+
209
+ def test_scope_with_assigns
210
+ assert_equal 'variable', Liquid::Template.parse('{% assign a = "variable"%}{{a}}').render!('context' => ContextDrop.new)
211
+ assert_equal 'variable', Liquid::Template.parse('{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1])
212
+ assert_equal 'test', Liquid::Template.parse('{% assign header_gif = "test"%}{{header_gif}}').render!('context' => ContextDrop.new)
213
+ assert_equal 'test', Liquid::Template.parse("{% assign header_gif = 'test'%}{{header_gif}}").render!('context' => ContextDrop.new)
214
+ end
215
+
216
+ def test_scope_from_tags
217
+ assert_equal '1', Liquid::Template.parse('{% for i in context.scopes_as_array %}{{i}}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1])
218
+ 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])
219
+ 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])
220
+ end
221
+
222
+ def test_access_context_from_drop
223
+ assert_equal '123', Liquid::Template.parse('{%for a in dummy%}{{ context.loop_pos }}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1, 2, 3])
224
+ end
225
+
226
+ def test_enumerable_drop
227
+ assert_equal '123', Liquid::Template.parse('{% for c in collection %}{{c}}{% endfor %}').render!('collection' => EnumerableDrop.new)
228
+ end
229
+
230
+ def test_enumerable_drop_size
231
+ assert_equal '3', Liquid::Template.parse('{{collection.size}}').render!('collection' => EnumerableDrop.new)
232
+ end
233
+
234
+ def test_enumerable_drop_will_invoke_liquid_method_missing_for_clashing_method_names
235
+ ["select", "each", "map", "cycle"].each do |method|
236
+ assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
237
+ assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
238
+ assert_equal method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
239
+ assert_equal method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
240
+ end
241
+ end
242
+
243
+ def test_some_enumerable_methods_still_get_invoked
244
+ [ :count, :max ].each do |method|
245
+ assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
246
+ assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
247
+ assert_equal "3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
248
+ assert_equal "3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
249
+ end
250
+
251
+ assert_equal "yes", Liquid::Template.parse("{% if collection contains 3 %}yes{% endif %}").render!('collection' => RealEnumerableDrop.new)
252
+
253
+ [ :min, :first ].each do |method|
254
+ assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new)
255
+ assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new)
256
+ assert_equal "1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new)
257
+ assert_equal "1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new)
258
+ end
259
+ end
260
+
261
+ def test_empty_string_value_access
262
+ assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => '')
263
+ end
264
+
265
+ def test_nil_value_access
266
+ assert_equal '', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => nil)
267
+ end
268
+
269
+ def test_default_to_s_on_drops
270
+ assert_equal 'ProductDrop', Liquid::Template.parse("{{ product }}").render!('product' => ProductDrop.new)
271
+ assert_equal 'EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new)
272
+ end
273
+ end # DropsTest