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