locomotivecms_solid 0.2.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 (50) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +152 -0
  8. data/Rakefile +7 -0
  9. data/lib/locomotivecms_solid.rb +2 -0
  10. data/lib/solid/arguments.rb +28 -0
  11. data/lib/solid/block.rb +13 -0
  12. data/lib/solid/conditional_block.rb +35 -0
  13. data/lib/solid/context_error.rb +2 -0
  14. data/lib/solid/default_security_rules.rb +24 -0
  15. data/lib/solid/element.rb +51 -0
  16. data/lib/solid/engine.rb +4 -0
  17. data/lib/solid/extensions.rb +17 -0
  18. data/lib/solid/iterable.rb +18 -0
  19. data/lib/solid/liquid_extensions/assign_tag.rb +21 -0
  20. data/lib/solid/liquid_extensions/for_tag.rb +102 -0
  21. data/lib/solid/liquid_extensions/if_tag.rb +44 -0
  22. data/lib/solid/liquid_extensions/unless_tag.rb +13 -0
  23. data/lib/solid/liquid_extensions/variable.rb +34 -0
  24. data/lib/solid/liquid_extensions.rb +87 -0
  25. data/lib/solid/method_whitelist.rb +56 -0
  26. data/lib/solid/model_drop.rb +119 -0
  27. data/lib/solid/parser.rb +265 -0
  28. data/lib/solid/tag.rb +11 -0
  29. data/lib/solid/template.rb +24 -0
  30. data/lib/solid/version.rb +3 -0
  31. data/lib/solid.rb +48 -0
  32. data/locomotivecms_solid.gemspec +25 -0
  33. data/spec/solid/arguments_spec.rb +310 -0
  34. data/spec/solid/block_spec.rb +39 -0
  35. data/spec/solid/conditional_block_spec.rb +39 -0
  36. data/spec/solid/default_security_rules_spec.rb +180 -0
  37. data/spec/solid/element_examples.rb +67 -0
  38. data/spec/solid/liquid_extensions/assign_tag_spec.rb +27 -0
  39. data/spec/solid/liquid_extensions/for_tag_spec.rb +48 -0
  40. data/spec/solid/liquid_extensions/if_tag_spec.rb +64 -0
  41. data/spec/solid/liquid_extensions/unless_tag_spec.rb +54 -0
  42. data/spec/solid/liquid_extensions/variable_spec.rb +25 -0
  43. data/spec/solid/model_drop_spec.rb +26 -0
  44. data/spec/solid/tag_spec.rb +26 -0
  45. data/spec/solid/template_spec.rb +37 -0
  46. data/spec/spec_helper.rb +8 -0
  47. data/spec/support/class_highjacker_examples.rb +33 -0
  48. data/spec/support/method_whitelist_matchers.rb +17 -0
  49. data/spec/support/tag_highjacker_examples.rb +33 -0
  50. metadata +201 -0
