blocks 1.2.5 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ module Blocks
2
+ module ControllerAdditions
3
+ module ClassMethods
4
+ def blocks
5
+ @controller_blocks ||= Blocks::Base.new(view_context)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module Blocks
2
+ module ViewAdditions
3
+ module ClassMethods
4
+ def blocks
5
+ return @blocks if @blocks
6
+ @blocks = Blocks::Base.new(self)
7
+ @blocks.blocks.merge! @controller_blocks.blocks if @controller_blocks
8
+ @blocks
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1 @@
1
+ require 'blocks'
@@ -0,0 +1,659 @@
1
+ require "spec_helper"
2
+
3
+ describe Blocks::Base do
4
+ before :each do
5
+ @view = ActionView::Base.new
6
+ @builder = Blocks::Base.new(@view)
7
+ end
8
+
9
+ it "should be able change the default global partials directory" do
10
+ Blocks.template_folder = "shared"
11
+ Blocks.use_partials = true
12
+ @builder = Blocks::Base.new(@view)
13
+ @builder.expects(:render_before_blocks).at_least_once
14
+ @builder.expects(:render_after_blocks).at_least_once
15
+ @view.expects(:capture).with(:value1 => 1, :value2 => 2).never
16
+ @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
17
+ @view.expects(:render).with("shared/some_block", :value1 => 1, :value2 => 2).once
18
+ @builder.render :some_block, :value1 => 1, :value2 => 2
19
+ end
20
+
21
+ describe "defined? method" do
22
+ it "should be able to determine if a block by a specific name is already defined" do
23
+ @builder.defined?(:test_block).should be_false
24
+ @builder.define :test_block do end
25
+ @builder.defined?(:test_block).should be_true
26
+ end
27
+
28
+ it "should not care whether the block name was defined with a string or a symbol" do
29
+ @builder.defined?(:test_block).should be_false
30
+ @builder.define "test_block" do end
31
+ @builder.defined?(:test_block).should be_true
32
+
33
+ @builder.defined?(:test_block2).should be_false
34
+ @builder.define :test_block2 do end
35
+ @builder.defined?(:test_block2).should be_true
36
+ end
37
+
38
+ it "should not care whether the defined? method is passed a string or a symbol" do
39
+ @builder.defined?("test_block").should be_false
40
+ @builder.define :test_block do end
41
+ @builder.defined?("test_block").should be_true
42
+ end
43
+ end
44
+
45
+ describe "define method" do
46
+ it "should be able to define a new block" do
47
+ block = Proc.new { |options| }
48
+
49
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block
50
+
51
+ test_block = @builder.blocks[:test_block]
52
+ test_block.options[:option1].should eql("value1")
53
+ test_block.options[:option2].should eql("value2")
54
+ test_block.name.should eql(:test_block)
55
+ test_block.block.should eql(block)
56
+ end
57
+
58
+ it "should not replace a defined block with another attempted definition" do
59
+ block1 = Proc.new do |options| end
60
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block1
61
+
62
+ block2 = Proc.new do |options| end
63
+ @builder.define :test_block, :option3 => "value3", :option4 => "value4", &block2
64
+
65
+ test_block = @builder.blocks[:test_block]
66
+ test_block.options[:option1].should eql("value1")
67
+ test_block.options[:option2].should eql("value2")
68
+ test_block.options[:option3].should be_nil
69
+ test_block.options[:option4].should be_nil
70
+ test_block.name.should eql(:test_block)
71
+ test_block.block.should eql(block1)
72
+ end
73
+ end
74
+
75
+ describe "replace method" do
76
+ it "should be able to replace a defined block" do
77
+ block1 = Proc.new do |options| end
78
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block1
79
+
80
+ block2 = Proc.new do |options| end
81
+ @builder.replace :test_block, :option3 => "value3", :option4 => "value4", &block2
82
+
83
+ test_block = @builder.blocks[:test_block]
84
+ test_block.options[:option1].should be_nil
85
+ test_block.options[:option2].should be_nil
86
+ test_block.options[:option3].should eql("value3")
87
+ test_block.options[:option4].should eql("value4")
88
+ test_block.name.should eql(:test_block)
89
+ test_block.block.should eql(block2)
90
+ end
91
+ end
92
+
93
+ describe "queue method" do
94
+ it "should store all queued blocks in the queued_blocks array" do
95
+ @builder.queued_blocks.should be_empty
96
+ @builder.queue :test_block
97
+ @builder.queued_blocks.length.should eql 1
98
+ @builder.queued_blocks.map(&:name).first.should eql(:test_block)
99
+ end
100
+
101
+ it "should convert a string block name to a symbol" do
102
+ @builder.queue "test_block"
103
+ @builder.queued_blocks.map(&:name).first.should eql(:test_block)
104
+ end
105
+
106
+ it "should queue blocks as Blocks::Container objects" do
107
+ @builder.queue :test_block, :a => 1, :b => 2, :c => 3
108
+ container = @builder.queued_blocks.first
109
+ container.should be_a(Blocks::Container)
110
+ container.name.should eql(:test_block)
111
+ container.options.should eql(:a => 1, :b => 2, :c => 3)
112
+ end
113
+
114
+ it "should not require a name for the block being queued" do
115
+ @builder.queue
116
+ @builder.queue
117
+ @builder.queued_blocks.length.should eql 2
118
+ @builder.queued_blocks.map(&:name).first.should eql(:block_1)
119
+ @builder.queued_blocks.map(&:name).second.should eql(:block_2)
120
+ end
121
+
122
+ it "should anonymously define the name of a block if not specified" do
123
+ @builder.queue
124
+ @builder.queue :my_block
125
+ @builder.queue
126
+ @builder.queued_blocks.map(&:name).first.should eql(:block_1)
127
+ @builder.queued_blocks.map(&:name).second.should eql(:my_block)
128
+ @builder.queued_blocks.map(&:name).third.should eql(:block_2)
129
+ end
130
+
131
+ it "should store queued blocks in the order in which they are queued" do
132
+ @builder.queue :block1
133
+ @builder.queue :block3
134
+ @builder.queue :block2
135
+ @builder.queued_blocks.map(&:name).first.should eql(:block1)
136
+ @builder.queued_blocks.map(&:name).second.should eql(:block3)
137
+ @builder.queued_blocks.map(&:name).third.should eql(:block2)
138
+ end
139
+
140
+ it "should allow a definition to be provided for a queued block" do
141
+ block = Proc.new do |options| end
142
+ @builder.queue :test_block, &block
143
+ container = @builder.queued_blocks.first
144
+ container.block.should eql block
145
+ end
146
+ end
147
+
148
+ describe "render_template method" do
149
+ it "should attempt to render a partial specified as the :template parameter" do
150
+ view = mock()
151
+ builder = Blocks::Base.new(view)
152
+ view.expects(:render).with{ |template, options| template == "my_template"}
153
+ builder.render_template("my_template")
154
+ end
155
+
156
+ it "should set all of the global options as local variables to the partial it renders" do
157
+ view = mock()
158
+ builder = Blocks::Base.new(view)
159
+ view.expects(:render).with { |template, options| template == 'some_template' && options[:blocks] == builder }
160
+ builder.render_template("some_template")
161
+ end
162
+
163
+ it "should capture the data of a block if a block has been specified" do
164
+ block = Proc.new { |options| "my captured block" }
165
+ builder = Blocks::Base.new(@view)
166
+ @view.expects(:render).with { |tempate, options| options[:captured_block] == "my captured block" }
167
+ builder.render_template("template", &block)
168
+ end
169
+
170
+ it "should by default add a variable to the partial called 'blocks' as a pointer to the Blocks::Base instance" do
171
+ view = mock()
172
+ builder = Blocks::Base.new(view)
173
+ view.expects(:render).with { |template, options| options[:blocks] == builder }
174
+ builder.render_template("some_template")
175
+ end
176
+
177
+ it "should allow the user to override the local variable passed to the partial as a pointer to the Blocks::Base instance" do
178
+ view = mock()
179
+ builder = Blocks::Base.new(view, :variable => "my_variable")
180
+ view.expects(:render).with { |template, options| options[:blocks].should be_nil }
181
+ builder.render_template("some_template")
182
+ end
183
+ end
184
+
185
+ describe "before method" do
186
+ it "should be aliased with prepend" do
187
+ block = Proc.new { |options| }
188
+ @builder.prepend :some_block, &block
189
+ @builder.blocks[:before_some_block].should be_present
190
+ end
191
+
192
+ it "should defined before blocks as the block name with the word 'before_' prepended to it" do
193
+ block = Proc.new { |options| }
194
+ @builder.before :some_block, &block
195
+ @builder.blocks[:before_some_block].should be_present
196
+ end
197
+
198
+ it "should store a before block in an array" do
199
+ block = Proc.new { |options| }
200
+ @builder.before :some_block, &block
201
+ before_blocks = @builder.blocks[:before_some_block]
202
+ before_blocks.should be_a(Array)
203
+ end
204
+
205
+ it "should store a before block as a Blocks::Container" do
206
+ block = Proc.new { |options| }
207
+ @builder.before :some_block, :option1 => "some option", &block
208
+ before_blocks = @builder.blocks[:before_some_block]
209
+ block_container = before_blocks.first
210
+ block_container.should be_a(Blocks::Container)
211
+ block_container.options.should eql :option1 => "some option"
212
+ block_container.block.should eql block
213
+ end
214
+
215
+ it "should queue before blocks if there are multiple defined" do
216
+ block = Proc.new { |options| }
217
+ block2 = Proc.new { |options| }
218
+ @builder.before :some_block, &block
219
+ @builder.before :some_block, &block2
220
+ before_blocks = @builder.blocks[:before_some_block]
221
+ before_blocks.length.should eql 2
222
+ end
223
+
224
+ it "should store before blocks in the order in which they are defined" do
225
+ block = Proc.new { |options| }
226
+ block2 = Proc.new { |options| }
227
+ block3 = Proc.new { |options| }
228
+ @builder.before :some_block, &block
229
+ @builder.before :some_block, &block2
230
+ @builder.before :some_block, &block3
231
+ before_blocks = @builder.blocks[:before_some_block]
232
+ before_blocks.first.block.should eql block
233
+ before_blocks.second.block.should eql block2
234
+ before_blocks.third.block.should eql block3
235
+ end
236
+ end
237
+
238
+ describe "after method" do
239
+ it "should be aliased with append and for" do
240
+ block = Proc.new { |options| }
241
+ @builder.append :some_block, &block
242
+ @builder.blocks[:after_some_block].should be_present
243
+
244
+ block = Proc.new { |options| }
245
+ @builder.for :some_block, &block
246
+ @builder.blocks[:after_some_block].should be_present
247
+ end
248
+
249
+ it "should defined after blocks as the block name with the word 'after_' prepended to it" do
250
+ block = Proc.new { |options| }
251
+ @builder.after :some_block, &block
252
+ @builder.blocks[:after_some_block].should be_present
253
+ end
254
+
255
+ it "should store a after block in an array" do
256
+ block = Proc.new { |options| }
257
+ @builder.after :some_block, &block
258
+ after_blocks = @builder.blocks[:after_some_block]
259
+ after_blocks.should be_a(Array)
260
+ end
261
+
262
+ it "should store a after block as a Blocks::Container" do
263
+ block = Proc.new { |options| }
264
+ @builder.after :some_block, :option1 => "some option", &block
265
+ after_blocks = @builder.blocks[:after_some_block]
266
+ block_container = after_blocks.first
267
+ block_container.should be_a(Blocks::Container)
268
+ block_container.options.should eql :option1 => "some option"
269
+ block_container.block.should eql block
270
+ end
271
+
272
+ it "should queue after blocks if there are multiple defined" do
273
+ block = Proc.new { |options| }
274
+ block2 = Proc.new { |options| }
275
+ @builder.after :some_block, &block
276
+ @builder.after :some_block, &block2
277
+ after_blocks = @builder.blocks[:after_some_block]
278
+ after_blocks.length.should eql 2
279
+ end
280
+
281
+ it "should store after blocks in the order in which they are defined" do
282
+ block = Proc.new { |options| }
283
+ block2 = Proc.new { |options| }
284
+ block3 = Proc.new { |options| }
285
+ @builder.after :some_block, &block
286
+ @builder.after :some_block, &block2
287
+ @builder.after :some_block, &block3
288
+ after_blocks = @builder.blocks[:after_some_block]
289
+ after_blocks.first.block.should eql block
290
+ after_blocks.second.block.should eql block2
291
+ after_blocks.third.block.should eql block3
292
+ end
293
+ end
294
+
295
+ describe "render method" do
296
+ it "should alias the render method as use" do
297
+ block = Proc.new {"output"}
298
+ @builder.define :some_block, &block
299
+ @builder.use(:some_block).should eql "output"
300
+ end
301
+
302
+ it "should be able to use a defined block by its name" do
303
+ block = Proc.new {"output"}
304
+ @builder.define :some_block, &block
305
+ @builder.render(:some_block).should eql "output"
306
+ end
307
+
308
+ it "should automatically pass in an options hash to a defined block that takes one paramter when that block is used" do
309
+ block = Proc.new {|options| "Options are #{options.inspect}"}
310
+ @builder.define :some_block, &block
311
+ @builder.render(:some_block).should eql "Options are {}"
312
+ end
313
+
314
+ it "should be able to use a defined block by its name and pass in runtime arguments as a hash" do
315
+ block = Proc.new do |options|
316
+ print_hash(options)
317
+ end
318
+ @builder.define :some_block, &block
319
+ @builder.render(:some_block, :param1 => 1, :param2 => "value2").should eql print_hash(:param1 => 1, :param2 => "value2")
320
+ end
321
+
322
+ it "should be able to use a defined block by its name and pass in runtime arguments one by one" do
323
+ block = Proc.new do |first_param, second_param, options|
324
+ "first_param: #{first_param}, second_param: #{second_param}, #{print_hash options}"
325
+ end
326
+ @builder.define :some_block, &block
327
+ @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql("first_param: 3, second_param: 4, #{print_hash(:param1 => 1, :param2 => "value2")}")
328
+ end
329
+
330
+ it "should match up the number of arguments to a defined block with the parameters passed when a block is used" do
331
+ block = Proc.new {|first_param| "first_param = #{first_param}"}
332
+ @builder.define :some_block, &block
333
+ @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql "first_param = 3"
334
+
335
+ block = Proc.new {|first_param, second_param| "first_param = #{first_param}, second_param = #{second_param}"}
336
+ @builder.replace :some_block, &block
337
+ @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql "first_param = 3, second_param = 4"
338
+
339
+ block = Proc.new do |first_param, second_param, options|
340
+ "first_param: #{first_param}, second_param: #{second_param}, #{print_hash options}"
341
+ end
342
+ @builder.replace :some_block, &block
343
+ @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql("first_param: 3, second_param: 4, #{print_hash(:param1 => 1, :param2 => "value2")}")
344
+ end
345
+
346
+ it "should not render anything if using a block that has been defined" do
347
+ @builder.use_partials = true
348
+ @view.expects(:capture).never
349
+ @view.expects(:render).with("some_block", {}).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
350
+ @view.expects(:render).with("blocks/some_block", {}).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
351
+ @builder.render :some_block
352
+ end
353
+
354
+ it "should first attempt to capture a block's contents when blocks.render is called" do
355
+ block = Proc.new {|options|}
356
+ @view.expects(:capture).with(:value1 => 1, :value2 => 2)
357
+ @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).never
358
+ @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never
359
+ @builder.define :some_block, &block
360
+ @builder.render :some_block, :value1 => 1, :value2 => 2
361
+ end
362
+
363
+ it "should second attempt to render a local partial by the block's name when blocks.render is called" do
364
+ @builder.use_partials = true
365
+ @view.expects(:capture).with(:value1 => 1, :value2 => 2).never
366
+ @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).once
367
+ @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never
368
+ @builder.render :some_block, :value1 => 1, :value2 => 2
369
+ end
370
+
371
+ it "should third attempt to render a global partial by the block's name when blocks.render is called" do
372
+ @builder.use_partials = true
373
+ @view.expects(:capture).with(:value1 => 1, :value2 => 2).never
374
+ @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
375
+ @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).once
376
+ @builder.render :some_block, :value1 => 1, :value2 => 2
377
+ end
378
+
379
+ it "should fourth attempt to render a default block when blocks.render is called" do
380
+ block = Proc.new {|options|}
381
+ @builder.use_partials = true
382
+ @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
383
+ @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
384
+ @view.expects(:capture).with(:value1 => 1, :value2 => 2)
385
+ @builder.render :some_block, :value1 => 1, :value2 => 2, &block
386
+ end
387
+
388
+ it "should not attempt to render a partial if use_partials is set to false" do
389
+ @builder.use_partials = false
390
+ block = Proc.new {|options|}
391
+ @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).never
392
+ @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never
393
+ @view.expects(:capture).with(:value1 => 1, :value2 => 2)
394
+ @builder.render :some_block, :value1 => 1, :value2 => 2, &block
395
+ end
396
+
397
+ it "should not attempt to render a partial if use_partials is passed in as false as an option to Blocks::Base.new" do
398
+ mocha_teardown
399
+ @builder = Blocks::Base.new(@view, :use_partials => false)
400
+ @builder.expects(:render_before_blocks).at_least_once
401
+ @builder.expects(:render_after_blocks).at_least_once
402
+ block = Proc.new {|options|}
403
+ @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).never
404
+ @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never
405
+ @view.expects(:capture).with(:value1 => 1, :value2 => 2)
406
+ @builder.render :some_block, :value1 => 1, :value2 => 2, &block
407
+ end
408
+
409
+ it "should override hash options for a block by merging the runtime options the define default options into the queue level options into the global options" do
410
+ block = Proc.new {|options|}
411
+ @builder.global_options.merge!(:param1 => "global level", :param2 => "global level", :param3 => "global level", :param4 => "global level")
412
+ @builder.queue(:my_before_block, :param1 => "queue level", :param2 => "queue level")
413
+ @builder.define(:my_before_block, :param1 => "define level", :param2 => "define level", :param3 => "define level", &block)
414
+ block_container = @builder.queued_blocks.first
415
+ @view.expects(:capture).with(:param4 => 'global level', :param1 => 'use level', :param2 => 'queue level', :param3 => 'define level')
416
+ @builder.render block_container, :param1 => "use level"
417
+ end
418
+
419
+ it "should render the contents of a defined block when that block is used" do
420
+ block = Proc.new {}
421
+ @view.expects(:capture).with(nil).returns("rendered content")
422
+ @builder.define :some_block, &block
423
+ buffer = @builder.render :some_block
424
+ buffer.should eql "rendered content"
425
+ end
426
+
427
+ describe "with a collection passed in" do
428
+ it "should render a block for each element of the collection with the name of the block used as the name of the element passed into the block" do
429
+ block = Proc.new {|item, options| "output#{options[:some_block]} "}
430
+ @builder.define :some_block, &block
431
+ @builder.render(:some_block, :collection => [1,2,3]).should eql "output1 output2 output3 "
432
+ end
433
+
434
+ it "should render a block for each element of the collection with the 'as' option specifying the name of the element passed into the block" do
435
+ block = Proc.new {|item, options| "output#{options[:my_block_name]} "}
436
+ @builder.define :some_block, &block
437
+ @builder.render(:some_block, :collection => [1,2,3], :as => "my_block_name").should eql "output1 output2 output3 "
438
+ end
439
+
440
+ it "should render a block for each element of the collection with a surrounding element if that option is specified" do
441
+ block = Proc.new {|item, options| "output#{options[:my_block_name]} "}
442
+ @builder.define :some_block, &block
443
+ @builder.render(:some_block, :collection => [1,2,3], :surrounding_tag => "div").should eql "<div>output </div><div>output </div><div>output </div>"
444
+ end
445
+
446
+ it "should render a block for each element of the collection with a surrounding element and specified html options if those options are specified" do
447
+ block = Proc.new {|item, options| "output#{options[:my_block_name]} "}
448
+ @builder.define :some_block, &block
449
+ @builder.render(:some_block, :collection => [1,2,3], :surrounding_tag => "div", :surrounding_tag_html => {:class => lambda { @view.cycle("even", "odd")}, :style => "color:red"}).should eql "<div class=\"even\" style=\"color:red\">output </div><div class=\"odd\" style=\"color:red\">output </div><div class=\"even\" style=\"color:red\">output </div>"
450
+ end
451
+
452
+ it "should be able to render before blocks before each element of a collection" do
453
+ before_block = Proc.new {|item, options| "before#{options[:some_block]} "}
454
+ @builder.before :some_block, &before_block
455
+
456
+ block = Proc.new {|item, options| "output#{options[:some_block]} "}
457
+ @builder.define :some_block, &block
458
+ @builder.render(:some_block, :collection => [1,2,3]).should eql "before1 output1 before2 output2 before3 output3 "
459
+ end
460
+
461
+ it "should be able to render after blocks before each element of a collection" do
462
+ after_block = Proc.new {|item, options| "after#{options[:some_block]} "}
463
+ @builder.after :some_block, &after_block
464
+
465
+ block = Proc.new {|item, options| "output#{options[:some_block]} "}
466
+ @builder.define :some_block, &block
467
+ @builder.render(:some_block, :collection => [1,2,3]).should eql "output1 after1 output2 after2 output3 after3 "
468
+ end
469
+
470
+ it "should be able to render before and after blocks before each element of a collection" do
471
+ before_block = Proc.new {|item, options| "before#{options[:some_block]} "}
472
+ @builder.before :some_block, &before_block
473
+
474
+ after_block = Proc.new {|item, options| "after#{options[:some_block]} "}
475
+ @builder.after :some_block, &after_block
476
+
477
+ block = Proc.new {|item, options| "output#{options[:some_block]} "}
478
+ @builder.define :some_block, &block
479
+ @builder.render(:some_block, :collection => [1,2,3]).should eql "before1 output1 after1 before2 output2 after2 before3 output3 after3 "
480
+ end
481
+
482
+ it "should by default put surrounding elements around before and after blocks" do
483
+ before_block = Proc.new {|item, options| "before#{options[:some_block]} "}
484
+ @builder.before :some_block, &before_block
485
+
486
+ after_block = Proc.new {|item, options| "after#{options[:some_block]} "}
487
+ @builder.after :some_block, &after_block
488
+
489
+ block = Proc.new {|item, options| "output#{options[:some_block]} "}
490
+ @builder.define :some_block, &block
491
+ @builder.render(:some_block, :collection => [1,2,3], :surrounding_tag => "div").should eql "<div>before1 output1 after1 </div><div>before2 output2 after2 </div><div>before3 output3 after3 </div>"
492
+ end
493
+
494
+ it "should allow the global option to be set to render before and after blocks outside of surrounding elements" do
495
+ Blocks.surrounding_tag_surrounds_before_and_after_blocks = false
496
+ @builder = Blocks::Base.new(@view)
497
+ before_block = Proc.new {|item, options| "before#{options[:some_block]} "}
498
+ @builder.before :some_block, &before_block
499
+
500
+ after_block = Proc.new {|item, options| "after#{options[:some_block]} "}
501
+ @builder.after :some_block, &after_block
502
+
503
+ block = Proc.new {|item, options| "output#{options[:some_block]} "}
504
+ @builder.define :some_block, &block
505
+ @builder.render(:some_block, :collection => [1,2,3], :surrounding_tag => "div").should eql "before1 <div>output1 </div>after1 before2 <div>output2 </div>after2 before3 <div>output3 </div>after3 "
506
+ end
507
+
508
+ it "should allow the option to be set to render before and after blocks outside of surrounding elements to be specified when Blocks is initialized" do
509
+ @builder = Blocks::Base.new(@view, :surrounding_tag_surrounds_before_and_after_blocks => false)
510
+ before_block = Proc.new {|item, options| "before#{options[:some_block]} "}
511
+ @builder.before :some_block, &before_block
512
+
513
+ after_block = Proc.new {|item, options| "after#{options[:some_block]} "}
514
+ @builder.after :some_block, &after_block
515
+
516
+ block = Proc.new {|item, options| "output#{options[:some_block]} "}
517
+ @builder.define :some_block, &block
518
+ @builder.render(:some_block, :collection => [1,2,3], :surrounding_tag => "div").should eql "before1 <div>output1 </div>after1 before2 <div>output2 </div>after2 before3 <div>output3 </div>after3 "
519
+ end
520
+ end
521
+ end
522
+
523
+ describe "render method - before blocks" do
524
+ before :each do
525
+ @builder.expects(:render_block).at_least_once
526
+ @builder.expects(:render_after_blocks).at_least_once
527
+ end
528
+
529
+ it "should render before blocks when using a block" do
530
+ block = Proc.new {|value1, value2, options|}
531
+ @builder.before("my_before_block", &block)
532
+ @view.expects(:capture).with(1, 2, :value3 => 3, :value4 => 4)
533
+ @builder.render :my_before_block, 1, 2, :value3 => 3, :value4 => 4
534
+ end
535
+
536
+ it "should override hash options for before blocks by merging the runtime options into the before block options into the block options into the global options" do
537
+ block = Proc.new {|options|}
538
+ @builder.global_options.merge!(:param1 => "global level", :param2 => "global level", :param3 => "global level", :param4 => "global level")
539
+ @builder.define(:my_before_block, :param1 => "block level", :param2 => "block level", :param3 => "block level", &block)
540
+ @builder.before(:my_before_block, :param1 => "before block level", :param2 => "before block level", &block)
541
+ @view.expects(:capture).with(:param4 => 'global level', :param1 => 'top level', :param2 => 'before block level', :param3 => 'block level')
542
+ @builder.render :my_before_block, :param1 => "top level"
543
+ end
544
+ end
545
+
546
+ describe "render method - around blocks" do
547
+ it "should be able to render code around another block" do
548
+ my_block = Proc.new { "test" }
549
+ around_block = Proc.new { |content_block| "<span>#{content_block.call}</span>" }
550
+ @builder.define(:my_block, &my_block)
551
+ @builder.around(:my_block, &around_block)
552
+ @builder.render(:my_block).should eql("&lt;span&gt;test&lt;/span&gt;")
553
+ end
554
+
555
+ it "should be able to nest multiple around blocks with the last defined around block on the outside" do
556
+ my_block = Proc.new { "test" }
557
+ around_block1 = Proc.new { |content_block| "<h1>#{content_block.call}</h1>" }
558
+ around_block2 = Proc.new { |content_block| "<span style='font-size: 100px'>#{content_block.call}</span>" }
559
+ around_block3 = Proc.new { |content_block| "<span style='color:red'>#{content_block.call}</span>" }
560
+ @builder.define(:my_block, &my_block)
561
+ @builder.around(:my_block, &around_block1)
562
+ @builder.around(:my_block, &around_block2)
563
+ @builder.around(:my_block, &around_block3)
564
+ @builder.render(:my_block).should eql("&lt;h1&gt;&amp;lt;span style='font-size: 100px'&amp;gt;&amp;amp;lt;span style='color:red'&amp;amp;gt;test&amp;amp;lt;/span&amp;amp;gt;&amp;lt;/span&amp;gt;&lt;/h1&gt;")
565
+ end
566
+ end
567
+
568
+ describe "render method - after blocks" do
569
+ before :each do
570
+ @builder.expects(:render_block).at_least_once
571
+ @builder.expects(:render_before_blocks).at_least_once
572
+ end
573
+
574
+ it "should render after blocks when using a block" do
575
+ block = Proc.new {|value1, value2, options|}
576
+ @builder.after("my_after_block", &block)
577
+ @view.expects(:capture).with(1, 2, :value3 => 3, :value4 => 4)
578
+ @builder.render :my_after_block, 1, 2, :value3 => 3, :value4 => 4
579
+ end
580
+
581
+ it "should override hash options for after blocks by merging the runtime options into the after block options into the block options into the global options" do
582
+ block = Proc.new {|options|}
583
+ @builder.global_options.merge!(:param1 => "global level", :param2 => "global level", :param3 => "global level", :param4 => "global level")
584
+ @builder.define(:my_after_block, :param1 => "block level", :param2 => "block level", :param3 => "block level", &block)
585
+ @builder.after(:my_after_block, :param1 => "after block level", :param2 => "after block level", &block)
586
+ @view.expects(:capture).with(:param4 => 'global level', :param1 => 'top level', :param2 => 'after block level', :param3 => 'block level')
587
+ @builder.render :my_after_block, :param1 => "top level"
588
+ end
589
+ end
590
+
591
+ describe "method_missing method" do
592
+ it "should start a new block group if a method is missing" do
593
+ @builder.some_method
594
+ queued_blocks = @builder.block_groups[:some_method]
595
+ queued_blocks.should eql []
596
+ end
597
+
598
+ it "should add items to a queue when a new block group is started" do
599
+ @builder.some_method do
600
+ @builder.queue :myblock1
601
+ @builder.queue :myblock2
602
+ end
603
+ @builder.some_method2 do
604
+ @builder.queue :myblock3
605
+ end
606
+ queued_blocks = @builder.block_groups[:some_method]
607
+ queued_blocks.length.should eql 2
608
+ queued_blocks.first.name.should eql :myblock1
609
+ queued_blocks.second.name.should eql :myblock2
610
+ queued_blocks = @builder.block_groups[:some_method2]
611
+ queued_blocks.length.should eql 1
612
+ queued_blocks.first.name.should eql :myblock3
613
+ @builder.queued_blocks.should eql []
614
+ end
615
+ end
616
+
617
+ describe "evaluated_procs method" do
618
+ it "should evaluate any proc options" do
619
+ proc1 = lambda {@view.cycle("even", "odd")}
620
+ proc2 = lambda {@view.cycle("one", "two")}
621
+ evaluated_procs = @builder.evaluated_procs(:class => proc1, :id => proc2, :style => "color:red")
622
+ evaluated_procs[:class].should eql "even"
623
+ evaluated_procs[:id].should eql "one"
624
+ evaluated_procs[:style].should eql "color:red"
625
+ end
626
+
627
+ it "should pass any additional arguments to evaluated procs" do
628
+ proc1 = lambda { |param1, param2| "user_#{param1}_#{param2}"}
629
+ evaluated_procs = @builder.evaluated_procs({:class => proc1}, 1, 2)
630
+ evaluated_procs[:class].should eql "user_1_2"
631
+ end
632
+ end
633
+
634
+ describe "evaluated_proc method" do
635
+ it "should evaluate a proc" do
636
+ proc = lambda {@view.cycle("even", "odd")}
637
+ @builder.evaluated_proc(proc).should eql "even"
638
+ @builder.evaluated_proc(proc).should eql "odd"
639
+ @builder.evaluated_proc(proc).should eql "even"
640
+ end
641
+
642
+ it "should just return the value if it is not a proc" do
643
+ @builder.evaluated_proc("1234").should eql "1234"
644
+ end
645
+
646
+ it "should return nil if no arguments are specified" do
647
+ @builder.evaluated_proc.should be_nil
648
+ end
649
+
650
+ it "should treat the first argument as the potential proc to evaluate" do
651
+ @builder.evaluated_proc(1, 2, 3).should eql 1
652
+ end
653
+
654
+ it "should pass any additional arguments to the evaluated proc" do
655
+ proc1 = lambda { |param1, param2| "user_#{param1}_#{param2}"}
656
+ @builder.evaluated_proc(proc1, 1, 2).should eql "user_1_2"
657
+ end
658
+ end
659
+ end