blocks 1.2.5 → 2.1.0

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.
@@ -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