blocks 1.2.5 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +49 -0
- data/README.rdoc +1 -141
- data/Rakefile +22 -0
- data/VERSION +1 -0
- data/lib/blocks.rb +31 -5
- data/lib/blocks/base.rb +672 -0
- data/lib/blocks/controller_additions.rb +9 -0
- data/lib/blocks/view_additions.rb +12 -0
- data/rails/init.rb +1 -0
- data/spec/blocks/base_spec.rb +659 -0
- data/spec/blocks/blocks_spec.rb +24 -0
- data/spec/blocks/view_additions_spec.rb +22 -0
- data/spec/spec_helper.rb +19 -0
- metadata +287 -25
- data/LICENSE +0 -21
- data/app/helpers/blocks/helper_methods.rb +0 -35
- data/app/views/blocks/_list.html.erb +0 -31
- data/app/views/blocks/_table.html.erb +0 -105
- data/lib/blocks/builder.rb +0 -236
- data/lib/blocks/engine.rb +0 -12
- data/lib/blocks/list_for.rb +0 -14
- data/lib/blocks/table_for.rb +0 -18
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
2.1.0 (July 3, 2013)
|
2
|
+
* Biggest change is that this gem was moved back to the blocks repo and renamed from building-blocks to blocks, it's original name.
|
3
|
+
* changed rendering so that partials are no longer rendered by default
|
4
|
+
* surrounding_tag_surrounds_before_and_after_blocks is now false, by default, meaning that if a block has a surrounding_tag, it will only render the block's contents inside that tag, and any before and after blocks will render outside that tag.
|
5
|
+
* allows render options to be skipped or provider new helper methods, building blocks from the controller, got rid of aliases for "blocks", specify render order?
|
6
|
+
|
7
|
+
2.0.0 (October 18, 2012)
|
8
|
+
|
9
|
+
* Added ability to render a collection of objects and specify the surrounding elements and the html to apply to those surrounding elements
|
10
|
+
For example: blocks.render :test, :collection => @cuisine_types, :as => :cuisine_type, :surrounding_tag => "div", :surrounding_tag_html => {:class => Proc.new {cycle("even", "odd")}}
|
11
|
+
* Added ability to specify "around" blocks, i.e. blocks of view code that render around another block of code, such as:
|
12
|
+
<% blocks.around :test_block do |content_block| %>
|
13
|
+
<h1>
|
14
|
+
<%= content_block.call %>
|
15
|
+
</h1>
|
16
|
+
<% end %> %>
|
17
|
+
* Added a util method BuildingBlocks.render_template(self, partial, options={}, &block) that makes the templating feature easier to use
|
18
|
+
(as opposed to calling the long way: BuildingBlocks::Base.new(self, options={}).render_template(partial, &block))
|
19
|
+
* Aliased "#blocks" method that is available to views as "#buildingblocks", "#bb", and "#building_blocks"
|
20
|
+
* Aliased "#after" method to "#for", so that you can now call <%= blocks.for :block_name %> (should be slightly more familiar to users of content_for with yield)
|
21
|
+
* Added a "#setup" method to initialize BuildingBlocks globally (for example: BuildingBlocks.setup do |config| config.template_folder = "shared" end)
|
22
|
+
* Cleaned up the organization of the code base and now using autoload instead of require
|
23
|
+
* Removed :use_partials_for_before_and_after_hooks option from 1.2.2
|
24
|
+
|
25
|
+
1.2.3 (February 9, 2012)
|
26
|
+
|
27
|
+
* Created two new utility methods: evaluated_procs and evaluated_proc that allow parameters for blocks to be Proc objects so long as these methods are called to evaluate them. (These methods have been carried over and renamed from the table-for gem where they were used to be able to dynamically specify table css classes, styles, and ids at runtime).
|
28
|
+
|
29
|
+
1.2.2 (February 9, 2012)
|
30
|
+
|
31
|
+
* Allow :use_partials and :use_partials_for_before_and_after_hooks to be passed in as initialization options to BuildingBlocks::Base to control whether BuildingBlocks attempts to render partials when "blocks.render" is called.
|
32
|
+
|
33
|
+
1.2.1 (February 7, 2012)
|
34
|
+
|
35
|
+
* Only try to render "before" and "after" blocks as partials if that BuildingBlocks::USE_PARTIALS_FOR_BEFORE_AND_AFTER_HOOKS is globally set to true (set to false now by default)
|
36
|
+
|
37
|
+
1.2.0 (February 5, 2012)
|
38
|
+
|
39
|
+
* Changed prototype for "use" method, such that the name of the block being rendered is now a required parameter.
|
40
|
+
* Documented BuildingBlocks::Base more thoroughly
|
41
|
+
* Changed the blocks.use method to blocks.render (blocks.use is still available for legacy purposes)
|
42
|
+
* Removed the original render method and replaced with render_template that takes the partial and block to render as arguments.
|
43
|
+
|
44
|
+
1.1.0 (February 4, 2012)
|
45
|
+
|
46
|
+
* Ability to disable use of partials when rendering a block
|
47
|
+
* Ability to disable use of partials for before and after hooks
|
48
|
+
* Complete test coverage
|
49
|
+
* :template_folder and :variable options are no longer being passed in as part of the options hash to defined blocks and partials
|
data/README.rdoc
CHANGED
@@ -1,141 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Wiki[http://wiki.github.com/hunterae/blocks]
|
4
|
-
|
5
|
-
Blocks is a replacement / complement to content_for with yield. It allows a user to specify a block capable of taking parameters that may be passed in when using that block. A user may also specify other blocks to be prepended or appended before or after a specific block is rendered. A template may also be specified to blocks that will provide the layout for a specific component and provide default implementations for its blocks. In this way, blocks is able to offer a very simple to use table generator ({table_for}[https://github.com/hunterae/blocks/wiki/table_for]) and list generator (list_for).
|
6
|
-
|
7
|
-
== Installation
|
8
|
-
|
9
|
-
In <b>Rails 3</b>, add this to your Gemfile.
|
10
|
-
|
11
|
-
gem "blocks"
|
12
|
-
|
13
|
-
In <b>Rails 2</b>, add this to your environment.rb file. (At this time, it is untested in Rails 2)
|
14
|
-
|
15
|
-
config.gem "blocks"
|
16
|
-
|
17
|
-
Alternatively, you can install it as a plugin.
|
18
|
-
|
19
|
-
rails plugin install git://github.com/hunterae/blocks.git
|
20
|
-
|
21
|
-
|
22
|
-
== Getting Started
|
23
|
-
|
24
|
-
What makes blocks particularly powerful is that it represent a combination of the ruby definition of blocks and partials. A block may be defined inline utilizing syntax similar to that of content_for:
|
25
|
-
|
26
|
-
<%= blocks.define :some_block_name, :some_parameter => 1, :some_parameter2 => 2 do |options| %>
|
27
|
-
<%= options[:some_parameter] %>
|
28
|
-
<%= options[:some_parameter2] %>
|
29
|
-
<%= options[:some_parameter3] %>
|
30
|
-
<% end %>
|
31
|
-
|
32
|
-
or it may be written as a partial, existing in the controller view directory for whatever controller renders the view, or the globally configured blocks directory (views/blocks by default). The above block definition might then be written in the file views/blocks/_some_block_name.html.erb:
|
33
|
-
|
34
|
-
<%= some_parameter if defined?(some_parameter)%>
|
35
|
-
<%= some_parameter2 if defined?(some_parameter2) %>
|
36
|
-
<%= some_parameter3 if defined?(some_parameter3) %>
|
37
|
-
|
38
|
-
Notice that in the context of a partial, we have direct access to the parameters as local variables. However, since we're not utilizing "blocks.define" to create our block, we can't specify the default parameters :some_parameter and :some_parameter2 as we do in the first example. This has the potential to cause a runtime exception in the context of partials and we will need to assure that optional parameters are defined using "defined?".
|
39
|
-
|
40
|
-
In the first example, we specified two parameters that are provided automatically to the block named "some_block_name". They are "some_parameter" and "some_parameter2". In addition, the definition of the block is assuming that the user will be passing in another parameter called "some_parameter3". However, all parameters are passed in in a hash (or local variables for partials), no error will occur if the user fails to specify "some_parameter3".
|
41
|
-
|
42
|
-
Now, we may use the above block as follows:
|
43
|
-
|
44
|
-
<%= blocks.use :some_block_name %>
|
45
|
-
|
46
|
-
The system will first look for a block that's been defined inline by the name :some_block_name. If it cannot find one, it will try and render a partial with the same name within the current controller's view directory. Failing to find that, it will try and render a partial within the global blocks view directory (by default, views/blocks). If that partial also does not exist, it will give up and render nothing. (See [[Render Order]])
|
47
|
-
|
48
|
-
Here, we will see the output "1 2" for the first example (and "" for the second example). But if we pass in "some_parameter3", as follows:
|
49
|
-
|
50
|
-
<%= blocks.use :some_block_name, :some_parameter3 => 3 %>
|
51
|
-
|
52
|
-
Then we will see "1 2 3" for the first example (and "3" for the second example). Additionally, we can override any of the previous parameters when using a block simply by passing in the new value as a parameter:
|
53
|
-
|
54
|
-
<%= blocks.use :some_block_name, :some_parameter2 => "overridden", :some_parameter3 => 3 %>
|
55
|
-
|
56
|
-
In this case, we will see "1 overridden 3" for the first example (and "overridden 3" for the second example). Thus, we now have content_for but with parameters, and additional intelligence by utilizing partials.
|
57
|
-
|
58
|
-
== table_for
|
59
|
-
|
60
|
-
table_for is a useful example of how blocks may be utilized in an invaluable way. It is built entirely using the core blocks library. It is exposed as a helper method with the following prototype:
|
61
|
-
|
62
|
-
table_for(records, options={}, &block)
|
63
|
-
|
64
|
-
For example, if you have an Array of objects that respond to the following [:name, :email, :phonenumber] e.g.
|
65
|
-
|
66
|
-
@records = [OpenStruct.new({:name => "The Name", :email => "The Email", :phonenumber => "A phone number"}),
|
67
|
-
OpenStruct.new({:name => "The Second Name", :email => "The Second Email", :phonenumber => "A second phone number"})]
|
68
|
-
|
69
|
-
And using table_for you can very easily specify intricate details about the table (Note: most of the options in this example are optional):
|
70
|
-
|
71
|
-
<%= table_for @records,
|
72
|
-
:table_html => {:id => "records"},
|
73
|
-
:header_html => {:style => "color:red"},
|
74
|
-
:row_html => {:class => lambda { |parameters| cycle('odd', 'even')}},
|
75
|
-
:column_html => {:style => "color:green"} do |table| %>
|
76
|
-
<%= table.column :name, :column_html => {:style => "color:blue"}, :header_html => {:style => "color:orange"} %>
|
77
|
-
<%= table.column :email %>
|
78
|
-
<%= table.column :phonenumber, :column_html => {:style => "color:orange"}, :header_html => {:style => "color:blue"} %>
|
79
|
-
<%= table.column :label => "???" do %>
|
80
|
-
Some Random Column
|
81
|
-
<% end %>
|
82
|
-
<% end %>
|
83
|
-
|
84
|
-
Will generate the following table:
|
85
|
-
|
86
|
-
<table id="records">
|
87
|
-
<thead>
|
88
|
-
<tr>
|
89
|
-
<th style="color:orange">Name</th>
|
90
|
-
<th style="color:red">Email</th>
|
91
|
-
<th style="color:blue">Phonenumber</th>
|
92
|
-
<th style="color:red">???</th>
|
93
|
-
</tr>
|
94
|
-
</thead>
|
95
|
-
<tbody>
|
96
|
-
<tr class="odd">
|
97
|
-
<td style="color:blue">The Name</td>
|
98
|
-
<td style="color:green">The Email</td>
|
99
|
-
<td style="color:orange">A phone number</td>
|
100
|
-
<td style="color:green">Some Random Column</td>
|
101
|
-
</tr>
|
102
|
-
<tr class="even">
|
103
|
-
<td style="color:blue">The Second Name</td>
|
104
|
-
<td style="color:green">The Second Email</td>
|
105
|
-
<td style="color:orange">A second phone number</td>
|
106
|
-
<td style="color:green">Some Random Column</td>
|
107
|
-
</tr>
|
108
|
-
</tbody>
|
109
|
-
</table>
|
110
|
-
|
111
|
-
See {table_for}[https://github.com/hunterae/blocks/wiki/table_for] for details.
|
112
|
-
|
113
|
-
== Building Layouts
|
114
|
-
|
115
|
-
Utilizing blocks, we can rethink the way we define our templates. Everywhere where we might be tempted to write "yield :some_block_name", we can replace with "blocks.use :some_block_name". This gives us
|
116
|
-
the ability to provide a default implementation for that block if it cannot be found (see {Providing a Default Implementation of a Block}[https://github.com/hunterae/blocks/wiki/Providing-a-Default-Implementation-of-a-Block]), and provides hooks for being able to render code before and after :some_block_name, utilizing "blocks.before :some_block_name" and "blocks.after :some_block_name" (See {Before and After Blocks}[https://github.com/hunterae/blocks/wiki/Before-and-After-Blocks]]).
|
117
|
-
|
118
|
-
See {Building Layouts}[https://github.com/hunterae/blocks/wiki/Building-Layouts] for more details on how to utilize Blocks to build layouts.
|
119
|
-
|
120
|
-
== Wiki Docs
|
121
|
-
|
122
|
-
* {Basics}[https://github.com/hunterae/blocks/wiki/Basics]
|
123
|
-
* {Specifying your blocks as controller level partials}[https://github.com/hunterae/blocks/wiki/Specifying-your-blocks-as-controller-level-partials]
|
124
|
-
* {Specifying your blocks as global partials}[https://github.com/hunterae/blocks/wiki/Specifying-your-blocks-as-global-partials]
|
125
|
-
* {How Inline Blocks, Controller Level Blocks, and Global Blocks Work Together}[https://github.com/hunterae/blocks/wiki/How-Inline-Blocks,-Controller-Level-Blocks,-and-Global-Blocks-Work-Together]
|
126
|
-
* {Building Layouts}[https://github.com/hunterae/blocks/wiki/Building-Layouts]
|
127
|
-
* {Render Order}[https://github.com/hunterae/blocks/wiki/Render-Order]
|
128
|
-
* {Before and After Blocks}[https://github.com/hunterae/blocks/wiki/Before-and-After-Blocks]
|
129
|
-
* {Providing a Default Implementation of a Block}[https://github.com/hunterae/blocks/wiki/Providing-a-Default-Implementation-of-a-Block]
|
130
|
-
* {table_for}[https://github.com/hunterae/blocks/wiki/table_for]
|
131
|
-
* {Overriding the defaults in table_for}[https://github.com/hunterae/blocks/wiki/Overriding-the-defaults-in-table_for]
|
132
|
-
* {Defining your own reusage table_for implementation}[https://github.com/hunterae/blocks/wiki/Defining-your-own-reusage-table_for-implementation]
|
133
|
-
* {See more}[https://github.com/hunterae/blocks/wiki]
|
134
|
-
|
135
|
-
== Questions or Problems?
|
136
|
-
|
137
|
-
If you have any issues with Blocks which you cannot find the solution to in the documentation[https://github.com/hunterae/blocks/wiki], please add an {issue on GitHub}[https://github.com/hunterae/blocks/issues] or fork the project and send a pull request.
|
138
|
-
|
139
|
-
== Special Thanks
|
140
|
-
|
141
|
-
Thanks to Todd Fisher of Captico for implementation help and setup of gem and to Jon Phillips for suggestions and use case help.
|
1
|
+
Note: I am going to be completely rewriting this documentation, and what was here may have been invalid so stay tuned.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
|
3
|
+
RSpec::Core::RakeTask.new('spec')
|
4
|
+
|
5
|
+
# If you want to make this the default task
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'jeweler'
|
10
|
+
Jeweler::Tasks.new do |gemspec|
|
11
|
+
gemspec.name = "blocks"
|
12
|
+
gemspec.summary = "Blocks is an intricate way of rendering blocks of code, while combining some of the best features of content blocks and partials, and adding several new features that go above and beyond what a simple content_for with yield or a render :partial is capable of doing."
|
13
|
+
gemspec.description = "Blocks goes beyond blocks and partials"
|
14
|
+
gemspec.email = "hunterae@gmail.com"
|
15
|
+
gemspec.homepage = "http://github.com/hunterae/blocks"
|
16
|
+
gemspec.authors = ["Andrew Hunter"]
|
17
|
+
gemspec.files = FileList["[A-Z]*", "{lib,spec,rails}/**/*"] - FileList["**/*.log", "Gemfile", "Gemfile.lock"]
|
18
|
+
end
|
19
|
+
Jeweler::GemcutterTasks.new
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
22
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.0
|
data/lib/blocks.rb
CHANGED
@@ -1,5 +1,31 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require "action_view"
|
2
|
+
require "action_controller"
|
3
|
+
|
4
|
+
module Blocks
|
5
|
+
autoload :Base, "blocks/base"
|
6
|
+
autoload :Container, "blocks/container"
|
7
|
+
autoload :ViewAdditions, "blocks/view_additions"
|
8
|
+
autoload :ControllerAdditions, "blocks/controller_additions"
|
9
|
+
|
10
|
+
mattr_accessor :template_folder
|
11
|
+
@@template_folder = "blocks"
|
12
|
+
|
13
|
+
mattr_accessor :use_partials
|
14
|
+
@@use_partials = false
|
15
|
+
|
16
|
+
mattr_accessor :surrounding_tag_surrounds_before_and_after_blocks
|
17
|
+
@@surrounding_tag_surrounds_before_and_after_blocks = false
|
18
|
+
|
19
|
+
# Shortcut for using the templating feature / rendering templates
|
20
|
+
def self.render_template(view, partial, options={}, &block)
|
21
|
+
Blocks::Base.new(view, options).render_template(partial, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Default way to setup Blocks
|
25
|
+
def self.setup
|
26
|
+
yield self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
ActionView::Base.send :include, Blocks::ViewAdditions::ClassMethods
|
31
|
+
ActionController::Base.send :include, Blocks::ControllerAdditions::ClassMethods
|
data/lib/blocks/base.rb
ADDED
@@ -0,0 +1,672 @@
|
|
1
|
+
module Blocks
|
2
|
+
class Base
|
3
|
+
# a pointer to the ActionView that called Blocks
|
4
|
+
attr_accessor :view
|
5
|
+
|
6
|
+
# Hash of block names to Blocks::Container objects
|
7
|
+
attr_accessor :blocks
|
8
|
+
|
9
|
+
# Array of Blocks::Container objects, storing the order of blocks as they were queued
|
10
|
+
attr_accessor :queued_blocks
|
11
|
+
|
12
|
+
# counter, used to give unnamed blocks a unique name
|
13
|
+
attr_accessor :anonymous_block_number
|
14
|
+
|
15
|
+
# A Hash of queued_blocks arrays; a new array is started when method_missing is invoked
|
16
|
+
attr_accessor :block_groups
|
17
|
+
|
18
|
+
# These are the options that are passed into the initalize method
|
19
|
+
attr_accessor :global_options
|
20
|
+
|
21
|
+
# The default folder to look in for global partials
|
22
|
+
attr_accessor :template_folder
|
23
|
+
|
24
|
+
# The variable to use when rendering the partial for the templating feature (by default, "blocks")
|
25
|
+
attr_accessor :variable
|
26
|
+
|
27
|
+
# Boolean variable for whether Blocks should attempt to render blocks as partials if a defined block cannot be found
|
28
|
+
attr_accessor :use_partials
|
29
|
+
|
30
|
+
# Boolean variable for whether Blocks should render before and after blocks inside or outside of a collections' elements' surrounding tags
|
31
|
+
attr_accessor :surrounding_tag_surrounds_before_and_after_blocks
|
32
|
+
|
33
|
+
# Checks if a particular block has been defined within the current block scope.
|
34
|
+
# <%= blocks.defined? :some_block_name %>
|
35
|
+
# Options:
|
36
|
+
# [+name+]
|
37
|
+
# The name of the block to check
|
38
|
+
def defined?(name)
|
39
|
+
!blocks[name.to_sym].nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Define a block, unless a block by the same name is already defined.
|
43
|
+
# <%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
|
44
|
+
# <%= options[:parameter1] %> and <%= options[:parameter2] %>
|
45
|
+
# <% end %>
|
46
|
+
#
|
47
|
+
# Options:
|
48
|
+
# [+name+]
|
49
|
+
# The name of the block being defined (either a string or a symbol)
|
50
|
+
# [+options+]
|
51
|
+
# The default options for the block definition. Any or all of these options may be overrideen by
|
52
|
+
# whomever calls "blocks.render" on this block.
|
53
|
+
# [+block+]
|
54
|
+
# The block that is to be rendered when "blocks.render" is called for this block.
|
55
|
+
def define(name, options={}, &block)
|
56
|
+
collection = options.delete(:collection)
|
57
|
+
|
58
|
+
if collection
|
59
|
+
collection.each do |object|
|
60
|
+
define(evaluated_proc(name, object, options), options, &block)
|
61
|
+
end
|
62
|
+
else
|
63
|
+
self.define_block_container(name, options, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# Define a block, replacing an existing block by the same name if it is already defined.
|
70
|
+
# <%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
|
71
|
+
# <%= options[:parameter1] %> and <%= options[:parameter2] %>
|
72
|
+
# <% end %>
|
73
|
+
#
|
74
|
+
# <%= blocks.replace :some_block_name, :parameter3 => "3", :parameter4 => "4" do |options| %>
|
75
|
+
# <%= options[:parameter3] %> and <%= options[:parameter4] %>
|
76
|
+
# <% end %>
|
77
|
+
# Options:
|
78
|
+
# [+name+]
|
79
|
+
# The name of the block being defined (either a string or a symbol)
|
80
|
+
# [+options+]
|
81
|
+
# The default options for the block definition. Any or all of these options may be overrideen by
|
82
|
+
# whomever calls "blocks.render" on this block.
|
83
|
+
# [+block+]
|
84
|
+
# The block that is to be rendered when "blocks.render" is called for this block.
|
85
|
+
def replace(name, options={}, &block)
|
86
|
+
blocks[name.to_sym] = nil
|
87
|
+
self.define_block_container(name, options, &block)
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Render a block, first rendering any "before" blocks, then rendering the block itself, then rendering
|
92
|
+
# any "after" blocks. Additionally, a collection may also be passed in, and Blocks will render
|
93
|
+
# an the block, along with corresponding before and after blocks for each element of the collection.
|
94
|
+
# Blocks will make either two or four different attempts to render the block, depending on how use_partials
|
95
|
+
# is globally set, or an option is passed in to the render call to either use partials or skip partials:
|
96
|
+
# 1) Look for a block that has been defined inline elsewhere, using the blocks.define method:
|
97
|
+
# <% blocks.define :wizard do |options| %>
|
98
|
+
# Inline Block Step#<%= options[:step] %>.
|
99
|
+
# <% end %>
|
100
|
+
#
|
101
|
+
# <%= blocks.render :wizard, :step => @step %>
|
102
|
+
# 2) [IF use_partials is globally set to true or passed in as a runtime option,
|
103
|
+
# and skip_partials is not passed in as a runtime option]
|
104
|
+
# Look for a partial within the current controller's view directory:
|
105
|
+
# <%= blocks.render :wizard, :step => @step %>
|
106
|
+
#
|
107
|
+
# <!-- In /app/views/pages/_wizard.html.erb (assuming it is the pages controller running): -->
|
108
|
+
# Controller-specific Block Step# <%= step %>.
|
109
|
+
# 3) [IF use_partials is globally set to true or passed in as a runtime option,
|
110
|
+
# and skip_partials is not passed in as a runtime option]
|
111
|
+
# Look for a partial with the global blocks view directory (by default /app/views/blocks/):
|
112
|
+
# <%= blocks.render :wizard, :step => @step %>
|
113
|
+
#
|
114
|
+
# <!-- In /app/views/blocks/_wizard.html.erb: -->
|
115
|
+
# Global Block Step#<%= step %>.
|
116
|
+
# 4) Render the default implementation for the block if provided to the blocks.render call:
|
117
|
+
# <%= blocks.render :wizard, :step => @step do |options| do %>
|
118
|
+
# Default Implementation Block Step#<%= options %>.
|
119
|
+
# <% end %>
|
120
|
+
# Options:
|
121
|
+
# [+name_or_container+]
|
122
|
+
# The name of the block to render (either a string or a symbol)
|
123
|
+
# [+*args+]
|
124
|
+
# Any arguments to pass to the block to be rendered (and also to be passed to any "before" and "after" blocks).
|
125
|
+
# The last argument in the list can be a hash and can include the following special options:
|
126
|
+
# [:collection]
|
127
|
+
# The collection of elements to render blocks for
|
128
|
+
# [:as]
|
129
|
+
# The variable name to assign the current element in the collection being rendered over
|
130
|
+
# [:surrounding_tag]
|
131
|
+
# The content tag to render around a block, which might be particularly useful when rendering a collection of blocks,
|
132
|
+
# such as for a list or table
|
133
|
+
# [:surrounding_tag_html]
|
134
|
+
# The attributes to be applied to the HTML content tag, such as styling or special properties. Please note, any Procs passed
|
135
|
+
# in will automatically be evaluated (For example: :class => lambda { cycle("even", "odd") })
|
136
|
+
# [:use_partials]
|
137
|
+
# Overrides the globally defined use_partials and tells Blocks to render partials in trying to render a block
|
138
|
+
# [:skip_partials]
|
139
|
+
# Overrides the globally defined use_partials and tells Blocks to not render any partials in trying to render a block
|
140
|
+
# [+block+]
|
141
|
+
# The default block to render if no such block block that is to be rendered when "blocks.render" is called for this block.
|
142
|
+
def render(name_or_container, *args, &block)
|
143
|
+
options = args.extract_options!
|
144
|
+
collection = options.delete(:collection)
|
145
|
+
|
146
|
+
buffer = ActiveSupport::SafeBuffer.new
|
147
|
+
|
148
|
+
if collection
|
149
|
+
as = options.delete(:as)
|
150
|
+
|
151
|
+
collection.each do |object|
|
152
|
+
cloned_args = args.clone
|
153
|
+
cloned_args.unshift(object)
|
154
|
+
cloned_options = options.clone
|
155
|
+
cloned_options = cloned_options.merge(object.options) if object.is_a?(Blocks::Container)
|
156
|
+
cloned_args.push(cloned_options)
|
157
|
+
|
158
|
+
block_name = evaluated_proc(name_or_container, *cloned_args)
|
159
|
+
as_name = (as.presence || block_name).to_sym
|
160
|
+
cloned_options[as_name] = object
|
161
|
+
|
162
|
+
buffer << render(block_name, *cloned_args, &block)
|
163
|
+
end
|
164
|
+
else
|
165
|
+
surrounding_tag = options.delete(:surrounding_tag)
|
166
|
+
surrounding_tag_html = options.delete(:surrounding_tag_html)
|
167
|
+
|
168
|
+
args.push(options)
|
169
|
+
|
170
|
+
if surrounding_tag_surrounds_before_and_after_blocks
|
171
|
+
buffer << content_tag(surrounding_tag, surrounding_tag_html, *args) do
|
172
|
+
temp_buffer = ActiveSupport::SafeBuffer.new
|
173
|
+
temp_buffer << render_before_blocks(name_or_container, *args)
|
174
|
+
temp_buffer << render_block_with_around_blocks(name_or_container, *args, &block)
|
175
|
+
temp_buffer << render_after_blocks(name_or_container, *args)
|
176
|
+
end
|
177
|
+
else
|
178
|
+
buffer << render_before_blocks(name_or_container, *args)
|
179
|
+
buffer << content_tag(surrounding_tag, surrounding_tag_html, *args) do
|
180
|
+
render_block_with_around_blocks(name_or_container, *args, &block)
|
181
|
+
end
|
182
|
+
buffer << render_after_blocks(name_or_container, *args)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
buffer
|
187
|
+
end
|
188
|
+
alias use render
|
189
|
+
|
190
|
+
# Render a block, first rendering any "before" blocks, then rendering the block itself, then rendering
|
191
|
+
# any "after" blocks. Additionally, a collection may also be passed in, and Blocks will render
|
192
|
+
# an the block, along with corresponding before and after blocks for each element of the collection.
|
193
|
+
# Blocks will make two different attempts to render block:
|
194
|
+
# 1) Look for a block that has been defined inline elsewhere, using the blocks.define method:
|
195
|
+
# <% blocks.define :wizard do |options| %>
|
196
|
+
# Inline Block Step#<%= options[:step] %>.
|
197
|
+
# <% end %>
|
198
|
+
#
|
199
|
+
# <%= blocks.render :wizard, :step => @step %>
|
200
|
+
# 2) Render the default implementation for the block if provided to the blocks.render call:
|
201
|
+
# <%= blocks.render :wizard, :step => @step do |options| do %>
|
202
|
+
# Default Implementation Block Step#<%= options %>.
|
203
|
+
# <% end %>
|
204
|
+
# Options:
|
205
|
+
# [+name_or_container+]
|
206
|
+
# The name of the block to render (either a string or a symbol)
|
207
|
+
# [+*args+]
|
208
|
+
# Any arguments to pass to the block to be rendered (and also to be passed to any "before" and "after" blocks).
|
209
|
+
# The last argument in the list can be a hash and can include the following special options:
|
210
|
+
# [:collection]
|
211
|
+
# The collection of elements to render blocks for
|
212
|
+
# [:as]
|
213
|
+
# The variable name to assign the current element in the collection being rendered over
|
214
|
+
# [:surrounding_tag]
|
215
|
+
# The content tag to render around a block, which might be particularly useful when rendering a collection of blocks,
|
216
|
+
# such as for a list or table
|
217
|
+
# [:surrounding_tag_html]
|
218
|
+
# The attributes to be applied to the HTML content tag, such as styling or special properties. Please note, any Procs passed
|
219
|
+
# in will automatically be evaluated (For example: :class => lambda { cycle("even", "odd") })
|
220
|
+
# [+block+]
|
221
|
+
# The default block to render if no such block block that is to be rendered when "blocks.render" is called for this block.
|
222
|
+
def render_without_partials(name_or_container, *args, &block)
|
223
|
+
options = args.extract_options!
|
224
|
+
options[:skip_partials] = true
|
225
|
+
args.push(options)
|
226
|
+
render(name_or_container, *args, &block)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Render a block, first rendering any "before" blocks, then rendering the block itself, then rendering
|
230
|
+
# any "after" blocks. Additionally, a collection may also be passed in, and Blocks will render
|
231
|
+
# an the block, along with corresponding before and after blocks for each element of the collection.
|
232
|
+
# Blocks will make four different attempts to render block:
|
233
|
+
# 1) Look for a block that has been defined inline elsewhere, using the blocks.define method:
|
234
|
+
# <% blocks.define :wizard do |options| %>
|
235
|
+
# Inline Block Step#<%= options[:step] %>.
|
236
|
+
# <% end %>
|
237
|
+
#
|
238
|
+
# <%= blocks.render :wizard, :step => @step %>
|
239
|
+
# 2) Look for a partial within the current controller's view directory:
|
240
|
+
# <%= blocks.render :wizard, :step => @step %>
|
241
|
+
#
|
242
|
+
# <!-- In /app/views/pages/_wizard.html.erb (assuming it is the pages controller running): -->
|
243
|
+
# Controller-specific Block Step# <%= step %>.
|
244
|
+
# 3) Look for a partial with the global blocks view directory (by default /app/views/blocks/):
|
245
|
+
# <%= blocks.render :wizard, :step => @step %>
|
246
|
+
#
|
247
|
+
# <!-- In /app/views/blocks/_wizard.html.erb: -->
|
248
|
+
# Global Block Step#<%= step %>.
|
249
|
+
# 4) Render the default implementation for the block if provided to the blocks.render call:
|
250
|
+
# <%= blocks.render :wizard, :step => @step do |options| do %>
|
251
|
+
# Default Implementation Block Step#<%= options %>.
|
252
|
+
# <% end %>
|
253
|
+
# Options:
|
254
|
+
# [+name_or_container+]
|
255
|
+
# The name of the block to render (either a string or a symbol)
|
256
|
+
# [+*args+]
|
257
|
+
# Any arguments to pass to the block to be rendered (and also to be passed to any "before" and "after" blocks).
|
258
|
+
# The last argument in the list can be a hash and can include the following special options:
|
259
|
+
# [:collection]
|
260
|
+
# The collection of elements to render blocks for
|
261
|
+
# [:as]
|
262
|
+
# The variable name to assign the current element in the collection being rendered over
|
263
|
+
# [:surrounding_tag]
|
264
|
+
# The content tag to render around a block, which might be particularly useful when rendering a collection of blocks,
|
265
|
+
# such as for a list or table
|
266
|
+
# [:surrounding_tag_html]
|
267
|
+
# The attributes to be applied to the HTML content tag, such as styling or special properties. Please note, any Procs passed
|
268
|
+
# in will automatically be evaluated (For example: :class => lambda { cycle("even", "odd") })
|
269
|
+
# [+block+]
|
270
|
+
# The default block to render if no such block block that is to be rendered when "blocks.render" is called for this block.
|
271
|
+
def render_with_partials(name_or_container, *args, &block)
|
272
|
+
options = args.extract_options!
|
273
|
+
options[:use_partials] = true
|
274
|
+
args.push(options)
|
275
|
+
render(name_or_container, *args, &block)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Queue a block for later rendering, such as within a template.
|
279
|
+
# <%= Blocks::Base.new(self).render_template("shared/wizard") do |blocks| %>
|
280
|
+
# <% blocks.queue :step1 %>
|
281
|
+
# <% blocks.queue :step2 do %>
|
282
|
+
# My overridden Step 2 |
|
283
|
+
# <% end %>
|
284
|
+
# <% blocks.queue :step3 %>
|
285
|
+
# <% blocks.queue do %>
|
286
|
+
# | Anonymous Step 4
|
287
|
+
# <% end %>
|
288
|
+
# <% end %>
|
289
|
+
#
|
290
|
+
# <!-- In /app/views/shared/wizard -->
|
291
|
+
# <% blocks.define :step1 do %>
|
292
|
+
# Step 1 |
|
293
|
+
# <% end %>
|
294
|
+
#
|
295
|
+
# <% blocks.define :step2 do %>
|
296
|
+
# Step 2 |
|
297
|
+
# <% end %>
|
298
|
+
#
|
299
|
+
# <% blocks.define :step3 do %>
|
300
|
+
# Step 3
|
301
|
+
# <% end %>
|
302
|
+
#
|
303
|
+
# <% blocks.queued_blocks.each do |block| %>
|
304
|
+
# <%= blocks.render block %>
|
305
|
+
# <% end %>
|
306
|
+
#
|
307
|
+
# <!-- Will render: Step 1 | My overridden Step 2 | Step 3 | Anonymous Step 4-->
|
308
|
+
# Options:
|
309
|
+
# [+*args+]
|
310
|
+
# The options to pass in when this block is rendered. These will override any options provided to the actual block
|
311
|
+
# definition. Any or all of these options may be overriden by whoever calls "blocks.render" on this block.
|
312
|
+
# Usually the first of these args will be the name of the block being queued (either a string or a symbol)
|
313
|
+
# [+block+]
|
314
|
+
# The optional block definition to render when the queued block is rendered
|
315
|
+
def queue(*args, &block)
|
316
|
+
self.queued_blocks << self.define_block_container(*args, &block)
|
317
|
+
nil
|
318
|
+
end
|
319
|
+
|
320
|
+
# Render a partial, treating it as a template, and any code in the block argument will impact how the template renders
|
321
|
+
# <%= Blocks::Base.new(self).render_template("shared/wizard") do |blocks| %>
|
322
|
+
# <% blocks.queue :step1 %>
|
323
|
+
# <% blocks.queue :step2 do %>
|
324
|
+
# My overridden Step 2 |
|
325
|
+
# <% end %>
|
326
|
+
# <% blocks.queue :step3 %>
|
327
|
+
# <% blocks.queue do %>
|
328
|
+
# | Anonymous Step 4
|
329
|
+
# <% end %>
|
330
|
+
# <% end %>
|
331
|
+
#
|
332
|
+
# <!-- In /app/views/shared/wizard -->
|
333
|
+
# <% blocks.define :step1 do %>
|
334
|
+
# Step 1 |
|
335
|
+
# <% end %>
|
336
|
+
#
|
337
|
+
# <% blocks.define :step2 do %>
|
338
|
+
# Step 2 |
|
339
|
+
# <% end %>
|
340
|
+
#
|
341
|
+
# <% blocks.define :step3 do %>
|
342
|
+
# Step 3
|
343
|
+
# <% end %>
|
344
|
+
#
|
345
|
+
# <% blocks.queued_blocks.each do |block| %>
|
346
|
+
# <%= blocks.render block %>
|
347
|
+
# <% end %>
|
348
|
+
#
|
349
|
+
# <!-- Will render: Step 1 | My overridden Step 2 | Step 3 | Anonymous Step 4-->
|
350
|
+
# Options:
|
351
|
+
# [+partial+]
|
352
|
+
# The partial to render as a template
|
353
|
+
# [+block+]
|
354
|
+
# An optional block with code that affects how the template renders
|
355
|
+
def render_template(partial, &block)
|
356
|
+
render_options = global_options.clone
|
357
|
+
render_options[self.variable] = self
|
358
|
+
render_options[:captured_block] = view.capture(self, &block) if block_given?
|
359
|
+
|
360
|
+
view.render partial, render_options
|
361
|
+
end
|
362
|
+
|
363
|
+
# Add a block to render before another block. This before block will be put into an array so that multiple
|
364
|
+
# before blocks may be queued. They will render in the order in which they are declared when the
|
365
|
+
# "blocks#render" method is called. Any options specified to the before block will override any options
|
366
|
+
# specified in the block definition.
|
367
|
+
# <% blocks.define :wizard, :option1 => 1, :option2 => 2 do |options| %>
|
368
|
+
# Step 2 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
|
369
|
+
# <% end %>
|
370
|
+
#
|
371
|
+
# <% blocks.before :wizard, :option1 => 3 do
|
372
|
+
# Step 0 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
|
373
|
+
# <% end %>
|
374
|
+
#
|
375
|
+
# <% blocks.before :wizard, :option2 => 4 do
|
376
|
+
# Step 1 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
|
377
|
+
# <% end %>
|
378
|
+
#
|
379
|
+
# <%= blocks.render :wizard %>
|
380
|
+
#
|
381
|
+
# <!-- Will render:
|
382
|
+
# Step 0 (:option1 => 3, :option2 => 2)<br />
|
383
|
+
# Step 1 (:option1 => 1, :option2 => 4)<br />
|
384
|
+
# Step 2 (:option1 => 1, :option2 => 2)<br />
|
385
|
+
# -->
|
386
|
+
#
|
387
|
+
# <%= blocks.render :wizard, :step => @step %>
|
388
|
+
# Options:
|
389
|
+
# [+name+]
|
390
|
+
# The name of the block to render this code before when that block is rendered
|
391
|
+
# [+options+]
|
392
|
+
# Any options to specify to the before block when it renders. These will override any options
|
393
|
+
# specified when the block was defined.
|
394
|
+
# [+block+]
|
395
|
+
# The block of code to render before another block
|
396
|
+
def before(name, options={}, &block)
|
397
|
+
self.queue_block_container("before_#{name.to_s}", options, &block)
|
398
|
+
nil
|
399
|
+
end
|
400
|
+
alias prepend before
|
401
|
+
|
402
|
+
# Add a block to render after another block. This after block will be put into an array so that multiple
|
403
|
+
# after blocks may be queued. They will render in the order in which they are declared when the
|
404
|
+
# "blocks#render" method is called. Any options specified to the after block will override any options
|
405
|
+
# specified in the block definition.
|
406
|
+
# <% blocks.define :wizard, :option1 => 1, :option2 => 2 do |options| %>
|
407
|
+
# Step 2 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
|
408
|
+
# <% end %>
|
409
|
+
#
|
410
|
+
# <% blocks.after :wizard, :option1 => 3 do
|
411
|
+
# Step 3 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
|
412
|
+
# <% end %>
|
413
|
+
#
|
414
|
+
# <% blocks.after :wizard, :option2 => 4 do
|
415
|
+
# Step 4 (:option1 => <%= options[option1] %>, :option2 => <%= options[option2] %>)<br />
|
416
|
+
# <% end %>
|
417
|
+
#
|
418
|
+
# <%= blocks.render :wizard %>
|
419
|
+
#
|
420
|
+
# <!-- Will render:
|
421
|
+
# Step 2 (:option1 => 1, :option2 => 2)<br />
|
422
|
+
# Step 3 (:option1 => 3, :option2 => 2)<br />
|
423
|
+
# Step 4 (:option1 => 1, :option2 => 4)<br />
|
424
|
+
# -->
|
425
|
+
#
|
426
|
+
# <%= blocks.render :wizard, :step => @step %>
|
427
|
+
# Options:
|
428
|
+
# [+name+]
|
429
|
+
# The name of the block to render this code after when that block is rendered
|
430
|
+
# [+options+]
|
431
|
+
# Any options to specify to the after block when it renders. These will override any options
|
432
|
+
# specified when the block was defined.
|
433
|
+
# [+block+]
|
434
|
+
# The block of code to render after another block
|
435
|
+
def after(name, options={}, &block)
|
436
|
+
self.queue_block_container("after_#{name.to_s}", options, &block)
|
437
|
+
nil
|
438
|
+
end
|
439
|
+
alias append after
|
440
|
+
alias for after
|
441
|
+
|
442
|
+
# Add a block to render around another block. This around block will be put into an array so that multiple
|
443
|
+
# around blocks may be queued. They will render in the order in which they are declared when the
|
444
|
+
# "blocks#render" method is called, with the last declared around block being rendered as the outer-most code, and
|
445
|
+
# the first declared around block rendered as the inner-most code. Any options specified to the after block will override any options
|
446
|
+
# specified in the block definition. The user of an around block must declare a block with at least one parameter and
|
447
|
+
# should invoke the #call method on that argument.
|
448
|
+
#
|
449
|
+
# <% blocks.define :my_block do %>
|
450
|
+
# test
|
451
|
+
# <% end %>
|
452
|
+
#
|
453
|
+
# <% blocks.around :my_block do |content_block| %>
|
454
|
+
# <h1>
|
455
|
+
# <%= content_block.call %>
|
456
|
+
# </h1>
|
457
|
+
# <% end %>
|
458
|
+
#
|
459
|
+
# <% blocks.around :my_block do |content_block| %>
|
460
|
+
# <span style="color:red">
|
461
|
+
# <%= content_block.call %>
|
462
|
+
# </span>
|
463
|
+
# <% end %>
|
464
|
+
#
|
465
|
+
# <%= blocks.render :my_block %>
|
466
|
+
#
|
467
|
+
# <!-- Will render:
|
468
|
+
# <h1>
|
469
|
+
# <span style="color:red">
|
470
|
+
# test
|
471
|
+
# </span>
|
472
|
+
# </h1>
|
473
|
+
#
|
474
|
+
# Options:
|
475
|
+
# [+name+]
|
476
|
+
# The name of the block to render this code around when that block is rendered
|
477
|
+
# [+options+]
|
478
|
+
# Any options to specify to the around block when it renders. These will override any options
|
479
|
+
# specified when the block was defined.
|
480
|
+
# [+block+]
|
481
|
+
# The block of code to render after another block
|
482
|
+
def around(name, options={}, &block)
|
483
|
+
self.queue_block_container("around_#{name.to_s}", options, &block)
|
484
|
+
nil
|
485
|
+
end
|
486
|
+
|
487
|
+
def evaluated_procs(*args)
|
488
|
+
options = args.shift.presence || {}
|
489
|
+
if options.is_a?(Proc)
|
490
|
+
evaluated_proc(options, *args)
|
491
|
+
else
|
492
|
+
options.inject({}) { |hash, (k, v)| hash[k] = evaluated_proc(v, *args); hash}
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def evaluated_proc(*args)
|
497
|
+
return nil unless args.present?
|
498
|
+
v = args.shift
|
499
|
+
v.is_a?(Proc) ? v.call(*(args[0, v.arity])) : v
|
500
|
+
end
|
501
|
+
|
502
|
+
protected
|
503
|
+
|
504
|
+
# If a method is missing, we'll assume the user is starting a new block group by that missing method name
|
505
|
+
def method_missing(m, *args, &block)
|
506
|
+
options = args.extract_options!
|
507
|
+
|
508
|
+
# If the specified block group has already been defined, it is simply returned here for iteration.
|
509
|
+
# It will consist of all the blocks used in this block group that have yet to be rendered,
|
510
|
+
# as the call for their use occurred before the template was rendered (where their definitions likely occurred)
|
511
|
+
return self.block_groups[m] unless self.block_groups[m].nil?
|
512
|
+
|
513
|
+
# Allows for nested block groups, store the current block positions array and start a new one
|
514
|
+
original_queued_blocks = self.queued_blocks
|
515
|
+
self.queued_blocks = []
|
516
|
+
self.block_groups[m] = self.queued_blocks
|
517
|
+
|
518
|
+
# Capture the contents of the block group (this will only capture block definitions and block renders; it will ignore anything else)
|
519
|
+
view.capture(global_options.merge(options), &block) if block_given?
|
520
|
+
|
521
|
+
# restore the original block positions array
|
522
|
+
self.queued_blocks = original_queued_blocks
|
523
|
+
nil
|
524
|
+
end
|
525
|
+
|
526
|
+
def initialize(view, options={})
|
527
|
+
self.template_folder = options[:template_folder] ? options.delete(:template_folder) : Blocks.template_folder
|
528
|
+
self.variable = (options[:variable] ? options.delete(:variable) : :blocks).to_sym
|
529
|
+
self.view = view
|
530
|
+
self.global_options = options
|
531
|
+
self.queued_blocks = []
|
532
|
+
self.blocks = {}
|
533
|
+
self.anonymous_block_number = 0
|
534
|
+
self.block_groups = {}
|
535
|
+
self.use_partials = options[:use_partials].nil? ? Blocks.use_partials : options.delete(:use_partials)
|
536
|
+
self.surrounding_tag_surrounds_before_and_after_blocks = options[:surrounding_tag_surrounds_before_and_after_blocks].nil? ? Blocks.surrounding_tag_surrounds_before_and_after_blocks : options.delete(:surrounding_tag_surrounds_before_and_after_blocks)
|
537
|
+
end
|
538
|
+
|
539
|
+
# Return a unique name for an anonymously defined block (i.e. a block that has not been given a name)
|
540
|
+
def anonymous_block_name
|
541
|
+
self.anonymous_block_number += 1
|
542
|
+
"block_#{anonymous_block_number}"
|
543
|
+
end
|
544
|
+
|
545
|
+
def render_block_with_around_blocks(name_or_container, *args, &block)
|
546
|
+
name = name_or_container.is_a?(Blocks::Container) ? name_or_container.name.to_sym : name_or_container.to_sym
|
547
|
+
around_name = "around_#{name.to_s}".to_sym
|
548
|
+
|
549
|
+
around_blocks = blocks[around_name].present? ? blocks[around_name].clone : []
|
550
|
+
|
551
|
+
content_block = Proc.new do
|
552
|
+
block_container = around_blocks.shift
|
553
|
+
if block_container
|
554
|
+
view.capture(content_block, *(args[0, block_container.block.arity - 1]), &block_container.block)
|
555
|
+
else
|
556
|
+
render_block(name_or_container, *args, &block)
|
557
|
+
end
|
558
|
+
end
|
559
|
+
content_block.call
|
560
|
+
end
|
561
|
+
|
562
|
+
# Render a block, first trying to find a previously defined block with the same name
|
563
|
+
def render_block(name_or_container, *args, &block)
|
564
|
+
options = args.extract_options!
|
565
|
+
|
566
|
+
buffer = ActiveSupport::SafeBuffer.new
|
567
|
+
|
568
|
+
block_options = {}
|
569
|
+
if (name_or_container.is_a?(Blocks::Container))
|
570
|
+
name = name_or_container.name.to_sym
|
571
|
+
block_options = name_or_container.options
|
572
|
+
else
|
573
|
+
name = name_or_container.to_sym
|
574
|
+
end
|
575
|
+
|
576
|
+
if blocks[name]
|
577
|
+
block_container = blocks[name]
|
578
|
+
args.push(global_options.merge(block_container.options).merge(block_options).merge(options))
|
579
|
+
buffer << view.capture(*(args[0, block_container.block.arity]), &block_container.block)
|
580
|
+
elsif (use_partials || options[:use_partials]) && !options[:skip_partials]
|
581
|
+
begin
|
582
|
+
begin
|
583
|
+
buffer << view.render("#{name.to_s}", global_options.merge(block_options).merge(options))
|
584
|
+
rescue ActionView::MissingTemplate
|
585
|
+
buffer << view.render("#{self.template_folder}/#{name.to_s}", global_options.merge(block_options).merge(options))
|
586
|
+
end
|
587
|
+
rescue ActionView::MissingTemplate
|
588
|
+
args.push(global_options.merge(options))
|
589
|
+
buffer << view.capture(*(args[0, block.arity]), &block) if block_given?
|
590
|
+
end
|
591
|
+
else
|
592
|
+
args.push(global_options.merge(options))
|
593
|
+
buffer << view.capture(*(args[0, block.arity]), &block) if block_given?
|
594
|
+
end
|
595
|
+
|
596
|
+
buffer
|
597
|
+
end
|
598
|
+
|
599
|
+
# Render all the before blocks for a partial block
|
600
|
+
def render_before_blocks(name_or_container, *args)
|
601
|
+
render_before_or_after_blocks(name_or_container, "before", *args)
|
602
|
+
end
|
603
|
+
|
604
|
+
# Render all the after blocks for a partial block
|
605
|
+
def render_after_blocks(name_or_container, *args)
|
606
|
+
render_before_or_after_blocks(name_or_container, "after", *args)
|
607
|
+
end
|
608
|
+
|
609
|
+
# Utility method to render either the before or after blocks for a partial block
|
610
|
+
def render_before_or_after_blocks(name_or_container, before_or_after, *args)
|
611
|
+
options = args.extract_options!
|
612
|
+
|
613
|
+
block_options = {}
|
614
|
+
if (name_or_container.is_a?(Blocks::Container))
|
615
|
+
name = name_or_container.name.to_sym
|
616
|
+
block_options = name_or_container.options
|
617
|
+
else
|
618
|
+
name = name_or_container.to_sym
|
619
|
+
block_options = blocks[name].options if blocks[name]
|
620
|
+
end
|
621
|
+
|
622
|
+
before_name = "#{before_or_after}_#{name.to_s}".to_sym
|
623
|
+
buffer = ActiveSupport::SafeBuffer.new
|
624
|
+
|
625
|
+
blocks[before_name].each do |block_container|
|
626
|
+
args_clone = args.clone
|
627
|
+
args_clone.push(global_options.merge(block_options).merge(block_container.options).merge(options))
|
628
|
+
buffer << view.capture(*(args_clone[0, block_container.block.arity]), &block_container.block)
|
629
|
+
end if blocks[before_name].present?
|
630
|
+
|
631
|
+
buffer
|
632
|
+
end
|
633
|
+
|
634
|
+
# Build a Blocks::Container object given the passed in arguments
|
635
|
+
def build_block_container(*args, &block)
|
636
|
+
options = args.extract_options!
|
637
|
+
name = args.first ? args.shift : self.anonymous_block_name
|
638
|
+
block_container = Blocks::Container.new
|
639
|
+
block_container.name = name.to_sym
|
640
|
+
block_container.options = options
|
641
|
+
block_container.block = block
|
642
|
+
block_container
|
643
|
+
end
|
644
|
+
|
645
|
+
# Build a Blocks::Container object and add it to an array of containers matching it's block name
|
646
|
+
# (used only for queuing a collection of before and after blocks for a particular block name)
|
647
|
+
def queue_block_container(*args, &block)
|
648
|
+
block_container = self.build_block_container(*args, &block)
|
649
|
+
if blocks[block_container.name].nil?
|
650
|
+
blocks[block_container.name] = [block_container]
|
651
|
+
else
|
652
|
+
blocks[block_container.name] << block_container
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
# Build a Blocks::Container object and add it to the global hash of blocks if a block by the same
|
657
|
+
# name is not already defined
|
658
|
+
def define_block_container(*args, &block)
|
659
|
+
block_container = self.build_block_container(*args, &block)
|
660
|
+
blocks[block_container.name] = block_container if blocks[block_container.name].nil? && block_given?
|
661
|
+
block_container
|
662
|
+
end
|
663
|
+
|
664
|
+
def content_tag(tag, tag_html, *args, &block)
|
665
|
+
if tag
|
666
|
+
view.content_tag(tag, block.call, evaluated_procs(tag_html, *args))
|
667
|
+
else
|
668
|
+
block.call
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
672
|
+
end
|