blocks 2.8.0 → 3.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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