blocks 2.8.0 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +4 -4
  3. data/.travis.yml +51 -0
  4. data/Gemfile +15 -2
  5. data/Guardfile +15 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +41 -0
  8. data/Rakefile +3 -7
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/blocks.gemspec +18 -11
  12. data/gemfiles/Gemfile.rails-3-0-stable +13 -0
  13. data/gemfiles/Gemfile.rails-3-1-stable +13 -0
  14. data/gemfiles/Gemfile.rails-3-2-stable +13 -0
  15. data/gemfiles/Gemfile.rails-4-0-stable +12 -0
  16. data/gemfiles/Gemfile.rails-4-1-stable +12 -0
  17. data/gemfiles/Gemfile.rails-4-2-stable +12 -0
  18. data/gemfiles/Gemfile.rails-5-0-stable +10 -0
  19. data/gemfiles/Gemfile.rails-5-1-stable +10 -0
  20. data/lib/blocks.rb +41 -20
  21. data/lib/blocks/action_view_extensions/view_extensions.rb +26 -0
  22. data/lib/blocks/builders/block_definition.rb +71 -0
  23. data/lib/blocks/builders/builder.rb +159 -0
  24. data/lib/blocks/builders/hook_definition.rb +25 -0
  25. data/lib/blocks/experimental/builder_permissions.rb +52 -0
  26. data/lib/blocks/experimental/invalid_permissions_handler.rb +27 -0
  27. data/lib/blocks/renderers/abstract_renderer.rb +69 -0
  28. data/lib/blocks/renderers/adjacent_blocks_renderer.rb +15 -0
  29. data/lib/blocks/renderers/block_placeholder.rb +13 -0
  30. data/lib/blocks/renderers/block_renderer.rb +13 -0
  31. data/lib/blocks/renderers/block_with_hooks_renderer.rb +35 -0
  32. data/lib/blocks/renderers/collection_renderer.rb +17 -0
  33. data/lib/blocks/renderers/nesting_blocks_renderer.rb +24 -0
  34. data/lib/blocks/renderers/partial_renderer.rb +18 -0
  35. data/lib/blocks/renderers/renderer.rb +43 -0
  36. data/lib/blocks/renderers/runtime_context.rb +193 -0
  37. data/lib/blocks/renderers/wrapper_renderer.rb +19 -0
  38. data/lib/blocks/utilities/configurator.rb +26 -0
  39. data/lib/blocks/utilities/dynamic_configuration.rb +71 -0
  40. data/lib/blocks/utilities/hash_with_caller.rb +73 -0
  41. data/lib/blocks/utilities/hash_with_render_strategy.rb +47 -0
  42. data/lib/blocks/utilities/options_set.rb +95 -0
  43. data/lib/blocks/version.rb +1 -1
  44. metadata +70 -80
  45. data/.ruby-gemset +0 -1
  46. data/.ruby-version +0 -1
  47. data/README.rdoc +0 -99
  48. data/blocks_render_order.graffle +0 -1397
  49. data/blocks_render_order.png +0 -0
  50. data/lib/blocks/base.rb +0 -580
  51. data/lib/blocks/container.rb +0 -5
  52. data/lib/blocks/controller_additions.rb +0 -9
  53. data/lib/blocks/view_additions.rb +0 -10
  54. data/rails/init.rb +0 -1
  55. data/spec/blocks/base_spec.rb +0 -641
  56. data/spec/blocks/blocks_spec.rb +0 -12
  57. data/spec/blocks/view_additions_spec.rb +0 -22
  58. data/spec/spec_helper.rb +0 -22
