building-blocks 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -0,0 +1,241 @@
1
+ = BuildingBlocks
2
+
3
+ BuildingBlocks is an intricate way of rendering blocks of code, while adding several features that go above and beyond what a simple content_for with yield is capable of doing.
4
+
5
+ 1. It provides the ability to pass parameters to a defined block of code (something content_for with yield is incapable of doing).
6
+ 2. It provides "before" and "after" hooks that can render code before and after a specified block of code is rendered (this can be particularly useful when you want to specify a dynamic list of javascript or stylesheet includes after your standard includes).
7
+ 3. It allows the developer to define a block of code as a global partial, a controller-specific partial, or an inline block of code, all with the same syntax usage.
8
+ 4. (Probably the most powerful aspect) It allows the developer to build complex reusable UI components by essentially providing their own DTD (see the separate project {table-for}[https://github.com/hunterae/table-for] for an example of a nice table builder that was created using minimal code by apply BuildingBlocks).
9
+
10
+ == Installation
11
+
12
+ In <b>Rails 3</b>, add this to your Gemfile.
13
+
14
+ gem "building-blocks"
15
+
16
+ == Defining and using blocks
17
+
18
+ The syntax for defining and using blocks is similar to how content_for and yield are used. At its simplest form:
19
+
20
+ <% blocks.define :my_block do %>
21
+ My code to render
22
+ <% end %>
23
+
24
+ <!-- Elsewhere, you can use the block as follows -->
25
+ <%= blocks.use :my_block %>
26
+
27
+ <!-- Will render: My code to render -->
28
+
29
+ == Passing parameters to blocks
30
+
31
+ Parameters may also be passed into defined blocks:
32
+
33
+ <% blocks.define :my_block do |options| %>
34
+ The user of this block passed in "<%= options[:my_parameter] %>" as :my_parameter.
35
+ <% end %>
36
+
37
+ <!-- Elsewhere, you can use the block as follows -->
38
+ <%= blocks.use :my_block, :my_parameter => "The value I'm passing in" %>
39
+
40
+ <!-- Will render: The user of this block passed in "The value I'm passing in" as :my_parameter. -->
41
+
42
+ <!-- If the anticipated parameters are not passed: -->
43
+ <%= blocks.use :my_block %>
44
+
45
+ <!-- Will render: The user of this block passed in "" as :my_parameter. -->
46
+
47
+ The parameters are not required, but unexpected results might occur if the "necessary" parameters are not passed in.
48
+
49
+ == Passing non-hash parameters into defined blocks:
50
+
51
+ <% blocks.define :my_block do |first_parameter, second_parameter, options| %>
52
+ First parameter: <%= first_parameter %>, Second parameter: <%= second_parameter %>, Third parameter: <%= options[:third_parameter] %>
53
+ <% end %>
54
+
55
+ <!-- Elsewhere, you can use the block as follows -->
56
+ <%= blocks.use :my_block, "Value 1", 2, :third_parameter => "Value 3" %>
57
+
58
+ <!-- Will render: First parameter: Value 1, Second parameter: 2, Third parameter: Value 3 -->
59
+
60
+ == Providing default values for parameters to blocks
61
+
62
+ In the last example, the parameter the block was expecting was not passed in. For this reason, it is possible to specify default values for the parameters when you define a block. If parameters are passed in when the block is used, the values passed in override the default values.
63
+
64
+ <% blocks.define :my_block, :parameter1 => "Parameter 1", :parameter2 => "Parameter 2" do |options| %>
65
+ The values specified are :parameter1 = "<%= options[:parameter1] %>", :parameter2 = "<%= options[:parameter2] %>"
66
+ <% end %>
67
+
68
+ <!-- Elsewhere, you can use the block as follows (specifying zero, one, or both of the parameters the block uses) -->
69
+ <%= blocks.use :my_block %><br />
70
+ <%= blocks.use :my_block, :parameter1 => "New Parameter 1" %><br />
71
+ <%= blocks.use :my_block, :parameter2 => "New Parameter 2" %><br />
72
+ <%= blocks.use :my_block, :parameter1 => "New Parameter 1", :parameter2 => "New Parameter 2" %>
73
+
74
+ <!--
75
+ Will render:
76
+ The values specified are :parameter1 = "Parameter 1", :parameter2 = "Parameter 2"
77
+ The values specified are :parameter1 = "New Parameter 1", :parameter2 = "Parameter 2"
78
+ The values specified are :parameter1 = "Parameter 1", :parameter2 = "New Parameter 2"
79
+ The values specified are :parameter1 = "New Parameter 1", :parameter2 = "New Parameter 2"
80
+ -->
81
+
82
+ == Providing a default definition for a block
83
+
84
+ What happens if you attempt to "use" a block that hasn't been "define"d? Nothing will get rendered.
85
+
86
+ However, you may want to provide a default definition for a block to "use" if such a block was never "define"d. You can do this as follows:
87
+
88
+ <%= blocks.use :my_block, :my_parameter_1 => "Parameter 1" do %>
89
+ This is my default definition of :my_block.
90
+ <% end %>
91
+
92
+ In this case, BuildingBlocks will see if any block by the name :my_block has ever been defined. When it doesn't find one, it will simply render the default definition and you will see:
93
+ This is my default definition of :my_block.
94
+
95
+ If however, you have defined :my_block elsewhere, it would have used that definition:
96
+
97
+ <% blocks.define :my_block do |options| %>
98
+ Some other definition of :my_block with :my_parameter_1 set to "<%= options[:my_parameter_1] %>"
99
+ <% end %>
100
+
101
+ <!-- Elsewhere, you can use the block as follows -->
102
+ <%= blocks.use :my_block, :my_parameter_1 => "Parameter 1" do %>
103
+ This is my default definition of :my_block.
104
+ <% end %>
105
+
106
+ <!-- Will render: Some other definition of :my_block with :my_parameter_1 set to "Parameter 1" -->
107
+ <!-- (since the block was defined, i.e. the default definition is not needed) -->
108
+
109
+ == Using "before" and "after filters"
110
+
111
+ "Before" and "After" hooks render code before and after the code produced by a "blocks.use" call. A practical example of this would be adding view-specific javascript and stylesheet includes to a global layout file.
112
+
113
+ In your application.html layout file, you might use this as follows:
114
+
115
+ <html>
116
+ <head>
117
+ <%= blocks.use :includes do %>
118
+ <%= blocks.use :stylesheets do %>
119
+ <%= stylesheet_link_tag "jquery" %>
120
+ <% end %>
121
+ <%= blocks.use :javscripts do %>
122
+ <%= javascript_include_tag "jquery" %>
123
+ <% end %>
124
+ <% end %>
125
+ </head>
126
+ <body>
127
+ <%= yield %>
128
+ </body>
129
+ </html>
130
+
131
+ Then, in a specific view that is rendered using this layout, you can add stylesheets before or after the list of stylesheets includes, before or after the list of javascript includes, or before or after the entire list of stylesheet and javascript includes. For example, index.html.erb might add in more stylesheets and javascripts:
132
+
133
+ <% blocks.before :includes do %>
134
+ <%= stylesheet_link_tag "first_overall_stylesheet" %>
135
+ <% end %>
136
+
137
+ <% blocks.after :includes do %>
138
+ <%= stylesheet_link_tag "last_overall_stylesheet" %>
139
+ <% end %>
140
+
141
+ <% blocks.before :stylesheets do %>
142
+ <%= stylesheet_link_tag "stylesheet_before_jquery" %>
143
+ <% end %>
144
+
145
+ <% blocks.after :stylesheets do %>
146
+ <%= stylesheet_link_tag "stylesheet_after_jquery" %>
147
+ <% end %>
148
+
149
+ <% blocks.before :javascripts do %>
150
+ <%= javascript_include_tag "javascript_before_jquery" %>
151
+ <% end %>
152
+
153
+ <% blocks.after :javascripts do %>
154
+ <%= javascript_include_tag "stylesheet_before_jquery" %>
155
+ <% end %>
156
+
157
+ <!--
158
+ When index.html.erb is rendered, it will output:
159
+ <html>
160
+ <head>
161
+ <link href="/stylesheets/first_overall_stylesheet.css" media="screen" rel="stylesheet" type="text/css" />
162
+ <link href="/stylesheets/stylesheet_before_jquery.css" media="screen" rel="stylesheet" type="text/css" />
163
+ <link href="/stylesheets/jquery.css" media="screen" rel="stylesheet" type="text/css" />
164
+ <link href="/stylesheets/stylesheet_after_jquery.css" media="screen" rel="stylesheet" type="text/css" />
165
+ <script src="/javascripts/javascript_before_jquery.js" type="text/javascript"></script>
166
+ <script src="/javascripts/jquery.js" type="text/javascript"></script>
167
+ <script src="/javascripts/javascript_after_jquery.js" type="text/javascript"></script>
168
+ <link href="/stylesheets/last_overall_stylesheet.css" media="screen" rel="stylesheet" type="text/css" />
169
+ </head>
170
+ <body>
171
+ </body>
172
+ </html>
173
+ -->
174
+ (An alternative syntax to "blocks.before" and "blocks.after" would be, respectively, "blocks.prepend" and "blocks.append")
175
+
176
+ == Blocks as Partials
177
+
178
+ Using exactly the same syntax for "using" blocks, one can put the code to be rendered in it's own separate file (in a partial). When "blocks.use :some_block" is called, the system will first look for a block defined inline (i.e. one that has been defined using "blocks.define :some_block"). Failing to find that, it will see if a default implementation has been provided for the block and render it if one has been specified. Failing to find that, it will look for a partial by the same name in your current controller's view directory. And failing to find that partial, it will look for a partial in the global blocks' directory (by default, /app/views/blocks). Any parameters passed in as a hash will be initialized in the partial as local variables.
179
+
180
+ As an example, consider the following code, running in a view for PagesController:
181
+
182
+ <%= blocks.use :wizard, :step => @step %>
183
+
184
+ <!-- 1) Check and see if there was a block defined called "wizard" somewhere prior to its use... No? then... -->
185
+ <!-- 2) Check and see if there is a default definition provided for "wizard", i.e. specified in the "blocks.use" call... No? Then... -->
186
+ <!-- 3) Check and see if there is a controller-specific partial /app/views/pages/wizard.html.erb. No? Then... -->
187
+ <!-- 4) Check and see if there is a global partial /app/views/blocks/wizard.html.erb. No? Then render nothing. -->
188
+
189
+ Let's look at each example individually, written in the order that BuildingBlocks attempts to render them:
190
+
191
+ 1. Inline definition of a block:
192
+ <% blocks.define :wizard do |options| %>
193
+ Inline Block Step#<%= options[:step] %>.
194
+ <% end %>
195
+
196
+ <!-- Elsewhere, you can use the block as follows -->
197
+ <%= blocks.use :wizard, :step => @step %>
198
+ 2. Default implementation of a block:
199
+ <%= blocks.use :wizard, :step => @step do |options| do %>
200
+ Default Implementation Block Step#<%= options %>.
201
+ <% end %>
202
+ 3. Controller-specific partial:
203
+ <%= blocks.use :wizard, :step => @step %>
204
+
205
+ <!-- In /app/views/pages/_wizard.html.erb: -->
206
+ Controller-specific Block Step# <%= step %>.
207
+ 4. Global partial:
208
+ <%= blocks.use :wizard, :step => @step %>
209
+
210
+ <!-- In /app/views/blocks/_wizard.html.erb: -->
211
+ Global Block Step#<%= step %>.
212
+
213
+ == Overall Render Order
214
+
215
+ Putting all the pieces together from the previous examples, here is what BuildingBlock is doing when a block is rendered:
216
+ link:/hunterae/building-blocks/raw/master/blocks_render_order.png
217
+
218
+ == Templating
219
+
220
+ The most advanced feature of BuildingBlocks is the ability to utilize it for templating and writing your own DTD specifications for the components you write.
221
+
222
+ As an example, consider {table-for}[https://github.com/hunterae/table-for], a library that was written with minimal codes that provides its user with a very nice, easy-to-use table builder. A sample usage might look something like:
223
+
224
+ <%= table_for @users do |table| %>
225
+ <% table.column :name do |user| %>
226
+ <%= "#{user.first_name} #{user.last_name}" %>
227
+ <% end %>
228
+ <% table.column :email %>
229
+ <% end %>
230
+
231
+ MORE EXPLANATION TO COME
232
+
233
+ == MORE COMING SOON...
234
+
235
+ == Questions or Problems?
236
+
237
+ If you have any issues with BuildingBlocks which you cannot find the solution to in the documentation, please add an {issue on GitHub}[https://github.com/hunterae/building-blocks/issues] or fork the project and send a pull request.
238
+
239
+ == Special Thanks
240
+
241
+ Thanks to {Todd Fisher}[https://github.com/taf2] of LivingSocial for implementation help and setup of gem and {Jon Phillips}[https://github.com/elguapo1611] of LivingSocial for suggestions and use case help.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.7
1
+ 0.0.8
@@ -2,7 +2,7 @@ require "action_view"
2
2
 
3
3
  $LOAD_PATH.unshift(File.dirname(__FILE__))
4
4
 
5
- require "building_blocks/building_blocks"
5
+ require "building_blocks/base"
6
6
  require "building_blocks/container"
7
7
  require "building_blocks/helper_methods"
8
8
 
@@ -1,24 +1,22 @@
1
1
  module BuildingBlocks
2
2
  class Base
3
3
  attr_accessor :view
4
-
5
- attr_accessor :blocks
6
-
4
+
5
+ attr_accessor :blocks
6
+
7
7
  attr_accessor :block
8
-
8
+
9
9
  # Array of BuildingBlocks::Container objects, storing the order of blocks as they were used
10
- attr_accessor :block_positions
11
-
10
+ attr_accessor :queued_blocks
11
+
12
12
  # counter, used to give unnamed blocks a unique name
13
13
  attr_accessor :anonymous_block_number
14
-
15
- attr_accessor :start_rendering_blocks
16
-
14
+
17
15
  attr_accessor :block_groups
18
16
 
19
17
  # These are the options that are passed into the initalize method
20
18
  attr_accessor :global_options
21
-
19
+
22
20
  # Checks if a particular block has been defined within the current block scope.
23
21
  # <%= blocks.defined? :some_block_name %>
24
22
  # Options:
@@ -27,40 +25,30 @@ module BuildingBlocks
27
25
  def defined?(name)
28
26
  !blocks[name.to_sym].nil?
29
27
  end
30
-
28
+
31
29
  # Define a block, unless a block by the same name is already defined.
32
30
  # <%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
33
31
  # <%= options[:parameter1] %> and <%= options[:parameter2] %>
34
32
  # <% end %>
35
- #
33
+ #
36
34
  # Options:
37
35
  # [+name+]
38
36
  # The name of the block being defined (either a string or a symbol)
39
37
  # [+options+]
40
- # The default options for the block definition. Any or all of these options may be overrideen by
38
+ # The default options for the block definition. Any or all of these options may be overrideen by
41
39
  # whomever calls "blocks.use" on this block.
42
40
  # [+block+]
43
41
  # The block that is to be rendered when "blocks.use" is called for this block.
44
42
  def define(name, options={}, &block)
45
- # Check if a block by this name is already defined.
46
- if blocks[name.to_sym].nil?
47
- # Store the attributes of the defined block in a container for later use
48
- block_container = BuildingBlocks::Container.new
49
- block_container.name = name
50
- block_container.options = options
51
- block_container.block = block
52
-
53
- blocks[name.to_sym] = block_container
54
- end
55
-
43
+ self.define_block_container(name, options, &block)
56
44
  nil
57
45
  end
58
-
46
+
59
47
  # Define a block, replacing an existing block by the same name if it is already defined.
60
48
  # <%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
61
49
  # <%= options[:parameter1] %> and <%= options[:parameter2] %>
62
50
  # <% end %>
63
- #
51
+ #
64
52
  # <%= blocks.replace :some_block_name, :parameter3 => "3", :parameter4 => "4" do |options| %>
65
53
  # <%= options[:parameter3] %> and <%= options[:parameter4] %>
66
54
  # <% end %>
@@ -68,58 +56,53 @@ module BuildingBlocks
68
56
  # [+name+]
69
57
  # The name of the block being defined (either a string or a symbol)
70
58
  # [+options+]
71
- # The default options for the block definition. Any or all of these options may be overrideen by
59
+ # The default options for the block definition. Any or all of these options may be overrideen by
72
60
  # whomever calls "blocks.use" on this block.
73
61
  # [+block+]
74
62
  # The block that is to be rendered when "blocks.use" is called for this block.
75
63
  def replace(name, options={}, &block)
76
64
  blocks[name.to_sym] = nil
77
- define(name, options, &block)
65
+ self.define_block_container(name, options, &block)
66
+ nil
78
67
  end
79
-
68
+
80
69
  def use(*args, &block)
81
- options = args.extract_options!
82
-
70
+ options = args.extract_options!
71
+
83
72
  # If the user doesn't specify a block name, we generate an anonymous block name to assure other
84
73
  # anonymous blocks don't override its definition
85
74
  name = args.first ? args.shift : self.anonymous_block_name
86
-
87
- block_container = BuildingBlocks::Container.new
88
- block_container.name = name
89
- block_container.options = options
90
- block_container.block = block
91
75
 
92
- blocks[name.to_sym] = block_container if !name.is_a?(BuildingBlocks::Container) and blocks[name.to_sym].nil? and block_given?
93
-
94
- if start_rendering_blocks
95
- render_block name, args, options
96
- else
97
- # Delays rendering this block until the partial has been rendered and all the blocks have had a chance to be defined
98
- self.block_positions << block_container
99
- nil
100
- end
101
-
102
- # nil
76
+ self.render_block name, args, options
103
77
  end
104
-
78
+
79
+ def queue(*args, &block)
80
+ options = args.extract_options!
81
+
82
+ # If the user doesn't specify a block name, we generate an anonymous block name to assure other
83
+ # anonymous blocks don't override its definition
84
+ name = args.first ? args.shift : self.anonymous_block_name
85
+
86
+ # Delays rendering this block until the partial has been rendered and all the blocks have had a chance to be defined
87
+ self.queued_blocks << self.define_block_container(name, options, &block)
88
+ nil
89
+ end
90
+
105
91
  def render
106
- self.start_rendering_blocks = false
107
-
108
- global_options[:captured_block] = view.capture(self, &self.block) if self.block
109
-
110
- self.start_rendering_blocks = true
92
+ raise "Must specify :template parameter in order to render" unless global_options[:template]
111
93
 
94
+ global_options[:captured_block] = view.capture(self, &self.block) if self.block
112
95
  view.render global_options[:template], global_options
113
96
  end
114
-
97
+
115
98
  def before(name, options={}, &block)
116
99
  name = "before_#{name.to_s}".to_sym
117
-
100
+
118
101
  block_container = BuildingBlocks::Container.new
119
102
  block_container.name = name
120
103
  block_container.options = options
121
104
  block_container.block = block
122
-
105
+
123
106
  if view.blocks.blocks[name].nil?
124
107
  blocks[name] = [block_container]
125
108
  else
@@ -129,15 +112,15 @@ module BuildingBlocks
129
112
  nil
130
113
  end
131
114
  alias prepend before
132
-
115
+
133
116
  def after(name, options={}, &block)
134
117
  name = "after_#{name.to_s}".to_sym
135
-
118
+
136
119
  block_container = BuildingBlocks::Container.new
137
120
  block_container.name = name
138
121
  block_container.options = options
139
122
  block_container.block = block
140
-
123
+
141
124
  if view.blocks.blocks[name].nil?
142
125
  blocks[name] = [block_container]
143
126
  else
@@ -147,51 +130,52 @@ module BuildingBlocks
147
130
  nil
148
131
  end
149
132
  alias append after
150
-
133
+
151
134
  # If a method is missing, we'll assume the user is starting a new block group by that missing method name
152
- def method_missing(m, options={}, &block)
135
+ def method_missing(m, *args, &block)
136
+ options = args.extract_options!
137
+
153
138
  # If the specified block group has already been defined, it is simply returned here for iteration.
154
139
  # It will consist of all the blocks used in this block group that have yet to be rendered,
155
140
  # as the call for their use occurred before the template was rendered (where their definitions likely occurred)
156
141
  return self.block_groups[m] unless self.block_groups[m].nil?
157
-
142
+
158
143
  # Allows for nested block groups, store the current block positions array and start a new one
159
- original_block_positions = self.block_positions
160
- self.block_positions = []
161
- self.block_groups[m] = self.block_positions
162
-
144
+ original_queued_blocks = self.queued_blocks
145
+ self.queued_blocks = []
146
+ self.block_groups[m] = self.queued_blocks
147
+
163
148
  # Capture the contents of the block group (this will only capture block definitions and block uses)
164
149
  view.capture(global_options.merge(options), &block) if block_given?
165
-
150
+
166
151
  # restore the original block positions array
167
- self.block_positions = original_block_positions
152
+ self.queued_blocks = original_queued_blocks
168
153
  nil
169
154
  end
170
-
155
+
171
156
  protected
172
-
157
+
173
158
  def initialize(view, options={}, &block)
174
159
  options[options[:variable] ? options[:variable].to_sym : :blocks] = self
175
160
  options[:templates_folder] = "blocks" if options[:templates_folder].nil?
176
-
161
+
177
162
  self.view = view
178
163
  self.global_options = options
179
164
  self.block = block
180
- self.block_positions = []
181
- self.blocks = {}
165
+ self.queued_blocks = []
166
+ self.blocks = {}
182
167
  self.anonymous_block_number = 0
183
- self.block_groups = {}
184
- self.start_rendering_blocks = true
168
+ self.block_groups = {}
185
169
  end
186
-
170
+
187
171
  def anonymous_block_name
188
172
  self.anonymous_block_number = self.anonymous_block_number + 1
189
173
  "block_#{anonymous_block_number}"
190
174
  end
191
-
192
- def render_block(name_or_container, args, runtime_options={})
175
+
176
+ def render_block(name_or_container, args, runtime_options={})
193
177
  buffer = ActiveSupport::SafeBuffer.new
194
-
178
+
195
179
  block_options = {}
196
180
  if (name_or_container.is_a?(BuildingBlocks::Container))
197
181
  name = name_or_container.name.to_sym
@@ -199,18 +183,18 @@ module BuildingBlocks
199
183
  else
200
184
  name = name_or_container.to_sym
201
185
  end
202
-
186
+
203
187
  buffer << render_before_blocks(name_or_container, runtime_options)
204
-
205
- if blocks[name]
188
+
189
+ if blocks[name]
206
190
  block_container = blocks[name]
207
-
191
+
208
192
  args.push(global_options.merge(block_container.options).merge(block_options).merge(runtime_options))
209
-
193
+
210
194
  # If the block is taking more than one parameter, we can use *args
211
195
  if block_container.block.arity > 1
212
196
  buffer << view.capture(*args, &block_container.block)
213
-
197
+
214
198
  # However, if the block only takes a single parameter, we do not want ruby to try to cram the args list into that parameter
215
199
  # as an array
216
200
  else
@@ -218,13 +202,13 @@ module BuildingBlocks
218
202
  end
219
203
  elsif view.blocks.blocks[name]
220
204
  block_container = view.blocks.blocks[name]
221
-
205
+
222
206
  args.push(global_options.merge(block_container.options).merge(block_options).merge(runtime_options))
223
-
207
+
224
208
  # If the block is taking more than one parameter, we can use *args
225
209
  if block_container.block.arity > 1
226
210
  buffer << view.capture(*args, &block_container.block)
227
-
211
+
228
212
  # However, if the block only takes a single parameter, we do not want ruby to try to cram the args list into that parameter
229
213
  # as an array
230
214
  else
@@ -242,15 +226,15 @@ module BuildingBlocks
242
226
  # This block does not exist and no partial can be found to satify it
243
227
  end
244
228
  end
245
-
229
+
246
230
  buffer << render_after_blocks(name_or_container, runtime_options)
247
-
231
+
248
232
  buffer
249
233
  end
250
-
234
+
251
235
  def render_before_blocks(name_or_container, runtime_options={})
252
236
  options = global_options
253
-
237
+
254
238
  block_options = {}
255
239
  if (name_or_container.is_a?(BuildingBlocks::Container))
256
240
  name = name_or_container.name.to_sym
@@ -258,39 +242,37 @@ module BuildingBlocks
258
242
  else
259
243
  name = name_or_container.to_sym
260
244
  end
261
-
245
+
262
246
  before_name = "before_#{name.to_s}".to_sym
263
-
264
- if blocks[name]
247
+
248
+ if blocks[name]
265
249
  block_container = blocks[name]
266
-
267
250
  options = options.merge(block_container.options)
268
251
  elsif view.blocks.blocks[name]
269
252
  block_container = view.blocks.blocks[name]
270
-
271
253
  options = options.merge(block_container.options)
272
- end
273
-
254
+ end
255
+
274
256
  buffer = ActiveSupport::SafeBuffer.new
275
-
257
+
276
258
  unless blocks[before_name].nil?
277
259
  blocks[before_name].each do |block_container|
278
260
  buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
279
261
  end
280
262
  end
281
-
263
+
282
264
  unless view.blocks.blocks[before_name].nil? || view.blocks.blocks == blocks
283
265
  view.blocks.blocks[before_name].each do |block_container|
284
266
  buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
285
267
  end
286
268
  end
287
-
269
+
288
270
  buffer
289
271
  end
290
-
272
+
291
273
  def render_after_blocks(name_or_container, runtime_options={})
292
274
  options = global_options
293
-
275
+
294
276
  block_options = {}
295
277
  if (name_or_container.is_a?(BuildingBlocks::Container))
296
278
  name = name_or_container.name.to_sym
@@ -298,34 +280,43 @@ module BuildingBlocks
298
280
  else
299
281
  name = name_or_container.to_sym
300
282
  end
301
-
283
+
302
284
  after_name = "after_#{name.to_s}".to_sym
303
-
304
- if blocks[name]
285
+
286
+ if blocks[name]
305
287
  block_container = blocks[name]
306
-
288
+
307
289
  options = options.merge(block_container.options)
308
290
  elsif view.blocks.blocks[name]
309
291
  block_container = view.blocks.blocks[name]
310
-
292
+
311
293
  options = options.merge(block_container.options)
312
- end
313
-
294
+ end
295
+
314
296
  buffer = ActiveSupport::SafeBuffer.new
315
-
297
+
316
298
  unless blocks[after_name].nil?
317
299
  blocks[after_name].each do |block_container|
318
300
  buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
319
301
  end
320
302
  end
321
-
303
+
322
304
  unless view.blocks.blocks[after_name].nil? || view.blocks.blocks == blocks
323
305
  view.blocks.blocks[after_name].each do |block_container|
324
306
  buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
325
307
  end
326
308
  end
327
-
309
+
328
310
  buffer
329
311
  end
312
+
313
+ def define_block_container(name, options, &block)
314
+ block_container = BuildingBlocks::Container.new
315
+ block_container.name = name
316
+ block_container.options = options
317
+ block_container.block = block
318
+ blocks[name.to_sym] = block_container if blocks[name.to_sym].nil? && block_given?
319
+ block_container
320
+ end
330
321
  end
331
322
  end
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ describe BuildingBlocks::Base do
4
+ before :each do
5
+ @builder = BuildingBlocks::Base.new({})
6
+ end
7
+
8
+ describe "defined? method" do
9
+ it "should be able to determine if a block by a specific name is already defined" do
10
+ @builder.defined?(:test_block).should be_false
11
+ @builder.define :test_block do end
12
+ @builder.defined?(:test_block).should be_true
13
+ @builder.defined?("test_block").should be_true
14
+ end
15
+ end
16
+
17
+ describe "define method" do
18
+ it "should be able to define a new block" do
19
+ block = Proc.new { |options| }
20
+
21
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block
22
+
23
+ test_block = @builder.blocks[:test_block]
24
+ test_block.options[:option1].should eql("value1")
25
+ test_block.options[:option2].should eql("value2")
26
+ test_block.name.should eql(:test_block)
27
+ test_block.block.should eql(block)
28
+ end
29
+
30
+ it "should not replace a defined block with another attempted definition" do
31
+ block1 = Proc.new do |options| end
32
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block1
33
+
34
+ block2 = Proc.new do |options| end
35
+ @builder.define :test_block, :option3 => "value3", :option4 => "value4", &block2
36
+
37
+ test_block = @builder.blocks[:test_block]
38
+ test_block.options[:option1].should eql("value1")
39
+ test_block.options[:option2].should eql("value2")
40
+ test_block.options[:option3].should be_nil
41
+ test_block.options[:option4].should be_nil
42
+ test_block.name.should eql(:test_block)
43
+ test_block.block.should eql(block1)
44
+ end
45
+ end
46
+
47
+ describe "replace method" do
48
+ it "should be able to replace a defined block" do
49
+ block1 = Proc.new do |options| end
50
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block1
51
+
52
+ block2 = Proc.new do |options| end
53
+ @builder.replace :test_block, :option3 => "value3", :option4 => "value4", &block2
54
+
55
+ test_block = @builder.blocks[:test_block]
56
+ test_block.options[:option1].should be_nil
57
+ test_block.options[:option2].should be_nil
58
+ test_block.options[:option3].should eql("value3")
59
+ test_block.options[:option4].should eql("value4")
60
+ test_block.name.should eql(:test_block)
61
+ test_block.block.should eql(block2)
62
+ end
63
+ end
64
+
65
+ describe "use method" do
66
+ it "should be able to use a defined block by its name" do
67
+ @builder.expects(:render_block).with(:test_block, [], {})
68
+
69
+ block = Proc.new do |options| end
70
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block
71
+
72
+ @builder.use :test_block
73
+ end
74
+
75
+ it "should be able to use a defined block by its name and pass in runtime arguments" do
76
+ @builder.expects(:render_block).with(:test_block, ["value5"], {:option3 => "value3", :option4 => "value4"})
77
+
78
+ block = Proc.new do |options| end
79
+ @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block
80
+
81
+ @builder.use :test_block, "value5", :option3 => "value3", :option4 => "value4"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'building-blocks' # and any other gems you need
5
+
6
+ RSpec.configure do |config|
7
+ config.mock_with :mocha
8
+ # config.mock_with :flexmock
9
+ # config.mock_with :rr
10
+ # config.mock_with :rspec
11
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: building-blocks
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
5
- prerelease: false
4
+ hash: 15
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 7
10
- version: 0.0.7
9
+ - 8
10
+ version: 0.0.8
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Hunter
@@ -15,12 +15,10 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-20 00:00:00 -04:00
18
+ date: 2012-01-20 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- prerelease: false
23
- type: :runtime
24
22
  name: building-blocks
25
23
  version_requirements: &id001 !ruby/object:Gem::Requirement
26
24
  none: false
@@ -31,10 +29,10 @@ dependencies:
31
29
  segments:
32
30
  - 0
33
31
  version: "0"
34
- requirement: *id001
35
- - !ruby/object:Gem::Dependency
36
32
  prerelease: false
37
33
  type: :runtime
34
+ requirement: *id001
35
+ - !ruby/object:Gem::Dependency
38
36
  name: rails
39
37
  version_requirements: &id002 !ruby/object:Gem::Requirement
40
38
  none: false
@@ -47,7 +45,23 @@ dependencies:
47
45
  - 0
48
46
  - 0
49
47
  version: 3.0.0
48
+ prerelease: false
49
+ type: :runtime
50
50
  requirement: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: jeweler
53
+ version_requirements: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ prerelease: false
63
+ type: :development
64
+ requirement: *id003
51
65
  description: ""
52
66
  email: hunterae@gmail.com
53
67
  executables: []
@@ -61,10 +75,12 @@ files:
61
75
  - Rakefile
62
76
  - VERSION
63
77
  - lib/building-blocks.rb
64
- - lib/building_blocks/building_blocks.rb
78
+ - lib/building_blocks/base.rb
65
79
  - lib/building_blocks/container.rb
66
80
  - lib/building_blocks/helper_methods.rb
67
81
  - rails/init.rb
82
+ - spec/building-blocks/base_spec.rb
83
+ - spec/spec_helper.rb
68
84
  has_rdoc: true
69
85
  homepage: http://github.com/hunterae/building-blocks
70
86
  licenses: []
@@ -95,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
111
  requirements: []
96
112
 
97
113
  rubyforge_project:
98
- rubygems_version: 1.3.7
114
+ rubygems_version: 1.5.2
99
115
  signing_key:
100
116
  specification_version: 3
101
117
  summary: ""