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.
- checksums.yaml +5 -13
- data/.gitignore +4 -4
- data/.travis.yml +51 -0
- data/Gemfile +15 -2
- data/Guardfile +15 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +3 -7
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/blocks.gemspec +18 -11
- data/gemfiles/Gemfile.rails-3-0-stable +13 -0
- data/gemfiles/Gemfile.rails-3-1-stable +13 -0
- data/gemfiles/Gemfile.rails-3-2-stable +13 -0
- data/gemfiles/Gemfile.rails-4-0-stable +12 -0
- data/gemfiles/Gemfile.rails-4-1-stable +12 -0
- data/gemfiles/Gemfile.rails-4-2-stable +12 -0
- data/gemfiles/Gemfile.rails-5-0-stable +10 -0
- data/gemfiles/Gemfile.rails-5-1-stable +10 -0
- data/lib/blocks.rb +41 -20
- data/lib/blocks/action_view_extensions/view_extensions.rb +26 -0
- data/lib/blocks/builders/block_definition.rb +71 -0
- data/lib/blocks/builders/builder.rb +159 -0
- data/lib/blocks/builders/hook_definition.rb +25 -0
- data/lib/blocks/experimental/builder_permissions.rb +52 -0
- data/lib/blocks/experimental/invalid_permissions_handler.rb +27 -0
- data/lib/blocks/renderers/abstract_renderer.rb +69 -0
- data/lib/blocks/renderers/adjacent_blocks_renderer.rb +15 -0
- data/lib/blocks/renderers/block_placeholder.rb +13 -0
- data/lib/blocks/renderers/block_renderer.rb +13 -0
- data/lib/blocks/renderers/block_with_hooks_renderer.rb +35 -0
- data/lib/blocks/renderers/collection_renderer.rb +17 -0
- data/lib/blocks/renderers/nesting_blocks_renderer.rb +24 -0
- data/lib/blocks/renderers/partial_renderer.rb +18 -0
- data/lib/blocks/renderers/renderer.rb +43 -0
- data/lib/blocks/renderers/runtime_context.rb +193 -0
- data/lib/blocks/renderers/wrapper_renderer.rb +19 -0
- data/lib/blocks/utilities/configurator.rb +26 -0
- data/lib/blocks/utilities/dynamic_configuration.rb +71 -0
- data/lib/blocks/utilities/hash_with_caller.rb +73 -0
- data/lib/blocks/utilities/hash_with_render_strategy.rb +47 -0
- data/lib/blocks/utilities/options_set.rb +95 -0
- data/lib/blocks/version.rb +1 -1
- metadata +70 -80
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/README.rdoc +0 -99
- data/blocks_render_order.graffle +0 -1397
- data/blocks_render_order.png +0 -0
- data/lib/blocks/base.rb +0 -580
- data/lib/blocks/container.rb +0 -5
- data/lib/blocks/controller_additions.rb +0 -9
- data/lib/blocks/view_additions.rb +0 -10
- data/rails/init.rb +0 -1
- data/spec/blocks/base_spec.rb +0 -641
- data/spec/blocks/blocks_spec.rb +0 -12
- data/spec/blocks/view_additions_spec.rb +0 -22
- data/spec/spec_helper.rb +0 -22
data/blocks_render_order.png
DELETED
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
|