Binary file
data/lib/blocks/base.rb DELETED
@@ -1,580 +0,0 @@
1
- require 'active_support'
2
-
3
- module Blocks
4
- class Base
5
- include CallWithParams
6
-
7
- # a pointer to the ActionView that called Blocks
8
- attr_accessor :view
9
-
10
- # Hash of block names to Blocks::Container objects
11
- attr_accessor :blocks
12
-
13
- # counter, used to give unnamed blocks a unique name
14
- attr_accessor :anonymous_block_number
15
-
16
- # These are the options that are passed into the initalize method
17
- attr_accessor :global_options
18
-
19
- # Hash of block names that have been explicitely skipped
20
- attr_accessor :skipped_blocks
21
-
22
- # Checks if a particular block has been defined within the current block scope.
23
- # <%= blocks.defined? :some_block_name %>
24
- # Options:
25
- # [+name+]
26
- # The name of the block to check
27
- def defined?(name)
28
- !blocks[name].nil?
29
- end
30
-
31
- # Define a block, unless a block by the same name is already defined.
32
- # <%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
33
- # <%= options[:parameter1] %> and <%= options[:parameter2] %>
34
- # <% end %>
35
- #
36
- # Options:
37
- # [+name+]
38
- # The name of the block being defined (either a string or a symbol or a Proc)
39
- # [+options+]
40
- # The default options for the block definition. Any or all of these options may be overridden by
41
- # whomever calls "blocks.render" on this block. If :collection => some_array,
42
- # Blocks will assume that the first argument is a Proc and define a block for each object in the
43
- # collection
44
- # [+block+]
45
- # The block that is to be rendered when "blocks.render" is called for this block.
46
- def define(name, options={}, &block)
47
- collection = options.delete(:collection)
48
-
49
- if collection
50
- collection.each do |object|
51
- define(call_with_params(name, object, options), options, &block)
52
- end
53
- else
54
- self.define_block_container(name, options, &block)
55
- end
56
-
57
- nil
58
- end
59
-
60
- # Define a block, replacing an existing block by the same name if it is already defined.
61
- # <%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
62
- # <%= options[:parameter1] %> and <%= options[:parameter2] %>
63
- # <% end %>
64
- #
65
- # <%= blocks.replace :some_block_name, :parameter3 => "3", :parameter4 => "4" do |options| %>
66
- # <%= options[:parameter3] %> and <%= options[:parameter4] %>
67
- # <% end %>
68
- # Options:
69
- # [+name+]
70
- # The name of the block being defined (either a string or a symbol)
71
- # [+options+]
72
- # The default options for the block definition. Any or all of these options may be overridden by
73
- # whomever calls "blocks.render" on this block.
74
- # [+block+]
75
- # The block that is to be rendered when "blocks.render" is called for this block.
76
- def replace(name, options={}, &block)
77
- blocks[name] = nil
78
- self.define_block_container(name, options, &block)
79
- nil
80
- end
81
-
82
- # Skip the rendering of a particular block when blocks.render is called for the a particular block name
83
- # <%= blocks.define :some_block_name do %>
84
- # My output
85
- # <% end %>
86
- #
87
- # <%= blocks.skip :some_block_name %>
88
- #
89
- # <%= blocks.render :some_block_name %>
90
- # <%# will not render anything %>
91
- # Options:
92
- # [+name+]
93
- # The name of the block to skip rendering for
94
- def skip(name)
95
- blocks[name] = nil
96
- skipped_blocks[name] = true
97
- self.define_block_container(name) do
98
- end
99
- nil
100
- end
101
-
102
- # Render a block, first rendering any "before" blocks, then rendering the block itself, then rendering
103
- # any "after" blocks. Additionally, a collection may also be passed in, and Blocks will render
104
- # an the block, along with corresponding before and after blocks for each element of the collection.
105
- # Blocks will make either two or four different attempts to render the block, depending on how use_partials
106
- # is globally set, or an option is passed in to the render call to either use partials or skip partials:
107
- # 1) Look for a block that has been defined inline elsewhere, using the blocks.define method:
108
- # <% blocks.define :wizard do |options| %>
109
- # Inline Block Step#<%= options[:step] %>.
110
- # <% end %>
111
- #
112
- # <%= blocks.render :wizard, :step => @step %>
113
- # 2) [IF use_partials is globally set to true or passed in as a runtime option,
114
- # and skip_partials is not passed in as a runtime option]
115
- # Look for a partial within the current controller's view directory:
116
- # <%= blocks.render :wizard, :step => @step %>
117
- #
118
- # <!-- In /app/views/pages/_wizard.html.erb (assuming it is the pages controller running): -->
119
- # Controller-specific Block Step# <%= step %>.
120
- # 3) [IF use_partials is globally set to true or passed in as a runtime option,
121
- # and skip_partials is not passed in as a runtime option]
122
- # Look for a partial with the global blocks view directory (by default /app/views/blocks/):
123
- # <%= blocks.render :wizard, :step => @step %>
124
- #
125
- # <!-- In /app/views/blocks/_wizard.html.erb: -->
126
- # Global Block Step#<%= step %>.
127
- # 4) Render the default implementation for the block if provided to the blocks.render call:
128
- # <%= blocks.render :wizard, :step => @step do |options| do %>
129
- # Default Implementation Block Step#<%= options %>.
130
- # <% end %>
131
- # Options:
132
- # [+name_or_container+]
133
- # The name of the block to render (either a string or a symbol)
134
- # [+*args+]
135
- # Any arguments to pass to the block to be rendered (and also to be passed to any "before" and "after" blocks).
136
- # The last argument in the list can be a hash and can include the following special options:
137
- # [:collection]
138
- # The collection of elements to render blocks for
139
- # [:as]
140
- # The variable name to assign the current element in the collection being rendered over
141
- # [:wrap_with]
142
- # The content tag to render around this block (For example: :wrap_with => {:tag => TAG_TYPE, :class => "my-class", :style => "border: 1px solid black"})
143
- # [:wrap_each]
144
- # The content tag to render around each item in a collection (For example: :wrap_each { :class => lambda { cycle("even", "odd") }})
145
- # [:use_partials]
146
- # Overrides the globally defined use_partials and tells Blocks to render partials in trying to render a block
147
- # [:skip_partials]
148
- # Overrides the globally defined use_partials and tells Blocks to not render any partials in trying to render a block
149
- # [+block+]
150
- # The default block to render if no such block block that is to be rendered when "blocks.render" is called for this block.
151
- def render(name_or_container, *args, &block)
152
- options = args.extract_options!
153
- collection = options.delete(:collection)
154
- name = extract_block_name name_or_container
155
- if skipped_blocks[name] && global_options.skip_applies_to_surrounding_blocks
156
- return
157
- end
158
-
159
- buffer = ActiveSupport::SafeBuffer.new
160
-
161
- wrap_with = options.delete(:wrap_with) || {}
162
-
163
- if collection
164
- as = options.delete(:as)
165
- wrap_each = options.delete(:wrap_each) || {}
166
-
167
- buffer = content_tag_with_block(wrap_with[:tag], wrap_with.except(:tag), *args) do
168
- collection.each_with_index do |object, index|
169
- cloned_args = args.clone
170
- cloned_args.unshift(object)
171
- cloned_options = options.clone
172
- cloned_options[:current_index] = index
173
- cloned_options = cloned_options.merge(object.options) if object.is_a?(Blocks::Container)
174
- cloned_args.push(cloned_options)
175
-
176
- block_name = call_with_params(name_or_container, *cloned_args)
177
- as_name = (as.presence || block_name).to_sym
178
- cloned_options[as_name] = object
179
- cloned_options[:wrap_with] = wrap_each
180
-
181
- buffer << render(block_name, *cloned_args, &block)
182
- end
183
- buffer
184
- end
185
- else
186
- args.push(options)
187
-
188
- if global_options.merge(options)[:wrap_before_and_after_blocks]
189
- buffer << content_tag_with_block(wrap_with[:tag], wrap_with.except(:tag), *args) do
190
- temp_buffer = ActiveSupport::SafeBuffer.new
191
- temp_buffer << render_before_blocks(name_or_container, *args)
192
- temp_buffer << render_block_with_around_blocks(name_or_container, *args, &block)
193
- temp_buffer << render_after_blocks(name_or_container, *args)
194
- end
195
- else
196
- buffer << render_before_blocks(name_or_container, *args)
197
- buffer << content_tag_with_block(wrap_with[:tag], wrap_with.except(:tag), *args) do
198
- render_block_with_around_blocks(name_or_container, *args, &block)
199
- end
200
- buffer << render_after_blocks(name_or_container, *args)
201
- end
202
- end
203
-
204
- buffer
205
- end
206
- alias use render
207
-
208
- # Render a block, first rendering any "before" blocks, then rendering the block itself, then rendering
209
- # any "after" blocks. Additionally, a collection may also be passed in, and Blocks will render
210
- # an the block, along with corresponding before and after blocks for each element of the collection.
211
- # Blocks will make two different attempts to render block:
212
- # 1) Look for a block that has been defined inline elsewhere, using the blocks.define method:
213
- # <% blocks.define :wizard do |options| %>
214
- # Inline Block Step#<%= options[:step] %>.
215
- # <% end %>
216
- #
217
- # <%= blocks.render :wizard, :step => @step %>
218
- # 2) Render the default implementation for the block if provided to the blocks.render call:
219
- # <%= blocks.render :wizard, :step => @step do |options| do %>
220
- # Default Implementation Block Step#<%= options %>.
221
- # <% end %>
222
- # Options:
223
- # [+name_or_container+]
224
- # The name of the block to render (either a string or a symbol)
225
- # [+*args+]
226
- # Any arguments to pass to the block to be rendered (and also to be passed to any "before" and "after" blocks).
227
- # The last argument in the list can be a hash and can include the following special options:
228
- # [:collection]
229
- # The collection of elements to render blocks for
230
- # [:as]
231
- # The variable name to assign the current element in the collection being rendered over
232
- # [:wrap_with]
233
- # The content tag to render around this block (For example: :wrap_with => {:tag => TAG_TYPE, :class => "my-class", :style => "border: 1px solid black"})
234
- # [:wrap_each]
235
- # The content tag to render around each item in a collection (For example: :wrap_each { :class => lambda { cycle("even", "odd") }})
236
- # [+block+]
237
- # The default block to render if no such block block that is to be rendered when "blocks.render" is called for this block.
238
- def render_without_partials(name_or_container, *args, &block)
239
- options = args.extract_options!
240
- options[:skip_partials] = true
241
- args.push(options)
242
- render(name_or_container, *args, &block)
243
- end
244
-
245
- # Render a block, first rendering any "before" blocks, then rendering the block itself, then rendering
246
- # any "after" blocks. Additionally, a collection may also be passed in, and Blocks will render
247
- # an the block, along with corresponding before and after blocks for each element of the collection.
248
- # Blocks will make four different attempts to render block:
249
- # 1) Look for a block that has been defined inline elsewhere, using the blocks.define method:
250
- # <% blocks.define :wizard do |options| %>
251
- # Inline Block Step#<%= options[:step] %>.
252
- # <% end %>
253
- #
254
- # <%= blocks.render :wizard, :step => @step %>
255
- # 2) Look for a partial within the current controller's view directory:
256
- # <%= blocks.render :wizard, :step => @step %>
257
- #
258
- # <!-- In /app/views/pages/_wizard.html.erb (assuming it is the pages controller running): -->
259
- # Controller-specific Block Step# <%= step %>.
260
- # 3) Look for a partial with the global blocks view directory (by default /app/views/blocks/):
261
- # <%= blocks.render :wizard, :step => @step %>
262
- #
263
- # <!-- In /app/views/blocks/_wizard.html.erb: -->
264
- # Global Block Step#<%= step %>.
265
- # 4) Render the default implementation for the block if provided to the blocks.render call:
266
- # <%= blocks.render :wizard, :step => @step do |options| do %>
267
- # Default Implementation Block Step#<%= options %>.
268
- # <% end %>
269
- # Options:
270
- # [+name_or_container+]
271
- # The name of the block to render (either a string or a symbol)
272
- # [+*args+]
273
- # Any arguments to pass to the block to be rendered (and also to be passed to any "before" and "after" blocks).
274
- # The last argument in the list can be a hash and can include the following special options:
275
- # [:collection]
276
- # The collection of elements to render blocks for
277
- # [:as]
278
- # The variable name to assign the current element in the collection being rendered over
279
- # [:wrap_with]
280
- # The content tag to render around this block (For example: :wrap_with => {:tag => TAG_TYPE, :class => "my-class", :style => "border: 1px solid black"})
281
- # [:wrap_each]
282
- # The content tag to render around each item in a collection (For example: :wrap_each { :class => lambda { cycle("even", "odd") }})
283
- # [+block+]
284
- # The default block to render if no such block block that is to be rendered when "blocks.render" is called for this block.
285
- def render_with_partials(name_or_container, *args, &block)
286
- options = args.extract_options!
287
- options[:use_partials] = true
288
- args.push(options)
289
- render(name_or_container, *args, &block)
290
- end
291
-
292
- # Add a block to render before another block. This before block will be put into an array so that multiple
293
- # before blocks may be queued. They will render in the order in which they are declared when the
294
- # "blocks#render" method is called. Any options specified to the before block will override any options
295
- # specified in the block definition.
296
- # <% blocks.define :wizard, :option1 => 1, :option2 => 2 do |options| %>
297
- # Step 2 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
298
- # <% end %>
299
- #
300
- # <% blocks.before :wizard, :option1 => 3 do
301
- # Step 0 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
302
- # <% end %>
303
- #
304
- # <% blocks.before :wizard, :option2 => 4 do
305
- # Step 1 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
306
- # <% end %>
307
- #
308
- # <%= blocks.render :wizard %>
309
- #
310
- # <!-- Will render:
311
- # Step 0 (:option1 => 3, :option2 => 2)<br />
312
- # Step 1 (:option1 => 1, :option2 => 4)<br />
313
- # Step 2 (:option1 => 1, :option2 => 2)<br />
314
- # -->
315
- #
316
- # <%= blocks.render :wizard, :step => @step %>
317
- # Options:
318
- # [+name+]
319
- # The name of the block to render this code before when that block is rendered
320
- # [+options+]
321
- # Any options to specify to the before block when it renders. These will override any options
322
- # specified when the block was defined.
323
- # [+block+]
324
- # The block of code to render before another block
325
- def before(name, options={}, &block)
326
- self.add_block_container_to_list("before_#{name.to_s}", options, &block)
327
- nil
328
- end
329
- alias prepend before
330
-
331
- # Add a block to render after another block. This after block will be put into an array so that multiple
332
- # after blocks may be queued. They will render in the order in which they are declared when the
333
- # "blocks#render" method is called. Any options specified to the after block will override any options
334
- # specified in the block definition.
335
- # <% blocks.define :wizard, :option1 => 1, :option2 => 2 do |options| %>
336
- # Step 2 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
337
- # <% end %>
338
- #
339
- # <% blocks.after :wizard, :option1 => 3 do
340
- # Step 3 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
341
- # <% end %>
342
- #
343
- # <% blocks.after :wizard, :option2 => 4 do
344
- # Step 4 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
345
- # <% end %>
346
- #
347
- # <%= blocks.render :wizard %>
348
- #
349
- # <!-- Will render:
350
- # Step 2 (:option1 => 1, :option2 => 2)<br />
351
- # Step 3 (:option1 => 3, :option2 => 2)<br />
352
- # Step 4 (:option1 => 1, :option2 => 4)<br />
353
- # -->
354
- #
355
- # <%= blocks.render :wizard, :step => @step %>
356
- # Options:
357
- # [+name+]
358
- # The name of the block to render this code after when that block is rendered
359
- # [+options+]
360
- # Any options to specify to the after block when it renders. These will override any options
361
- # specified when the block was defined.
362
- # [+block+]
363
- # The block of code to render after another block
364
- def after(name, options={}, &block)
365
- self.add_block_container_to_list("after_#{name.to_s}", options, &block)
366
- nil
367
- end
368
- alias append after
369
- alias for after
370
-
371
- # Add a block to render around another block. This around block will be put into an array so that multiple
372
- # around blocks may be queued. They will render in the order in which they are declared when the
373
- # "blocks#render" method is called, with the last declared around block being rendered as the outer-most code, and
374
- # the first declared around block rendered as the inner-most code. Any options specified to the after block will override any options
375
- # specified in the block definition. The user of an around block must declare a block with at least one parameter and
376
- # should invoke the #call method on that argument.
377
- #
378
- # <% blocks.define :my_block do %>
379
- # test
380
- # <% end %>
381
- #
382
- # <% blocks.around :my_block do |content_block| %>
383
- # <h1>
384
- # <%= content_block.call %>
385
- # </h1>
386
- # <% end %>
387
- #
388
- # <% blocks.around :my_block do |content_block| %>
389
- # <span style="color:red">
390
- # <%= content_block.call %>
391
- # </span>
392
- # <% end %>
393
- #
394
- # <%= blocks.render :my_block %>
395
- #
396
- # <!-- Will render:
397
- # <h1>
398
- # <span style="color:red">
399
- # test
400
- # </span>
401
- # </h1>
402
- #
403
- # Options:
404
- # [+name+]
405
- # The name of the block to render this code around when that block is rendered
406
- # [+options+]
407
- # Any options to specify to the around block when it renders. These will override any options
408
- # specified when the block was defined.
409
- # [+block+]
410
- # The block of code to render after another block
411
- def around(name, options={}, &block)
412
- self.add_block_container_to_list("around_#{name.to_s}", options, &block)
413
- nil
414
- end
415
-
416
- def content_tag_with_block(tag, tag_html, *args, &block)
417
- if tag
418
- view.content_tag(tag, view.capture(&block), call_each_hash_value_with_params(tag_html, *args))
419
- else
420
- view.capture(&block)
421
- end
422
- end
423
-
424
- def initialize(view, options={})
425
- self.view = view
426
- self.global_options = Blocks.config.merge(options)
427
- self.skipped_blocks = HashWithIndifferentAccess.new
428
- self.blocks = HashWithIndifferentAccess.new
429
- self.anonymous_block_number = 0
430
- end
431
-
432
- protected
433
-
434
- # Return a unique name for an anonymously defined block (i.e. a block that has not been given a name)
435
- def anonymous_block_name
436
- self.anonymous_block_number += 1
437
- "block_#{anonymous_block_number}"
438
- end
439
-
440
- def render_block_with_around_blocks(name_or_container, *args, &block)
441
- name = extract_block_name name_or_container
442
- around_name = "around_#{name}"
443
-
444
- around_blocks = blocks[around_name].present? ? blocks[around_name].clone : []
445
-
446
- content_block = Proc.new do
447
- block_container = around_blocks.shift
448
- if block_container
449
- view.capture(content_block, *(args[0, block_container.block.arity - 1]), &block_container.block)
450
- else
451
- render_block(name_or_container, *args, &block)
452
- end
453
- end
454
- content_block.call
455
- end
456
-
457
- # Render a block, first trying to find a previously defined block with the same name
458
- def render_block(name_or_container, *args, &block)
459
- buffer = ActiveSupport::SafeBuffer.new
460
-
461
- name, block_render_options = extract_block_name_and_options(name_or_container)
462
-
463
- block_definition_options = {}
464
- if blocks[name]
465
- block_container = blocks[name]
466
- block_definition_options = block_container.options
467
- end
468
-
469
- options = global_options.merge(block_definition_options).merge(block_render_options).merge(args.extract_options!)
470
-
471
- if blocks[name]
472
- block_container = blocks[name]
473
- args.push(options)
474
- buffer << view.capture(*(args[0, block_container.block.arity]), &block_container.block)
475
- elsif options[:use_partials] && !options[:skip_partials]
476
- begin
477
- begin
478
- buffer << view.render("#{name.to_s}", options)
479
- rescue ActionView::MissingTemplate, ArgumentError
480
- buffer << view.render("#{options[:partials_folder]}/#{name.to_s}", options)
481
- end
482
- rescue ActionView::MissingTemplate, ArgumentError
483
- args.push(global_options.merge(options))
484
- buffer << view.capture(*(args[0, block.arity]), &block) if block_given?
485
- end
486
- else
487
- args.push(global_options.merge(options))
488
- buffer << view.capture(*(args[0, block.arity]), &block) if block_given?
489
- end
490
-
491
- buffer
492
- end
493
-
494
- # Render all the before blocks for a partial block
495
- def render_before_blocks(name_or_container, *args)
496
- render_before_or_after_blocks(name_or_container, "before", *args)
497
- end
498
-
499
- # Render all the after blocks for a partial block
500
- def render_after_blocks(name_or_container, *args)
501
- render_before_or_after_blocks(name_or_container, "after", *args)
502
- end
503
-
504
- # Utility method to render either the before or after blocks for a partial block
505
- def render_before_or_after_blocks(name_or_container, before_or_after, *args)
506
- options = args.extract_options!
507
-
508
- block_options = {}
509
- if (name_or_container.is_a?(Blocks::Container))
510
- name = name_or_container.name.to_sym
511
- block_options = name_or_container.options
512
- else
513
- name = name_or_container.to_sym
514
- block_options = blocks[name].options if blocks[name]
515
- end
516
-
517
- before_name = "#{before_or_after}_#{name.to_s}".to_sym
518
- buffer = ActiveSupport::SafeBuffer.new
519
-
520
- blocks[before_name].each do |block_container|
521
- args_clone = args.clone
522
- args_clone.push(global_options.merge(block_options).merge(block_container.options).merge(options))
523
- buffer << view.capture(*(args_clone[0, block_container.block.arity]), &block_container.block)
524
- end if blocks[before_name].present?
525
-
526
- buffer
527
- end
528
-
529
- # Build a Blocks::Container object given the passed in arguments
530
- def build_block_container(*args, &block)
531
- options = args.extract_options!
532
-
533
- anonymous = false
534
- if args.first
535
- name = args.shift
536
- else
537
- name = self.anonymous_block_name
538
- anonymous = true
539
- end
540
-
541
- block_container = Blocks::Container.new
542
- block_container.name = name.to_sym
543
- block_container.options = options
544
- block_container.block = block
545
- block_container.anonymous = anonymous
546
- block_container
547
- end
548
-
549
- # Build a Blocks::Container object and add it to an array of containers matching it's block name
550
- # (used only for queuing a collection of before, after, and around blocks for a particular block name)
551
- def add_block_container_to_list(*args, &block)
552
- block_container = self.build_block_container(*args, &block)
553
- if blocks[block_container.name].nil?
554
- blocks[block_container.name] = [block_container]
555
- else
556
- blocks[block_container.name] << block_container
557
- end
558
- end
559
-
560
- # Build a Blocks::Container object and add it to the global hash of blocks if a block by the same
561
- # name is not already defined
562
- def define_block_container(*args, &block)
563
- block_container = self.build_block_container(*args, &block)
564
- blocks[block_container.name] = block_container if blocks[block_container.name].nil? && block_given?
565
- block_container
566
- end
567
-
568
- def extract_block_name(name_or_container)
569
- extract_block_name_and_options(name_or_container).first
570
- end
571
-
572
- def extract_block_name_and_options(name_or_container)
573
- if name_or_container.is_a?(Blocks::Container)
574
- [name_or_container.name, name_or_container.options]
575
- else
576
- [name_or_container, {}]
577
- end
578
- end
579
- end
580
- end