@@ -0,0 +1,310 @@
1
+ require 'spec_helper'
2
+
3
+ describe Solid::Arguments do
4
+
5
+ class DummyDrop < Liquid::Drop
6
+
7
+ def before_method(name)
8
+ "dummy #{name}"
9
+ end
10
+
11
+ end
12
+
13
+ def parse(string, context={})
14
+ Solid::Arguments.parse(string).interpolate(Liquid::Context.new(context))
15
+ end
16
+
17
+ context 'with no arguments' do
18
+
19
+ it "parses as an empty array" do
20
+ parse('').should be == []
21
+ end
22
+
23
+ end
24
+
25
+ context 'with a single argument' do
26
+
27
+ context 'of type string' do
28
+
29
+ it 'can parse an empty string' do
30
+ parse("''").should be == ['']
31
+ end
32
+
33
+ it 'can parse a constant' do
34
+ parse("FooBar", {'FooBar' => 42}).should be == [42]
35
+ end
36
+
37
+ it 'can parse a simple string (between simple quotes)' do
38
+ parse("'foobar'").should be == ['foobar']
39
+ end
40
+
41
+ it 'can parse a simple string (between double quotes)' do
42
+ parse('"foobar"').should be == ['foobar']
43
+ end
44
+
45
+ it 'should not consider this string as a context var' do
46
+ parse('"foobar"', {'foobar' => 'plop'}).should_not == ['plop']
47
+ end
48
+
49
+ it 'should not be disturbed by a string containing a comma' do
50
+ parse(%{"foo,bar", 'egg,spam'}).should be == ['foo,bar', 'egg,spam']
51
+ end
52
+
53
+ it 'should not be disturbed by a string containing a simple quote' do
54
+ parse('"foo\'bar"').should be == ["foo'bar"]
55
+ end
56
+
57
+ it 'should not be disturbed by a string containing a double quote' do
58
+ parse("'foo\"bar'").should be == ['foo"bar']
59
+ end
60
+
61
+ pending('not yet implemented') do
62
+ it 'should work for a string containing interpolation' do
63
+ parse('"1#{foo}3"', {'foo' => 2}).should be == ['123']
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ context 'of type integer' do
70
+
71
+ it 'should work' do
72
+ parse('42').should be == [42]
73
+ end
74
+
75
+ end
76
+
77
+ context 'of type float' do
78
+
79
+ it 'should work' do
80
+ parse('4.2').should be == [4.2]
81
+ end
82
+
83
+ end
84
+
85
+ context 'of type boolean' do
86
+
87
+ it 'should work with `true`' do
88
+ parse('true').should be == [true]
89
+ end
90
+
91
+ it 'should work with `false`' do
92
+ parse('false').should be == [false]
93
+ end
94
+
95
+ end
96
+
97
+ context 'of type Regexp' do
98
+
99
+ it 'should work for simple cases' do
100
+ parse('/bb|[^b]{2}/').should be == [/bb|[^b]{2}/]
101
+ end
102
+
103
+ it 'should work for a regexp containing interpolation' do
104
+ pending('not yet implemented')
105
+ parse('/#{mystring}|[^b]{2}/', {'mystring' => 'bb'}).should be == [/bb|[^b]{2}/]
106
+ end
107
+
108
+ end
109
+
110
+ context 'of type Range' do
111
+
112
+ it 'should work for integer ranges' do
113
+ parse('1..10').should be == [1..10]
114
+ end
115
+
116
+ it 'should work for integer exclusive ranges' do
117
+ parse('1...10').should be == [1...10]
118
+ end
119
+
120
+ it 'should work for float ranges' do
121
+ parse('1.0..10.0').should be == [1.0..10.0]
122
+ end
123
+
124
+ it 'should work with context variables' do
125
+ parse('a..b', {'a' => 1, 'b' => 10}).should be == [1..10]
126
+ end
127
+
128
+ end
129
+
130
+ context 'binary operators' do
131
+
132
+ it 'should permit additions' do
133
+ parse('1 + 2').should be == [3]
134
+ end
135
+
136
+ it 'should permit multiplications' do
137
+ parse('2 * 3').should be == [6]
138
+ end
139
+
140
+ it 'should permit to use builtins boolean operators' do
141
+ parse('true && false').should be == [false]
142
+ parse('false || true').should be == [true]
143
+ end
144
+
145
+ end
146
+
147
+ context 'unary operators' do
148
+
149
+ it 'should allow to use "!"' do
150
+ parse('!true').should be == [false]
151
+ parse('!false').should be == [true]
152
+ end
153
+
154
+ end
155
+
156
+ context 'of type "context var"' do
157
+
158
+ it 'should work' do
159
+ parse('myvar', {'myvar' => 'myvalue'}).should be == ['myvalue']
160
+ end
161
+
162
+ it 'can call methods without arguments' do
163
+ parse('myvar.length', {'myvar' => ' myvalue '}).should be == [9]
164
+ end
165
+
166
+ it 'can call methods without arguments on immediate values' do
167
+ parse('"foobar".length').should be == [6]
168
+ end
169
+
170
+ it 'can call methods without arguments but parentheses on immediate values' do
171
+ parse('"foobar".length()').should be == [6]
172
+ end
173
+
174
+ it 'can call a method with arguments' do
175
+ parse('myvar.split(",", 2)', {'myvar' => 'foo,bar'}).should be == [%w(foo bar)]
176
+ end
177
+
178
+ it 'can call a method with context var arguments' do
179
+ parse('myvar.split(myseparator, 2)', {'myvar' => 'foo,bar', 'myseparator' => ','}).should be == [%w(foo bar)]
180
+ end
181
+
182
+ it 'can evaluate context var deeply unclosed in collections' do
183
+ parse('[{1 => [{2 => myvar}]}]', {'myvar' => 'myvalue'}).first.should be == [{1 => [{2 => 'myvalue'}]}]
184
+ end
185
+
186
+ it 'can call methods chain without arguments' do
187
+ parse('myvar.strip.length', {'myvar' => ' myvalue '}).should be == [7]
188
+ end
189
+
190
+ it 'can call predicate methods' do
191
+ parse('myvar.empty?', {'myvar' => ' myvalue '}).should be == [false]
192
+ end
193
+
194
+ it 'can get a hash value' do
195
+ parse('myvar.mykey', {'myvar' => {'mykey' => 'myvalue'}}).should be == ['myvalue']
196
+ end
197
+
198
+ it 'can fallback on Liquid::Drop#before_method' do
199
+ parse('myvar.mymethod', {'myvar' => DummyDrop.new}).should be == ['dummy mymethod']
200
+ end
201
+
202
+ it 'should manage errors'
203
+
204
+ end
205
+
206
+ context 'of type hash' do
207
+
208
+ it 'should be able to parse unclosed hashes' do
209
+ parse('permissions: ""').should be == [{permissions: ''}]
210
+ end
211
+
212
+ end
213
+
214
+ context 'of type "named parameter"' do
215
+
216
+ it 'should be able to parse a string' do
217
+ parse('foo:"bar"').should be == [{:foo => 'bar'}]
218
+ end
219
+
220
+ it 'should be able to parse an int' do
221
+ parse('foo:42').should be == [{:foo => 42}]
222
+ end
223
+
224
+ it 'should be able to parse a context var' do
225
+ parse('foo:bar', {'bar' => 'baz'}).should be == [{:foo => 'baz'}]
226
+ end
227
+
228
+ it "should not be disturbed by a comma into a named string" do
229
+ parse('foo:"bar,baz"').should be == [{:foo => 'bar,baz'}]
230
+ end
231
+
232
+ it "should support a mix of types" do
233
+ parse('foo:"bar",bar:42, baz:true, egg:spam', {'spam' => 'egg'}).should be == [{
234
+ foo: 'bar',
235
+ bar: 42,
236
+ baz: true,
237
+ egg: 'egg',
238
+ }]
239
+ end
240
+
241
+ end
242
+
243
+ end
244
+
245
+ context 'security !!!' do
246
+
247
+ it 'should not allow to call unsecure methods' do
248
+ parse('42.send("`", "echo foo")').should be == [nil]
249
+ end
250
+
251
+ it 'should not allow to call unsecure methods' do
252
+ parse('42.__send__("`", "echo foo")').should be == [nil]
253
+ end
254
+
255
+ it "should raise a Solid::SyntaxError on unknown constructs" do
256
+ expect {
257
+ parse('{}[]')
258
+ }.to raise_error(Solid::SyntaxError)
259
+ end
260
+
261
+ it "should use #to_liquid" do
262
+ drop = Object.new
263
+ def drop.to_liquid
264
+ 'liquid'
265
+ end
266
+ parse('drop', 'drop' => drop).should be == ['liquid']
267
+ end
268
+
269
+ it "should use #context= if available" do
270
+ drop = Object.new
271
+ class << drop
272
+ def to_liquid
273
+ self
274
+ end
275
+ def to_s
276
+ @alias
277
+ end
278
+ def context=(context)
279
+ @alias = context['alias']
280
+ end
281
+ end
282
+ parse('drop.to_s', 'drop' => drop, 'alias' => 'liquid').should be == ['liquid']
283
+ end
284
+
285
+ end
286
+
287
+ context 'with useless round brackets' do
288
+
289
+ it 'should still work' do
290
+ parse('(42)').should be == [42]
291
+ parse('(((((((42)))))))').should be == [42]
292
+ end
293
+
294
+ end
295
+
296
+ context 'with multiple arguments' do
297
+
298
+ it 'should return 3 arguments and an option hash' do
299
+ args = parse('1, "2", myvar, myopt:false', {'myvar' => 4.2})
300
+ args.should be == [1, '2', 4.2, {:myopt => false}]
301
+ end
302
+
303
+ it 'should be tolerant about whitespace around commas and colons' do
304
+ args = parse(" 1\t, '2' ,myvar, myopt: false", {'myvar' => 4.2})
305
+ args.should be == [1, '2', 4.2, {:myopt => false}]
306
+ end
307
+
308
+ end
309
+
310
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ class DummyBlock < Solid::Block
4
+
5
+ def display(condition)
6
+ if condition
7
+ yield
8
+ else
9
+ 'not_yielded'
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ describe Solid::Block do
16
+
17
+ it_behaves_like "a Solid element"
18
+
19
+ describe '#display' do
20
+
21
+ let(:tokens) { ["dummy", "{% enddummy %}", "outside"] }
22
+
23
+ subject{ DummyBlock.new('dummy', 'condition', tokens) }
24
+
25
+ it 'yielding should render the block content' do
26
+ subject.render(Liquid::Context.new('condition' => true)).should be == 'dummy'
27
+ end
28
+
29
+ it 'should only render until the {% endblock %} tag' do
30
+ subject.render(Liquid::Context.new('condition' => true)).should_not include('outside')
31
+ end
32
+
33
+ it 'should not render its content if it do not yield' do
34
+ subject.render(Liquid::Context.new('condition' => false)).should_not include('dummy')
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ class IfPresent < Solid::ConditionalBlock
4
+
5
+ def display(string)
6
+ yield(!string.strip.empty?)
7
+ end
8
+
9
+ end
10
+
11
+ describe Solid::ConditionalBlock do
12
+
13
+ it_behaves_like "a Solid element"
14
+
15
+ describe '#display' do
16
+
17
+ let(:tokens) { ["present", "{% else %}", "blank", "{% endifpresent %}"] }
18
+
19
+ subject{ IfPresent.new('ifpresent', 'mystring', tokens) }
20
+
21
+ it 'yielding true should render the main block' do
22
+ context = Liquid::Context.new('mystring' => 'blah')
23
+ subject.render(context).should be == 'present'
24
+ end
25
+
26
+ it 'yielding false should render the `else` block' do
27
+ context = Liquid::Context.new('mystring' => '')
28
+ subject.render(context).should be == 'blank'
29
+ end
30
+
31
+ it 'yielding false without a `else` block does not render anything' do
32
+ context = Liquid::Context.new('mystring' => '')
33
+ subject = IfPresent.new('ifpresent', 'mystring', ['present', '{% endifpresent %}'])
34
+ subject.render(context).should be_nil
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+ require 'active_support/core_ext'
3
+
4
+ describe Solid, 'default security rules' do
5
+
6
+ shared_examples_for 'a ruby object' do
7
+ it_should_safely_respond_to :nil?, :==, :!=, :!, :!~, :blank?, :present?, :in?, :to_json
8
+ it_should_not_safely_respond_to :const_get, :const_set,
9
+ :instance_variable_get, :instance_variable_set, :instance_variable_defined?,
10
+ :send, :__send__, :public_send,
11
+ :__id__, :object_id,
12
+ :class, :singleton_class, :trust, :taint, :untaint, :untrust,
13
+ :clone, :dup, :initialize_dup, :initialize_clone, :freeze,
14
+ :methods, :singleton_methods, :protected_methods, :private_methods,
15
+ :method, :public_method, :define_singleton_method, :extend,
16
+ :eval, :instance_eval, :instance_exec, :exec, :`, :system, :test,
17
+ :global_variables, :local_variables,
18
+ :gets, :readline, :readlines, :sleep,
19
+ :at_exit!, :exit, :fork, :spawn, :trap, :exit!, :syscall
20
+ end
21
+
22
+ shared_examples_for 'a ruby module' do
23
+ it_should_behave_like 'a ruby object'
24
+ it_should_not_safely_respond_to :ancestors
25
+ end
26
+
27
+ shared_examples_for 'a ruby class' do
28
+ it_should_behave_like 'a ruby module'
29
+ it_should_not_safely_respond_to :new, :allocate, :superclass
30
+ end
31
+
32
+ shared_examples_for 'a boolean' do
33
+ it_should_behave_like 'a ruby object'
34
+ it_should_safely_respond_to :false?, :true?
35
+ end
36
+
37
+ shared_examples_for 'an enumerable' do
38
+ it_should_safely_respond_to :sort, :length, :size
39
+ end
40
+
41
+ shared_examples_for 'a comparable' do
42
+ it_should_safely_respond_to :<, :<=, :==, :>, :>=, :between?
43
+ end
44
+
45
+ shared_examples_for 'a numeric' do
46
+ it_should_behave_like 'a ruby object', 'a comparable'
47
+ it_should_safely_respond_to :%, :*, :**, :+, :-, :-@, :/, :<=>, :===, :to_s, :abs,
48
+ :second, :seconds, :minute, :minutes, :hour, :hours, :day, :days, :week, :weeks,
49
+ :bytes, :kilobytes, :megabytes, :gigabytes, :terabytes, :petabytes, :exabytes
50
+ end
51
+
52
+ shared_examples_for 'an integer' do
53
+ it_should_behave_like 'a numeric'
54
+ it_should_safely_respond_to :div, :divmod, :even?, :odd?, :to_f,
55
+ :month, :months, :year, :years
56
+ end
57
+
58
+ describe 'nil' do
59
+ subject { nil }
60
+
61
+ it_should_behave_like 'a ruby object'
62
+ end
63
+
64
+ describe true do
65
+ subject { true }
66
+
67
+ it_should_behave_like 'a ruby object'
68
+ end
69
+
70
+ describe false do
71
+ subject { false }
72
+
73
+ it_should_behave_like 'a ruby object'
74
+ end
75
+
76
+ describe 'Basic object instance' do
77
+ let(:basic_class) { Class.new(Object) }
78
+ subject { basic_class.new }
79
+
80
+ it_should_behave_like 'a ruby object'
81
+ end
82
+
83
+ describe 'Array instances' do
84
+ subject { [] }
85
+
86
+ it_should_behave_like 'a ruby object', 'an enumerable'
87
+ it_should_safely_respond_to :[], :[]=, :first, :last, :join, :reverse, :uniq, :include?, :empty?,
88
+ :to_sentence, :in_groups_of, :in_groups
89
+ end
90
+
91
+ describe 'Array class' do
92
+ subject { Array }
93
+
94
+ it_should_behave_like 'a ruby class'
95
+ it_should_safely_respond_to :wrap
96
+ end
97
+
98
+ describe 'Hash instances' do
99
+ subject { {} }
100
+
101
+ it_should_behave_like 'a ruby object', 'an enumerable'
102
+ it_should_safely_respond_to :[], :[]=, :has_key?, :has_value?, :empty?, :except, :slice
103
+ end
104
+
105
+ describe 'Range instances' do
106
+ subject { 1..10 }
107
+
108
+ it_should_behave_like 'a ruby object', 'an enumerable'
109
+ it_should_safely_respond_to :first, :last, :begin, :end, :max, :min, :cover?, :include?, :member?
110
+ end
111
+
112
+ describe 'Regexp instances' do
113
+ subject { /bb|[^b]{2}/ }
114
+
115
+ it_should_behave_like 'a ruby object'
116
+ it_should_safely_respond_to :==, :===, :=~, :match
117
+ end
118
+
119
+ describe 'Bignum instances' do
120
+ subject { 2 ** 123 }
121
+
122
+ it { should be_a Bignum }
123
+ it_should_behave_like 'an integer'
124
+ end
125
+
126
+ describe 'Fixnum instances' do
127
+ subject { 4 }
128
+
129
+ it_should_behave_like 'an integer'
130
+ it_should_safely_respond_to :multiple_of?
131
+ end
132
+
133
+ describe 'Float instances' do
134
+ subject { 4.2 }
135
+
136
+ it_should_behave_like 'a numeric'
137
+ end
138
+
139
+ describe 'Time class' do
140
+ subject { Time }
141
+
142
+ it_should_behave_like 'a ruby class'
143
+ it_should_safely_respond_to :at, :now
144
+ end
145
+
146
+ describe 'Time instances' do
147
+ subject { Time.now }
148
+
149
+ it_should_safely_respond_to :to_i, :to_f, :<=>,
150
+ :localtime, :gmtime, :utc, :getlocal, :getgm, :getutc,
151
+ :ctime, :asctime, :to_s, :inspect, :to_a, :+, :-, :round,
152
+ :sec, :min, :hour, :mday, :day, :mon, :month, :year, :wday, :yday,
153
+ :isdst, :dst?, :zone, :gmtoff, :gmt_offset, :utc_offset, :utc?, :gmt?,
154
+ :sunday?, :monday?, :tuesday?, :wednesday?, :thursday?, :friday?, :saturday?,
155
+ :tv_sec, :tv_usec, :usec, :tv_nsec, :nsec, :subsec, :strftime,
156
+ :to_time, :to_date, :to_datetime
157
+ end
158
+
159
+ describe 'String instances' do
160
+ subject { 'string' }
161
+
162
+ it_should_behave_like 'a ruby object', 'a comparable', 'an enumerable'
163
+ it_should_safely_respond_to :gsub, :strip, :chop, :chomp, :start_with?, :end_with?,
164
+ :[], :length, :size, :empty?, :=~, :split, :upcase, :downcase, :capitalize, :squeeze, :tr,
165
+ :exclude?, :truncate
166
+ end
167
+
168
+ describe 'Module instances' do
169
+ subject { Module.new }
170
+
171
+ it_should_behave_like 'a ruby module'
172
+ end
173
+
174
+ describe 'Class instances' do
175
+ subject { Class.new }
176
+
177
+ it_should_behave_like 'a ruby class'
178
+ end
179
+
180
+ end
@@ -0,0 +1,67 @@
1
+ require 'solid'
2
+
3
+ shared_examples "a Solid element" do
4
+
5
+ describe '.tag_name' do
6
+
7
+ it 'should register tag to Liquid with given name' do
8
+ Liquid::Template.should_receive(:register_tag).with('dummy', described_class)
9
+ described_class.tag_name 'dummy'
10
+ end
11
+
12
+ it 'should return previously given name' do
13
+ Liquid::Template.stub(:register_tag)
14
+ described_class.tag_name 'dummy'
15
+ described_class.tag_name.should be == 'dummy'
16
+ end
17
+
18
+ end
19
+
20
+ describe '.context_attribute' do
21
+
22
+ let(:element) do
23
+ described_class.context_attribute :current_user
24
+ Solid::Arguments.stub(:parse).with('ARGUMENTS_STRING')
25
+ element = described_class.new('name', 'ARGUMENTS_STRING', ['{% endname %}'])
26
+ end
27
+
28
+ it 'should define a custom accessor to the rendered context' do
29
+ element.stub(:current_context => {'current_user' => 'me'})
30
+ element.current_user.should be == 'me'
31
+ end
32
+
33
+ it 'should raise a Solid::ContextError if called outside render' do
34
+ expect{
35
+ element.current_user
36
+ }.to raise_error(Solid::ContextError)
37
+ end
38
+
39
+ end
40
+
41
+ describe '#arguments' do
42
+
43
+ it 'should instanciate a Solid::Arguments with his arguments_string' do
44
+ Solid::Arguments.should_receive(:parse).with('ARGUMENTS_STRING')
45
+ described_class.new('name', 'ARGUMENTS_STRING', ['{% endname %}'])
46
+ end
47
+
48
+ it 'should store his Solid:Arguments instance' do
49
+ element = described_class.new('name', '1', ['{% endname %}'])
50
+ element.arguments.should be_a(Solid::Arguments)
51
+ end
52
+
53
+ end
54
+
55
+ describe '#display' do
56
+
57
+ it 'should force developper to define it in child class' do
58
+ Solid::Arguments.stub(:parse).with('ARGUMENTS_STRING')
59
+ element = described_class.new('name', 'ARGUMENTS_STRING', ['{% endname %}'])
60
+ expect{
61
+ element.display
62
+ }.to raise_error(NotImplementedError)
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Solid::LiquidExtensions::AssignTag do
4
+ it_should_behave_like 'a tag highjacker'
5
+
6
+ context 'when Liquid::Assign is replaced' do
7
+
8
+ before :each do
9
+ described_class.load!
10
+ end
11
+
12
+ after :each do
13
+ described_class.unload!
14
+ end
15
+
16
+ it 'should allow complex expression inside an assign tag' do
17
+ template = Solid::Template.parse(%(
18
+ {% assign included = foo.include?('bar') %}
19
+ {{ included }}
20
+ ))
21
+ output = template.render('foo' => ' bar ').strip
22
+ output.should be == 'true'
23
+ end
24
+
25
+ end
26
+
27
+ end