Class: BuildingBlocks::Base
- Inherits:
-
Object
- Object
- BuildingBlocks::Base
- Defined in:
- lib/building_blocks/base.rb
Instance Attribute Summary collapse
-
#anonymous_block_number ⇒ Object
counter, used to give unnamed blocks a unique name.
-
#block_groups ⇒ Object
A Hash of queued_blocks arrays; a new array is started when method_missing is invoked.
-
#blocks ⇒ Object
Hash of block names to BuildingBlocks::Container objects.
-
#global_options ⇒ Object
These are the options that are passed into the initalize method.
-
#queued_blocks ⇒ Object
Array of BuildingBlocks::Container objects, storing the order of blocks as they were queued.
-
#surrounding_tag_surrounds_before_and_after_blocks ⇒ Object
Boolean variable for whether BuildingBlocks should render before and after blocks inside or outside of a collections’ elements’ surrounding tags.
-
#template_folder ⇒ Object
The default folder to look in for global partials.
-
#use_partials ⇒ Object
Boolean variable for whether BuildingBlocks should attempt to render blocks as partials if a defined block cannot be found.
-
#variable ⇒ Object
The variable to use when rendering the partial for the templating feature (by default, “blocks”).
-
#view ⇒ Object
a pointer to the ActionView that called BuildingBlocks.
Instance Method Summary collapse
-
#after(name, options = {}, &block) ⇒ Object
(also: #append, #for)
Add a block to render after another block.
-
#around(name, options = {}, &block) ⇒ Object
Add a block to render around another block.
-
#before(name, options = {}, &block) ⇒ Object
(also: #prepend)
Add a block to render before another block.
-
#define(name, options = {}, &block) ⇒ Object
Define a block, unless a block by the same name is already defined.
-
#defined?(name) ⇒ Boolean
Checks if a particular block has been defined within the current block scope.
- #evaluated_proc(*args) ⇒ Object
- #evaluated_procs(*args) ⇒ Object
-
#queue(*args, &block) ⇒ Object
Queue a block for later rendering, such as within a template.
-
#render(name_or_container, *args, &block) ⇒ Object
(also: #use)
Render a block, first rendering any “before” blocks, then rendering the block itself, then rendering any “after” blocks.
-
#render_template(partial, &block) ⇒ Object
Render a partial, treating it as a template, and any code in the block argument will impact how the template renders <%= BuildingBlocks::Base.new(self).render_template(“shared/wizard”) do |blocks| %> <% blocks.queue :step1 %> <% blocks.queue :step2 do %> My overridden Step 2 | <% end %> <% blocks.queue :step3 %> <% blocks.queue do %> | Anonymous Step 4 <% end %> <% end %>.
-
#replace(name, options = {}, &block) ⇒ Object
Define a block, replacing an existing block by the same name if it is already defined.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(m, *args, &block) ⇒ Object (protected)
If a method is missing, we’ll assume the user is starting a new block group by that missing method name
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/building_blocks/base.rb', line 408 def method_missing(m, *args, &block) = args. # If the specified block group has already been defined, it is simply returned here for iteration. # It will consist of all the blocks used in this block group that have yet to be rendered, # as the call for their use occurred before the template was rendered (where their definitions likely occurred) return self.block_groups[m] unless self.block_groups[m].nil? # Allows for nested block groups, store the current block positions array and start a new one original_queued_blocks = self.queued_blocks self.queued_blocks = [] self.block_groups[m] = self.queued_blocks # Capture the contents of the block group (this will only capture block definitions and block renders; it will ignore anything else) view.capture(.merge(), &block) if block_given? # restore the original block positions array self.queued_blocks = original_queued_blocks nil end |
Instance Attribute Details
#anonymous_block_number ⇒ Object
counter, used to give unnamed blocks a unique name
13 14 15 |
# File 'lib/building_blocks/base.rb', line 13 def anonymous_block_number @anonymous_block_number end |
#block_groups ⇒ Object
A Hash of queued_blocks arrays; a new array is started when method_missing is invoked
16 17 18 |
# File 'lib/building_blocks/base.rb', line 16 def block_groups @block_groups end |
#blocks ⇒ Object
Hash of block names to BuildingBlocks::Container objects
7 8 9 |
# File 'lib/building_blocks/base.rb', line 7 def blocks @blocks end |
#global_options ⇒ Object
These are the options that are passed into the initalize method
19 20 21 |
# File 'lib/building_blocks/base.rb', line 19 def @global_options end |
#queued_blocks ⇒ Object
Array of BuildingBlocks::Container objects, storing the order of blocks as they were queued
10 11 12 |
# File 'lib/building_blocks/base.rb', line 10 def queued_blocks @queued_blocks end |
#surrounding_tag_surrounds_before_and_after_blocks ⇒ Object
Boolean variable for whether BuildingBlocks should render before and after blocks inside or outside of a collections’ elements’ surrounding tags
31 32 33 |
# File 'lib/building_blocks/base.rb', line 31 def surrounding_tag_surrounds_before_and_after_blocks @surrounding_tag_surrounds_before_and_after_blocks end |
#template_folder ⇒ Object
The default folder to look in for global partials
22 23 24 |
# File 'lib/building_blocks/base.rb', line 22 def template_folder @template_folder end |
#use_partials ⇒ Object
Boolean variable for whether BuildingBlocks should attempt to render blocks as partials if a defined block cannot be found
28 29 30 |
# File 'lib/building_blocks/base.rb', line 28 def use_partials @use_partials end |
#variable ⇒ Object
The variable to use when rendering the partial for the templating feature (by default, “blocks”)
25 26 27 |
# File 'lib/building_blocks/base.rb', line 25 def variable @variable end |
#view ⇒ Object
a pointer to the ActionView that called BuildingBlocks
4 5 6 |
# File 'lib/building_blocks/base.rb', line 4 def view @view end |
Instance Method Details
#after(name, options = {}, &block) ⇒ Object Also known as: append, for
Add a block to render after another block. This after block will be put into an array so that multiple
after blocks may be queued. They will render in the order in which they are declared when the
"blocks#render" method is called. Any options specified to the after block will override any options
specified in the block definition.
<% blocks.define :wizard, :option1 => 1, :option2 => 2 do |options| %>
Step 2 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
<% end %>
<% blocks.after :wizard, :option1 => 3 do
Step 3 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
<% end %>
<% blocks.after :wizard, :option2 => 4 do
Step 4 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
<% end %>
<%= blocks.render :wizard %>
<!-- Will render:
Step 2 (:option1 => 1, :option2 => 2)<br />
Step 3 (:option1 => 3, :option2 => 2)<br />
Step 4 (:option1 => 1, :option2 => 4)<br />
-->
<%= blocks.render :wizard, :step => @step %>
Options:
name
-
The name of the block to render this code after when that block is rendered
options
-
Any options to specify to the after block when it renders. These will override any options specified when the block was defined.
block
-
The block of code to render after another block
338 339 340 341 |
# File 'lib/building_blocks/base.rb', line 338 def after(name, ={}, &block) self.queue_block_container("after_#{name.to_s}", , &block) nil end |
#around(name, options = {}, &block) ⇒ Object
Add a block to render around another block. This around block will be put into an array so that multiple
around blocks may be queued. They will render in the order in which they are declared when the
"blocks#render" method is called, with the last declared around block being rendered as the outer-most code, and
the first declared around block rendered as the inner-most code. Any options specified to the after block will override any options
specified in the block definition. The user of an around block must declare a block with at least one parameter and
should invoke the #call method on that argument.
<% blocks.define :my_block do %>
test
<% end %>
<% blocks.around :my_block do |content_block| %>
<h1>
<%= content_block.call %>
</h1>
<% end %>
<% blocks.around :my_block do |content_block| %>
<span style="color:red">
<%= content_block.call %>
</span>
<% end %>
<%= blocks.render :my_block %>
<!-- Will render:
<h1>
<span style="color:red">
test
</span>
</h1>
Options:
name
-
The name of the block to render this code around when that block is rendered
options
-
Any options to specify to the around block when it renders. These will override any options specified when the block was defined.
block
-
The block of code to render after another block
385 386 387 388 |
# File 'lib/building_blocks/base.rb', line 385 def around(name, ={}, &block) self.queue_block_container("around_#{name.to_s}", , &block) nil end |
#before(name, options = {}, &block) ⇒ Object Also known as: prepend
Add a block to render before another block. This before block will be put into an array so that multiple
before blocks may be queued. They will render in the order in which they are declared when the
"blocks#render" method is called. Any options specified to the before block will override any options
specified in the block definition.
<% blocks.define :wizard, :option1 => 1, :option2 => 2 do |options| %>
Step 2 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
<% end %>
<% blocks.before :wizard, :option1 => 3 do
Step 0 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
<% end %>
<% blocks.before :wizard, :option2 => 4 do
Step 1 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
<% end %>
<%= blocks.render :wizard %>
<!-- Will render:
Step 0 (:option1 => 3, :option2 => 2)<br />
Step 1 (:option1 => 1, :option2 => 4)<br />
Step 2 (:option1 => 1, :option2 => 2)<br />
-->
<%= blocks.render :wizard, :step => @step %>
Options:
name
-
The name of the block to render this code before when that block is rendered
options
-
Any options to specify to the before block when it renders. These will override any options specified when the block was defined.
block
-
The block of code to render before another block
299 300 301 302 |
# File 'lib/building_blocks/base.rb', line 299 def before(name, ={}, &block) self.queue_block_container("before_#{name.to_s}", , &block) nil end |
#define(name, options = {}, &block) ⇒ Object
Define a block, unless a block by the same name is already defined.
<%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
<%= options[:parameter1] %> and <%= options[:parameter2] %>
<% end %>
Options:
name
-
The name of the block being defined (either a string or a symbol)
options
-
The default options for the block definition. Any or all of these options may be overrideen by whomever calls “blocks.render” on this block.
block
-
The block that is to be rendered when “blocks.render” is called for this block.
55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/building_blocks/base.rb', line 55 def define(name, ={}, &block) collection = .delete(:collection) if collection collection.each do |object| define(evaluated_proc(name, object, ), , &block) end else self.define_block_container(name, , &block) end nil end |
#defined?(name) ⇒ Boolean
Checks if a particular block has been defined within the current block scope.
<%= blocks.defined? :some_block_name %>
Options:
name
-
The name of the block to check
38 39 40 |
# File 'lib/building_blocks/base.rb', line 38 def defined?(name) !blocks[name.to_sym].nil? end |
#evaluated_proc(*args) ⇒ Object
399 400 401 402 403 |
# File 'lib/building_blocks/base.rb', line 399 def evaluated_proc(*args) return nil unless args.present? v = args.shift v.is_a?(Proc) ? v.call(*(args[0, v.arity])) : v end |
#evaluated_procs(*args) ⇒ Object
390 391 392 393 394 395 396 397 |
# File 'lib/building_blocks/base.rb', line 390 def evaluated_procs(*args) = args.shift.presence || {} if .is_a?(Proc) evaluated_proc(, *args) else .inject({}) { |hash, (k, v)| hash[k] = evaluated_proc(v, *args); hash} end end |
#queue(*args, &block) ⇒ Object
Queue a block for later rendering, such as within a template.
<%= BuildingBlocks::Base.new(self).render_template("shared/wizard") do |blocks| %>
<% blocks.queue :step1 %>
<% blocks.queue :step2 do %>
My overridden Step 2 |
<% end %>
<% blocks.queue :step3 %>
<% blocks.queue do %>
| Anonymous Step 4
<% end %>
<% end %>
<!-- In /app/views/shared/wizard -->
<% blocks.define :step1 do %>
Step 1 |
<% end %>
<% blocks.define :step2 do %>
Step 2 |
<% end %>
<% blocks.define :step3 do %>
Step 3
<% end %>
<% blocks.queued_blocks.each do |block| %>
<%= blocks.render block %>
<% end %>
<!-- Will render: Step 1 | My overridden Step 2 | Step 3 | Anonymous Step 4-->
Options:
- *args
-
The options to pass in when this block is rendered. These will override any options provided to the actual block definition. Any or all of these options may be overriden by whoever calls “blocks.render” on this block. Usually the first of these args will be the name of the block being queued (either a string or a symbol)
block
-
The optional block definition to render when the queued block is rendered
218 219 220 221 |
# File 'lib/building_blocks/base.rb', line 218 def queue(*args, &block) self.queued_blocks << self.define_block_container(*args, &block) nil end |
#render(name_or_container, *args, &block) ⇒ Object Also known as: use
Render a block, first rendering any “before” blocks, then rendering the block itself, then rendering any “after” blocks. Additionally, a collection may also be passed in, and BuildingBlocks will render an the block, along with corresponding before and after blocks for each element of the collection. BuildingBlocks will make four different attempts to render block:
1) Look for a block that has been defined inline elsewhere, using the blocks.define method:
<% blocks.define :wizard do |options| %>
Inline Block Step#<%= options[:step] %>.
<% end %>
<%= blocks.render :wizard, :step => @step %>
2) Look for a partial within the current controller's view directory:
<%= blocks.render :wizard, :step => @step %>
<!-- In /app/views/pages/_wizard.html.erb (assuming it is the pages controller running): -->
Controller-specific Block Step# <%= step %>.
3) Look for a partial with the global blocks view directory (by default /app/views/blocks/):
<%= blocks.render :wizard, :step => @step %>
<!-- In /app/views/blocks/_wizard.html.erb: -->
Global Block Step#<%= step %>.
4) Render the default implementation for the block if provided to the blocks.render call:
<%= blocks.render :wizard, :step => @step do |options| do %>
Default Implementation Block Step#<%= options %>.
<% end %>
Options:
name
-
The name of the block to render (either a string or a symbol)
- *args
-
Any arguments to pass to the block to be rendered (and also to be passed to any “before” and “after” blocks). The last argument in the list can be a hash and can include the following special options:
[:collection] The collection of elements to render blocks for [:as] The variable name to assign the current element in the collection being rendered over [:surrounding_tag] The content tag to render around a block, which might be particularly useful when rendering a collection of blocks, such as for a list or table [:surrounding_tag_html] The attributes to be applied to the HTML content tag, such as styling or special properties. Please note, any Procs passed in will automatically be evaluated (For example: :class => lambda { cycle("even", "odd") })
block
-
The default block to render if no such block block that is to be rendered when “blocks.render” is called for this block.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/building_blocks/base.rb', line 133 def render(name_or_container, *args, &block) = args. collection = .delete(:collection) buffer = ActiveSupport::SafeBuffer.new if collection as = .delete(:as) collection.each do |object| cloned_args = args.clone cloned_args.unshift(object) = .clone = .merge(object.) if object.is_a?(BuildingBlocks::Container) cloned_args.push() block_name = evaluated_proc(name_or_container, *cloned_args) as_name = (as.presence || block_name).to_sym [as_name] = object buffer << render(block_name, *cloned_args, &block) end else surrounding_tag = .delete(:surrounding_tag) surrounding_tag_html = .delete(:surrounding_tag_html) args.push() if surrounding_tag_surrounds_before_and_after_blocks buffer << content_tag(surrounding_tag, surrounding_tag_html, *args) do temp_buffer = ActiveSupport::SafeBuffer.new temp_buffer << render_before_blocks(name_or_container, *args) temp_buffer << render_block_with_around_blocks(name_or_container, *args, &block) temp_buffer << render_after_blocks(name_or_container, *args) end else buffer << render_before_blocks(name_or_container, *args) buffer << content_tag(surrounding_tag, surrounding_tag_html, *args) do render_block_with_around_blocks(name_or_container, *args, &block) end buffer << render_after_blocks(name_or_container, *args) end end buffer end |
#render_template(partial, &block) ⇒ Object
Render a partial, treating it as a template, and any code in the block argument will impact how the template renders
<%= BuildingBlocks::Base.new(self).render_template("shared/wizard") do |blocks| %>
<% blocks.queue :step1 %>
<% blocks.queue :step2 do %>
My overridden Step 2 |
<% end %>
<% blocks.queue :step3 %>
<% blocks.queue do %>
| Anonymous Step 4
<% end %>
<% end %>
<!-- In /app/views/shared/wizard -->
<% blocks.define :step1 do %>
Step 1 |
<% end %>
<% blocks.define :step2 do %>
Step 2 |
<% end %>
<% blocks.define :step3 do %>
Step 3
<% end %>
<% blocks.queued_blocks.each do |block| %>
<%= blocks.render block %>
<% end %>
<!-- Will render: Step 1 | My overridden Step 2 | Step 3 | Anonymous Step 4-->
Options:
partial
-
The partial to render as a template
block
-
An optional block with code that affects how the template renders
258 259 260 261 262 263 264 |
# File 'lib/building_blocks/base.rb', line 258 def render_template(partial, &block) = .clone [self.variable] = self [:captured_block] = view.capture(self, &block) if block_given? view.render partial, end |
#replace(name, options = {}, &block) ⇒ Object
Define a block, replacing an existing block by the same name if it is already defined.
<%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
<%= options[:parameter1] %> and <%= options[:parameter2] %>
<% end %>
<%= blocks.replace :some_block_name, :parameter3 => "3", :parameter4 => "4" do |options| %>
<%= options[:parameter3] %> and <%= options[:parameter4] %>
<% end %>
Options:
name
-
The name of the block being defined (either a string or a symbol)
options
-
The default options for the block definition. Any or all of these options may be overrideen by whomever calls “blocks.render” on this block.
block
-
The block that is to be rendered when “blocks.render” is called for this block.
85 86 87 88 89 |
# File 'lib/building_blocks/base.rb', line 85 def replace(name, ={}, &block) blocks[name.to_sym] = nil self.define_block_container(name, , &block) nil end |