building-blocks 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -176,40 +176,40 @@ Then, in a specific view that is rendered using this layout, you can add stylesh
176
176
 
177
177
  == Blocks as Partials
178
178
 
179
- 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
+ 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 look for a partial by the same name in your current controller's view directory. 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. And 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.
180
180
 
181
181
  As an example, consider the following code, running in a view for PagesController:
182
182
 
183
183
  <%= blocks.use :wizard, :step => @step %>
184
184
 
185
185
  <!-- 1) Check and see if there was a block defined called "wizard" somewhere prior to its use... No? then... -->
186
- <!-- 2) Check and see if there is a default definition provided for "wizard", i.e. specified in the "blocks.use" call... No? Then... -->
187
- <!-- 3) Check and see if there is a controller-specific partial /app/views/pages/wizard.html.erb. No? Then... -->
188
- <!-- 4) Check and see if there is a global partial /app/views/blocks/wizard.html.erb. No? Then render nothing. -->
186
+ <!-- 2) Check and see if there is a controller-specific partial /app/views/pages/wizard.html.erb. No? Then... -->
187
+ <!-- 3) Check and see if there is a global partial /app/views/blocks/wizard.html.erb. No? Then... -->
188
+ <!-- 4) Check and see if there is a default definition provided for "wizard", i.e. specified in the "blocks.use" call... No? Then render nothing -->
189
189
 
190
190
  Let's look at each example individually, written in the order that BuildingBlocks attempts to render them:
191
191
 
192
- 1. Inline definition of a block:
192
+ 1) Inline definition of a block:
193
193
  <% blocks.define :wizard do |options| %>
194
194
  Inline Block Step#<%= options[:step] %>.
195
195
  <% end %>
196
196
 
197
197
  <!-- Elsewhere, you can use the block as follows -->
198
198
  <%= blocks.use :wizard, :step => @step %>
199
- 2. Default implementation of a block:
200
- <%= blocks.use :wizard, :step => @step do |options| do %>
201
- Default Implementation Block Step#<%= options %>.
202
- <% end %>
203
- 3. Controller-specific partial:
199
+ 2) Controller-specific partial:
204
200
  <%= blocks.use :wizard, :step => @step %>
205
201
 
206
202
  <!-- In /app/views/pages/_wizard.html.erb: -->
207
203
  Controller-specific Block Step# <%= step %>.
208
- 4. Global partial:
204
+ 3) Global partial:
209
205
  <%= blocks.use :wizard, :step => @step %>
210
206
 
211
207
  <!-- In /app/views/blocks/_wizard.html.erb: -->
212
208
  Global Block Step#<%= step %>.
209
+ 4) Default implementation of a block:
210
+ <%= blocks.use :wizard, :step => @step do |options| do %>
211
+ Default Implementation Block Step#<%= options %>.
212
+ <% end %>
213
213
 
214
214
  == Overall Render Order
215
215
 
@@ -218,23 +218,24 @@ link:/hunterae/building-blocks/raw/master/blocks_render_order.png
218
218
 
219
219
  == Templating
220
220
 
221
- 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
+ The most advanced feature of BuildingBlocks is the ability to utilize it for templating and creating your own DTD specifications for the components you write.
222
222
 
223
- 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
+ As an example, consider {table-for}[https://github.com/hunterae/table-for], a gem 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:
224
224
 
225
- <%= table_for @users, :row_html => {:class => lambda { cycle('even', 'odd')},
226
- :id => lambda {|user| "user-#{user.id}"}},
227
- :sortable => true do |table| %>
228
- <% table.column :edit %>
229
- <% table.column :show %>
230
- <% table.column :email, :label => "Email Address" %>
231
- <% table.column :name, :header_html => {:style => "background-color:orange"} do |user| %>
225
+ <%= table_for @users, :table_html => {:style => "border: 1px solid black"},
226
+ :sortable => true,
227
+ :row_html => {:class => lambda { cycle('even', 'odd')},
228
+ :id => lambda {|user| "user-#{user.id}"}} do |table| %>
229
+ <%= table.column :edit %>
230
+ <%= table.column :show %>
231
+ <%= table.column :email, :label => "Email Address" %>
232
+ <%= table.column :label => "Full Name", :sortable => false, :header_html => {:style => "color:orange"} do |user| %>
232
233
  <%= "#{user.first_name} #{user.last_name}" %>
233
234
  <% end %>
234
- <% table.column :delete %>
235
+ <%= table.column :delete %>
235
236
  <% end %>
236
237
 
237
- MORE EXPLANATION TO COME
238
+ VIDEO TUTORIAL TO COME
238
239
 
239
240
  == MORE COMING SOON...
240
241
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 1.0.0
@@ -1,13 +1,5 @@
1
1
  require "action_view"
2
2
 
3
- $LOAD_PATH.unshift(File.dirname(__FILE__))
4
-
5
3
  require "building_blocks/base"
6
4
  require "building_blocks/container"
7
- require "building_blocks/helper_methods"
8
-
9
- $LOAD_PATH.shift
10
-
11
- if defined?(ActionView::Base)
12
- ActionView::Base.send :include, BuildingBlocks::HelperMethods
13
- end
5
+ require "building_blocks/view_additions"
@@ -1,4 +1,6 @@
1
1
  module BuildingBlocks
2
+ BUILDING_BLOCKS_TEMPLATE_FOLDER = "blocks"
3
+
2
4
  class Base
3
5
  attr_accessor :view
4
6
 
@@ -6,7 +8,7 @@ module BuildingBlocks
6
8
 
7
9
  attr_accessor :block
8
10
 
9
- # Array of BuildingBlocks::Container objects, storing the order of blocks as they were used
11
+ # Array of BuildingBlocks::Container objects, storing the order of blocks as they were queued
10
12
  attr_accessor :queued_blocks
11
13
 
12
14
  # counter, used to give unnamed blocks a unique name
@@ -67,25 +69,16 @@ module BuildingBlocks
67
69
  end
68
70
 
69
71
  def use(*args, &block)
70
- options = args.extract_options!
71
-
72
- # If the user doesn't specify a block name, we generate an anonymous block name to assure other
73
- # anonymous blocks don't override its definition
74
- name = args.first ? args.shift : self.anonymous_block_name
75
-
76
- # self.define_block_container(name, options, &block) if block_given?
77
- self.render_block name, args, options, &block
72
+ name_or_container = args.first ? args.shift : self.anonymous_block_name
73
+ buffer = ActiveSupport::SafeBuffer.new
74
+ buffer << render_before_blocks(name_or_container, *args)
75
+ buffer << render_block(name_or_container, *args, &block)
76
+ buffer << render_after_blocks(name_or_container, *args)
77
+ buffer
78
78
  end
79
79
 
80
80
  def queue(*args, &block)
81
- options = args.extract_options!
82
-
83
- # If the user doesn't specify a block name, we generate an anonymous block name to assure other
84
- # anonymous blocks don't override its definition
85
- name = args.first ? args.shift : self.anonymous_block_name
86
-
87
- # Delays rendering this block until the partial has been rendered and all the blocks have had a chance to be defined
88
- self.queued_blocks << self.define_block_container(name, options, &block)
81
+ self.queued_blocks << self.define_block_container(*args, &block)
89
82
  nil
90
83
  end
91
84
 
@@ -100,37 +93,13 @@ module BuildingBlocks
100
93
  end
101
94
 
102
95
  def before(name, options={}, &block)
103
- name = "before_#{name.to_s}".to_sym
104
-
105
- block_container = BuildingBlocks::Container.new
106
- block_container.name = name
107
- block_container.options = options
108
- block_container.block = block
109
-
110
- if view.blocks.blocks[name].nil?
111
- blocks[name] = [block_container]
112
- else
113
- blocks[name] << block_container
114
- end
115
-
96
+ self.queue_block_container("before_#{name.to_s}", options, &block)
116
97
  nil
117
98
  end
118
99
  alias prepend before
119
100
 
120
101
  def after(name, options={}, &block)
121
- name = "after_#{name.to_s}".to_sym
122
-
123
- block_container = BuildingBlocks::Container.new
124
- block_container.name = name
125
- block_container.options = options
126
- block_container.block = block
127
-
128
- if view.blocks.blocks[name].nil?
129
- blocks[name] = [block_container]
130
- else
131
- blocks[name] << block_container
132
- end
133
-
102
+ self.queue_block_container("after_#{name.to_s}", options, &block)
134
103
  nil
135
104
  end
136
105
  alias append after
@@ -160,7 +129,7 @@ module BuildingBlocks
160
129
  protected
161
130
 
162
131
  def initialize(view, options={}, &block)
163
- options[:templates_folder] = "blocks" if options[:templates_folder].nil?
132
+ options[:templates_folder] = BuildingBlocks::BUILDING_BLOCKS_TEMPLATE_FOLDER if options[:templates_folder].nil?
164
133
 
165
134
  self.view = view
166
135
  self.global_options = options
@@ -172,11 +141,13 @@ module BuildingBlocks
172
141
  end
173
142
 
174
143
  def anonymous_block_name
175
- self.anonymous_block_number = self.anonymous_block_number + 1
144
+ self.anonymous_block_number += 1
176
145
  "block_#{anonymous_block_number}"
177
146
  end
178
147
 
179
- def render_block(name_or_container, args, runtime_options={}, &block)
148
+ def render_block(name_or_container, *args, &block)
149
+ options = args.extract_options!
150
+
180
151
  buffer = ActiveSupport::SafeBuffer.new
181
152
 
182
153
  block_options = {}
@@ -187,63 +158,28 @@ module BuildingBlocks
187
158
  name = name_or_container.to_sym
188
159
  end
189
160
 
190
- buffer << render_before_blocks(name_or_container, runtime_options)
191
-
192
161
  if blocks[name]
193
162
  block_container = blocks[name]
194
-
195
- args.push(global_options.merge(block_container.options).merge(block_options).merge(runtime_options))
196
-
197
- # If the block is taking more than one parameter, we can use *args
198
- if block_container.block.arity > 1
199
- buffer << view.capture(*args, &block_container.block)
200
-
201
- # However, if the block only takes a single parameter, we do not want ruby to try to cram the args list into that parameter
202
- # as an array
203
- else
204
- buffer << view.capture(args.first, &block_container.block)
205
- end
206
- elsif view.blocks.blocks[name]
207
- block_container = view.blocks.blocks[name]
208
-
209
- args.push(global_options.merge(block_container.options).merge(block_options).merge(runtime_options))
210
-
211
- # If the block is taking more than one parameter, we can use *args
212
- if block_container.block.arity > 1
213
- buffer << view.capture(*args, &block_container.block)
214
-
215
- # However, if the block only takes a single parameter, we do not want ruby to try to cram the args list into that parameter
216
- # as an array
217
- else
218
- buffer << view.capture(args.first, &block_container.block)
219
- end
163
+ args.push(global_options.merge(block_container.options).merge(block_options).merge(options))
164
+ buffer << view.capture(*(args[0, block_container.block.arity]), &block_container.block)
220
165
  else
221
166
  begin
222
- begin
223
- buffer << view.render("#{name.to_s}", global_options.merge(block_options).merge(runtime_options))
224
- rescue ActionView::MissingTemplate
225
- # This partial did not exist in the current controller's view directory; now checking in the default templates folder
226
- buffer << view.render("#{self.global_options[:templates_folder]}/#{name.to_s}", global_options.merge(block_options).merge(runtime_options))
167
+ begin
168
+ buffer << view.render("#{name.to_s}", global_options.merge(block_options).merge(options))
169
+ rescue ActionView::MissingTemplate
170
+ buffer << view.render("#{self.global_options[:templates_folder]}/#{name.to_s}", global_options.merge(block_options).merge(options))
227
171
  end
228
172
  rescue ActionView::MissingTemplate
229
- if block_given?
230
- args.push(global_options.merge(runtime_options))
231
- if block.arity > 1
232
- buffer << view.capture(*args, &block)
233
- else
234
- buffer << view.capture(args.first, &block)
235
- end
236
- end
173
+ args.push(global_options.merge(options))
174
+ buffer << view.capture(*(args[0, block.arity]), &block) if block_given?
237
175
  end
238
176
  end
239
177
 
240
- buffer << render_after_blocks(name_or_container, runtime_options)
241
-
242
178
  buffer
243
179
  end
244
180
 
245
- def render_before_blocks(name_or_container, runtime_options={})
246
- options = global_options
181
+ def render_before_blocks(name_or_container, *args)
182
+ options = args.extract_options!
247
183
 
248
184
  block_options = {}
249
185
  if (name_or_container.is_a?(BuildingBlocks::Container))
@@ -251,37 +187,34 @@ module BuildingBlocks
251
187
  block_options = name_or_container.options
252
188
  else
253
189
  name = name_or_container.to_sym
190
+ block_options = blocks[name].options if blocks[name]
254
191
  end
255
192
 
256
193
  before_name = "before_#{name.to_s}".to_sym
257
-
258
- if blocks[name]
259
- block_container = blocks[name]
260
- options = options.merge(block_container.options)
261
- elsif view.blocks.blocks[name]
262
- block_container = view.blocks.blocks[name]
263
- options = options.merge(block_container.options)
264
- end
265
-
266
194
  buffer = ActiveSupport::SafeBuffer.new
267
195
 
268
- unless blocks[before_name].nil?
196
+ if blocks[before_name].present?
269
197
  blocks[before_name].each do |block_container|
270
- buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
198
+ args_clone = args.clone
199
+ args_clone.push(global_options.merge(block_options).merge(block_container.options).merge(options))
200
+ buffer << view.capture(*(args_clone[0, block_container.block.arity]), &block_container.block)
271
201
  end
272
- end
273
-
274
- unless view.blocks.blocks[before_name].nil? || view.blocks.blocks == blocks
275
- view.blocks.blocks[before_name].each do |block_container|
276
- buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
202
+ else
203
+ begin
204
+ begin
205
+ buffer << view.render("before_#{name.to_s}", global_options.merge(block_options).merge(options))
206
+ rescue ActionView::MissingTemplate
207
+ buffer << view.render("#{self.global_options[:templates_folder]}/before_#{name.to_s}", global_options.merge(block_options).merge(options))
208
+ end
209
+ rescue ActionView::MissingTemplate
277
210
  end
278
211
  end
279
212
 
280
213
  buffer
281
214
  end
282
215
 
283
- def render_after_blocks(name_or_container, runtime_options={})
284
- options = global_options
216
+ def render_after_blocks(name_or_container, *args)
217
+ options = args.extract_options!
285
218
 
286
219
  block_options = {}
287
220
  if (name_or_container.is_a?(BuildingBlocks::Container))
@@ -289,43 +222,54 @@ module BuildingBlocks
289
222
  block_options = name_or_container.options
290
223
  else
291
224
  name = name_or_container.to_sym
225
+ block_options = blocks[name].options if blocks[name]
292
226
  end
293
227
 
294
228
  after_name = "after_#{name.to_s}".to_sym
295
-
296
- if blocks[name]
297
- block_container = blocks[name]
298
-
299
- options = options.merge(block_container.options)
300
- elsif view.blocks.blocks[name]
301
- block_container = view.blocks.blocks[name]
302
-
303
- options = options.merge(block_container.options)
304
- end
305
-
306
229
  buffer = ActiveSupport::SafeBuffer.new
307
230
 
308
- unless blocks[after_name].nil?
231
+ if blocks[after_name].present?
309
232
  blocks[after_name].each do |block_container|
310
- buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
233
+ args_clone = args.clone
234
+ args_clone.push(global_options.merge(block_options).merge(block_container.options).merge(options))
235
+ buffer << view.capture(*(args_clone[0, block_container.block.arity]), &block_container.block)
311
236
  end
312
- end
313
-
314
- unless view.blocks.blocks[after_name].nil? || view.blocks.blocks == blocks
315
- view.blocks.blocks[after_name].each do |block_container|
316
- buffer << view.capture(options.merge(block_container.options).merge(block_options).merge(runtime_options), &block_container.block)
237
+ else
238
+ begin
239
+ begin
240
+ buffer << view.render("after_#{name.to_s}", global_options.merge(block_options).merge(options))
241
+ rescue ActionView::MissingTemplate
242
+ buffer << view.render("#{self.global_options[:templates_folder]}/after_#{name.to_s}", global_options.merge(block_options).merge(options))
243
+ end
244
+ rescue ActionView::MissingTemplate
317
245
  end
318
246
  end
319
247
 
320
248
  buffer
321
249
  end
322
250
 
323
- def define_block_container(name, options, &block)
251
+ def build_block_container(*args, &block)
252
+ options = args.extract_options!
253
+ name = args.first ? args.shift : self.anonymous_block_name
324
254
  block_container = BuildingBlocks::Container.new
325
- block_container.name = name
255
+ block_container.name = name.to_sym
326
256
  block_container.options = options
327
257
  block_container.block = block
328
- blocks[name.to_sym] = block_container if blocks[name.to_sym].nil? && block_given?
258
+ block_container
259
+ end
260
+
261
+ def queue_block_container(*args, &block)
262
+ block_container = self.build_block_container(*args, &block)
263
+ if blocks[block_container.name].nil?
264
+ blocks[block_container.name] = [block_container]
265
+ else
266
+ blocks[block_container.name] << block_container
267
+ end
268
+ end
269
+
270
+ def define_block_container(*args, &block)
271
+ block_container = self.build_block_container(*args, &block)
272
+ blocks[block_container.name] = block_container if blocks[block_container.name].nil? && block_given?
329
273
  block_container
330
274
  end
331
275
  end
@@ -0,0 +1,13 @@
1
+ module BuildingBlocks
2
+ module ViewAdditions
3
+ module ClassMethods
4
+ def blocks
5
+ @blocks ||= BuildingBlocks::Base.new(self)
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ if defined?(ActionView::Base)
12
+ ActionView::Base.send :include, BuildingBlocks::ViewAdditions::ClassMethods
13
+ end
@@ -2,7 +2,8 @@ require "spec_helper"
2
2
 
3
3
  describe BuildingBlocks::Base do
4
4
  before :each do
5
- @builder = BuildingBlocks::Base.new({})
5
+ @view = ActionView::Base.new
6
+ @builder = BuildingBlocks::Base.new(@view)
6
7
  end
7
8
 
8
9
  describe "defined? method" do
@@ -10,6 +11,21 @@ describe BuildingBlocks::Base do
10
11
  @builder.defined?(:test_block).should be_false
11
12
  @builder.define :test_block do end
12
13
  @builder.defined?(:test_block).should be_true
14
+ end
15
+
16
+ it "should not care whether the block name was defined with a string or a symbol" do
17
+ @builder.defined?(:test_block).should be_false
18
+ @builder.define "test_block" do end
19
+ @builder.defined?(:test_block).should be_true
20
+
21
+ @builder.defined?(:test_block2).should be_false
22
+ @builder.define :test_block2 do end
23
+ @builder.defined?(:test_block2).should be_true
24
+ end
25
+
26
+ it "should not care whether the defined? method is passed a string or a symbol" do
27
+ @builder.defined?("test_block").should be_false
28
+ @builder.define :test_block do end
13
29
  @builder.defined?("test_block").should be_true
14
30
  end
15
31
  end
@@ -35,12 +51,12 @@ describe BuildingBlocks::Base do
35
51
  @builder.define :test_block, :option3 => "value3", :option4 => "value4", &block2
36
52
 
37
53
  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)
54
+ test_block.options[:option1].should eql("value1")
55
+ test_block.options[:option2].should eql("value2")
56
+ test_block.options[:option3].should be_nil
57
+ test_block.options[:option4].should be_nil
58
+ test_block.name.should eql(:test_block)
59
+ test_block.block.should eql(block1)
44
60
  end
45
61
  end
46
62
 
@@ -62,23 +78,406 @@ describe BuildingBlocks::Base do
62
78
  end
63
79
  end
64
80
 
81
+ describe "queue method" do
82
+ it "should store all queued blocks in the queued_blocks array" do
83
+ @builder.queued_blocks.should be_empty
84
+ @builder.queue :test_block
85
+ @builder.queued_blocks.length.should eql 1
86
+ @builder.queued_blocks.map(&:name).first.should eql(:test_block)
87
+ end
88
+
89
+ it "should convert a string block name to a symbol" do
90
+ @builder.queue "test_block"
91
+ @builder.queued_blocks.map(&:name).first.should eql(:test_block)
92
+ end
93
+
94
+ it "should queue blocks as BuildingBlocks::Container objects" do
95
+ @builder.queue :test_block, :a => 1, :b => 2, :c => 3
96
+ container = @builder.queued_blocks.first
97
+ container.should be_a(BuildingBlocks::Container)
98
+ container.name.should eql(:test_block)
99
+ container.options.should eql(:a => 1, :b => 2, :c => 3)
100
+ end
101
+
102
+ it "should not require a name for the block being queued" do
103
+ @builder.queue
104
+ @builder.queue
105
+ @builder.queued_blocks.length.should eql 2
106
+ @builder.queued_blocks.map(&:name).first.should eql(:block_1)
107
+ @builder.queued_blocks.map(&:name).second.should eql(:block_2)
108
+ end
109
+
110
+ it "should anonymously define the name of a block if not specified" do
111
+ @builder.queue
112
+ @builder.queue :my_block
113
+ @builder.queue
114
+ @builder.queued_blocks.map(&:name).first.should eql(:block_1)
115
+ @builder.queued_blocks.map(&:name).second.should eql(:my_block)
116
+ @builder.queued_blocks.map(&:name).third.should eql(:block_2)
117
+ end
118
+
119
+ it "should store queued blocks in the order in which they are queued" do
120
+ @builder.queue :block1
121
+ @builder.queue :block3
122
+ @builder.queue :block2
123
+ @builder.queued_blocks.map(&:name).first.should eql(:block1)
124
+ @builder.queued_blocks.map(&:name).second.should eql(:block3)
125
+ @builder.queued_blocks.map(&:name).third.should eql(:block2)
126
+ end
127
+
128
+ it "should allow a definition to be provided for a queued block" do
129
+ block = Proc.new do |options| end
130
+ @builder.queue :test_block, &block
131
+ container = @builder.queued_blocks.first
132
+ container.block.should eql block
133
+ end
134
+ end
135
+
136
+ describe "render method" do
137
+ it "should raise an exception if no :template parameter is specified in the options hash" do
138
+ view = mock()
139
+ builder = BuildingBlocks::Base.new(view)
140
+ lambda { builder.render }.should raise_error("Must specify :template parameter in order to render")
141
+ end
142
+
143
+ it "should attempt to render a partial specified as the :template parameter" do
144
+ view = mock()
145
+ builder = BuildingBlocks::Base.new(view, :template => "my_template")
146
+ view.expects(:render).with{ |template, options| template.should eql "my_template"}
147
+ builder.render
148
+ end
149
+
150
+ it "should set all of the global options as local variables to the partial it renders" do
151
+ view = mock()
152
+ builder = BuildingBlocks::Base.new(view, :template => "some_template")
153
+ view.expects(:render).with { |template, options| options.should eql :templates_folder => 'blocks', :template => 'some_template', :blocks => builder }
154
+ builder.render
155
+ end
156
+
157
+ it "should capture the data of a block if a block has been specified" do
158
+ block = Proc.new { |options| "my captured block" }
159
+ builder = BuildingBlocks::Base.new(@view, :template => "template", &block)
160
+ @view.expects(:render).with { |tempate, options| options[:captured_block].should eql("my captured block") }
161
+ builder.render
162
+ end
163
+
164
+ it "should by default add a variable to the partial called 'blocks' as a pointer to the BuildingBlocks::Base instance" do
165
+ view = mock()
166
+ builder = BuildingBlocks::Base.new(view, :template => "some_template")
167
+ view.expects(:render).with { |template, options| options[:blocks].should eql(builder) }
168
+ builder.render
169
+ end
170
+
171
+ it "should allow the user to override the local variable passed to the partial as a pointer to the BuildingBlocks::Base instance" do
172
+ view = mock()
173
+ builder = BuildingBlocks::Base.new(view, :variable => "my_variable", :template => "some_template")
174
+ view.expects(:render).with { |template, options| options[:blocks].should be_nil }
175
+ builder.render
176
+ end
177
+ end
178
+
179
+ describe "before method" do
180
+ it "should defined before blocks as the block name with the word 'before_' prepended to it" do
181
+ block = Proc.new { |options| }
182
+ @builder.before :some_block, &block
183
+ @builder.blocks[:before_some_block].should be_present
184
+ end
185
+
186
+ it "should store a before block in an array" do
187
+ block = Proc.new { |options| }
188
+ @builder.before :some_block, &block
189
+ before_blocks = @builder.blocks[:before_some_block]
190
+ before_blocks.should be_a(Array)
191
+ end
192
+
193
+ it "should store a before block as a BuildingBlocks::Container" do
194
+ block = Proc.new { |options| }
195
+ @builder.before :some_block, :option1 => "some option", &block
196
+ before_blocks = @builder.blocks[:before_some_block]
197
+ block_container = before_blocks.first
198
+ block_container.should be_a(BuildingBlocks::Container)
199
+ block_container.options.should eql :option1 => "some option"
200
+ block_container.block.should eql block
201
+ end
202
+
203
+ it "should queue before blocks if there are multiple defined" do
204
+ block = Proc.new { |options| }
205
+ block2 = Proc.new { |options| }
206
+ @builder.before :some_block, &block
207
+ @builder.before :some_block, &block2
208
+ before_blocks = @builder.blocks[:before_some_block]
209
+ before_blocks.length.should eql 2
210
+ end
211
+
212
+ it "should store before blocks in the order in which they are defined" do
213
+ block = Proc.new { |options| }
214
+ block2 = Proc.new { |options| }
215
+ block3 = Proc.new { |options| }
216
+ @builder.before :some_block, &block
217
+ @builder.before :some_block, &block2
218
+ @builder.before :some_block, &block3
219
+ before_blocks = @builder.blocks[:before_some_block]
220
+ before_blocks.first.block.should eql block
221
+ before_blocks.second.block.should eql block2
222
+ before_blocks.third.block.should eql block3
223
+ end
224
+ end
225
+
226
+ describe "after method" do
227
+ it "should defined after blocks as the block name with the word 'after_' prepended to it" do
228
+ block = Proc.new { |options| }
229
+ @builder.after :some_block, &block
230
+ @builder.blocks[:after_some_block].should be_present
231
+ end
232
+
233
+ it "should store a after block in an array" do
234
+ block = Proc.new { |options| }
235
+ @builder.after :some_block, &block
236
+ after_blocks = @builder.blocks[:after_some_block]
237
+ after_blocks.should be_a(Array)
238
+ end
239
+
240
+ it "should store a after block as a BuildingBlocks::Container" do
241
+ block = Proc.new { |options| }
242
+ @builder.after :some_block, :option1 => "some option", &block
243
+ after_blocks = @builder.blocks[:after_some_block]
244
+ block_container = after_blocks.first
245
+ block_container.should be_a(BuildingBlocks::Container)
246
+ block_container.options.should eql :option1 => "some option"
247
+ block_container.block.should eql block
248
+ end
249
+
250
+ it "should queue after blocks if there are multiple defined" do
251
+ block = Proc.new { |options| }
252
+ block2 = Proc.new { |options| }
253
+ @builder.after :some_block, &block
254
+ @builder.after :some_block, &block2
255
+ after_blocks = @builder.blocks[:after_some_block]
256
+ after_blocks.length.should eql 2
257
+ end
258
+
259
+ it "should store after blocks in the order in which they are defined" do
260
+ block = Proc.new { |options| }
261
+ block2 = Proc.new { |options| }
262
+ block3 = Proc.new { |options| }
263
+ @builder.after :some_block, &block
264
+ @builder.after :some_block, &block2
265
+ @builder.after :some_block, &block3
266
+ after_blocks = @builder.blocks[:after_some_block]
267
+ after_blocks.first.block.should eql block
268
+ after_blocks.second.block.should eql block2
269
+ after_blocks.third.block.should eql block3
270
+ end
271
+ end
272
+
65
273
  describe "use method" do
274
+ before :each do
275
+ @builder.expects(:render_before_blocks).at_least_once
276
+ @builder.expects(:render_after_blocks).at_least_once
277
+ end
278
+
66
279
  it "should be able to use a defined block by its name" do
67
- @builder.expects(:render_block).with(:test_block, [], {})
280
+ block = Proc.new {"output"}
281
+ @builder.define :some_block, &block
282
+ @builder.use(:some_block).should eql "output"
283
+ end
68
284
 
69
- block = Proc.new do |options| end
70
- @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block
285
+ it "should automatically pass in an options hash to a defined block that takes one paramter when that block is used" do
286
+ block = Proc.new {|options| "Templates folder is #{options[:templates_folder]}"}
287
+ @builder.define :some_block, &block
288
+ @builder.use(:some_block).should eql "Templates folder is blocks"
289
+ end
71
290
 
72
- @builder.use :test_block
291
+ it "should be able to use a defined block by its name and pass in runtime arguments as a hash" do
292
+ block = Proc.new do |options|
293
+ print_hash(options)
294
+ end
295
+ @builder.define :some_block, &block
296
+ @builder.use(:some_block, :param1 => 1, :param2 => "value2").should eql print_hash(:templates_folder => 'blocks', :param1 => 1, :param2 => "value2")
73
297
  end
74
298
 
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"})
299
+ it "should be able to use a defined block by its name and pass in runtime arguments one by one" do
300
+ block = Proc.new do |first_param, second_param, options|
301
+ "first_param: #{first_param}, second_param: #{second_param}, #{print_hash options}"
302
+ end
303
+ @builder.define :some_block, &block
304
+ @builder.use(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql("first_param: 3, second_param: 4, #{print_hash(:templates_folder => 'blocks', :param1 => 1, :param2 => "value2")}")
305
+ end
77
306
 
78
- block = Proc.new do |options| end
79
- @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block
307
+ it "should match up the number of arguments to a defined block with the parameters passed when a block is used" do
308
+ block = Proc.new {|first_param| "first_param = #{first_param}"}
309
+ @builder.define :some_block, &block
310
+ @builder.use(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql "first_param = 3"
311
+
312
+ block = Proc.new {|first_param, second_param| "first_param = #{first_param}, second_param = #{second_param}"}
313
+ @builder.replace :some_block, &block
314
+ @builder.use(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql "first_param = 3, second_param = 4"
315
+
316
+ block = Proc.new do |first_param, second_param, options|
317
+ "first_param: #{first_param}, second_param: #{second_param}, #{print_hash options}"
318
+ end
319
+ @builder.replace :some_block, &block
320
+ @builder.use(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql("first_param: 3, second_param: 4, #{print_hash(:templates_folder => 'blocks', :param1 => 1, :param2 => "value2")}")
321
+ end
322
+
323
+ it "should not render anything if using a block that has been defined" do
324
+ @view.expects(:capture).never
325
+ @view.expects(:render).with("some_block", :templates_folder => 'blocks').raises(ActionView::MissingTemplate.new([],[],[],[],[]))
326
+ @view.expects(:render).with("blocks/some_block", :templates_folder => 'blocks').raises(ActionView::MissingTemplate.new([],[],[],[],[]))
327
+ @builder.use :some_block
328
+ end
329
+
330
+ it "should first attempt to capture a block's contents when blocks.use is called" do
331
+ block = Proc.new {|options|}
332
+ @view.expects(:capture).with(:templates_folder => 'blocks', :value1 => 1, :value2 => 2)
333
+ @view.expects(:render).with("some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).never
334
+ @view.expects(:render).with("blocks/some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).never
335
+ @builder.define :some_block, &block
336
+ @builder.use :some_block, :value1 => 1, :value2 => 2
337
+ end
338
+
339
+ it "should second attempt to render a local partial by the block's name when blocks.use is called" do
340
+ @view.expects(:capture).with(:templates_folder => 'blocks', :value1 => 1, :value2 => 2).never
341
+ @view.expects(:render).with("some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).once
342
+ @view.expects(:render).with("blocks/some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).never
343
+ @builder.use :some_block, :value1 => 1, :value2 => 2
344
+ end
345
+
346
+ it "should third attempt to render a global partial by the block's name when blocks.use is called" do
347
+ @view.expects(:capture).with(:templates_folder => 'blocks', :value1 => 1, :value2 => 2).never
348
+ @view.expects(:render).with("some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
349
+ @view.expects(:render).with("blocks/some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).once
350
+ @builder.use :some_block, :value1 => 1, :value2 => 2
351
+ end
352
+
353
+ it "should fourth attempt to render a default block when blocks.use is called" do
354
+ block = Proc.new {|options|}
355
+ @view.expects(:render).with("some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
356
+ @view.expects(:render).with("blocks/some_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
357
+ @view.expects(:capture).with(:templates_folder => 'blocks', :value1 => 1, :value2 => 2)
358
+ @builder.use :some_block, :value1 => 1, :value2 => 2, &block
359
+ end
360
+
361
+ it "should override hash options for a block by merging the runtime options the define default options into the queue level options into the global options" do
362
+ block = Proc.new {|options|}
363
+ @builder.global_options.merge!(:param1 => "global level", :param2 => "global level", :param3 => "global level", :param4 => "global level")
364
+ @builder.queue(:my_before_block, :param1 => "queue level", :param2 => "queue level")
365
+ @builder.define(:my_before_block, :param1 => "define level", :param2 => "define level", :param3 => "define level", &block)
366
+ block_container = @builder.queued_blocks.first
367
+ @view.expects(:capture).with(:param4 => 'global level', :param1 => 'use level', :templates_folder => 'blocks', :param2 => 'queue level', :param3 => 'define level')
368
+ @builder.use block_container, :param1 => "use level"
369
+ end
370
+
371
+ it "should render the contents of a defined block when that block is used" do
372
+ block = Proc.new {}
373
+ @view.expects(:capture).with(nil).returns("rendered content")
374
+ @builder.define :some_block, &block
375
+ buffer = @builder.use :some_block
376
+ buffer.should eql "rendered content"
377
+ end
378
+ end
379
+
380
+ describe "use method - before blocks" do
381
+ before :each do
382
+ @builder.expects(:render_block).at_least_once
383
+ @builder.expects(:render_after_blocks).at_least_once
384
+ end
385
+
386
+ it "should render before blocks when using a block" do
387
+ block = Proc.new {|value1, value2, options|}
388
+ @builder.before("my_before_block", &block)
389
+ @view.expects(:capture).with(1, 2, :templates_folder => 'blocks', :value3 => 3, :value4 => 4)
390
+ @builder.use :my_before_block, 1, 2, :value3 => 3, :value4 => 4
391
+ end
392
+
393
+ it "should try and render a before block as a local partial if no before blocks are specified" do
394
+ block = Proc.new {}
395
+ @view.expects(:capture).never
396
+ @view.expects(:render).with("before_my_before_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).once
397
+ @view.expects(:render).with("blocks/before_my_before_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).never
398
+ @builder.use :my_before_block, :value1 => 1, :value2 => 2
399
+ end
400
+
401
+ it "should try and render a before block as a global partial if no after blocks are specified and the local partial does not exist" do
402
+ block = Proc.new {}
403
+ @view.expects(:capture).never
404
+ @view.expects(:render).with("before_my_before_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
405
+ @view.expects(:render).with("blocks/before_my_before_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).once
406
+ @builder.use :my_before_block, :value1 => 1, :value2 => 2
407
+ end
408
+
409
+ it "should override hash options for before blocks by merging the runtime options into the before block options into the block options into the global options" do
410
+ block = Proc.new {|options|}
411
+ @builder.global_options.merge!(:param1 => "global level", :param2 => "global level", :param3 => "global level", :param4 => "global level")
412
+ @builder.define(:my_before_block, :param1 => "block level", :param2 => "block level", :param3 => "block level", &block)
413
+ @builder.before(:my_before_block, :param1 => "before block level", :param2 => "before block level", &block)
414
+ @view.expects(:capture).with(:param4 => 'global level', :param1 => 'top level', :templates_folder => 'blocks', :param2 => 'before block level', :param3 => 'block level')
415
+ @builder.use :my_before_block, :param1 => "top level"
416
+ end
417
+ end
418
+
419
+ describe "use method - after blocks" do
420
+ before :each do
421
+ @builder.expects(:render_block).at_least_once
422
+ @builder.expects(:render_before_blocks).at_least_once
423
+ end
424
+
425
+ it "should render after blocks when using a block" do
426
+ block = Proc.new {|value1, value2, options|}
427
+ @builder.after("my_after_block", &block)
428
+ @view.expects(:capture).with(1, 2, :templates_folder => 'blocks', :value3 => 3, :value4 => 4)
429
+ @builder.use :my_after_block, 1, 2, :value3 => 3, :value4 => 4
430
+ end
431
+
432
+ it "should try and render a after block as a local partial if no after blocks are specified" do
433
+ block = Proc.new {}
434
+ @view.expects(:capture).never
435
+ @view.expects(:render).with("after_my_after_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).once
436
+ @view.expects(:render).with("blocks/after_my_after_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).never
437
+ @builder.use :my_after_block, :value1 => 1, :value2 => 2
438
+ end
439
+
440
+ it "should try and render a after block as a global partial if no after blocks are specified and the local partial does not exist" do
441
+ block = Proc.new {}
442
+ @view.expects(:capture).never
443
+ @view.expects(:render).with("after_my_after_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[]))
444
+ @view.expects(:render).with("blocks/after_my_after_block", :templates_folder => 'blocks', :value1 => 1, :value2 => 2).once
445
+ @builder.use :my_after_block, :value1 => 1, :value2 => 2
446
+ end
447
+
448
+ it "should override hash options for after blocks by merging the runtime options into the after block options into the block options into the global options" do
449
+ block = Proc.new {|options|}
450
+ @builder.global_options.merge!(:param1 => "global level", :param2 => "global level", :param3 => "global level", :param4 => "global level")
451
+ @builder.define(:my_after_block, :param1 => "block level", :param2 => "block level", :param3 => "block level", &block)
452
+ @builder.after(:my_after_block, :param1 => "after block level", :param2 => "after block level", &block)
453
+ @view.expects(:capture).with(:param4 => 'global level', :param1 => 'top level', :templates_folder => 'blocks', :param2 => 'after block level', :param3 => 'block level')
454
+ @builder.use :my_after_block, :param1 => "top level"
455
+ end
456
+ end
457
+
458
+ describe "method_missing method" do
459
+ it "should start a new block group if a method is missing" do
460
+ @builder.some_method
461
+ queued_blocks = @builder.block_groups[:some_method]
462
+ queued_blocks.should eql []
463
+ end
80
464
 
81
- @builder.use :test_block, "value5", :option3 => "value3", :option4 => "value4"
465
+ it "should add items to a queue when a new block group is started" do
466
+ @builder.some_method do
467
+ @builder.queue :myblock1
468
+ @builder.queue :myblock2
469
+ end
470
+ @builder.some_method2 do
471
+ @builder.queue :myblock3
472
+ end
473
+ queued_blocks = @builder.block_groups[:some_method]
474
+ queued_blocks.length.should eql 2
475
+ queued_blocks.first.name.should eql :myblock1
476
+ queued_blocks.second.name.should eql :myblock2
477
+ queued_blocks = @builder.block_groups[:some_method2]
478
+ queued_blocks.length.should eql 1
479
+ queued_blocks.first.name.should eql :myblock3
480
+ @builder.queued_blocks.should eql []
82
481
  end
83
482
  end
84
483
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,10 @@ require 'bundler/setup'
3
3
 
4
4
  require 'building-blocks' # and any other gems you need
5
5
 
6
+ def print_hash(hash)
7
+ hash.inject("") { |s, (k, v)| "#{s} #{k}: #{v}." }
8
+ end
9
+
6
10
  RSpec.configure do |config|
7
11
  config.mock_with :mocha
8
12
  # config.mock_with :flexmock
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: 25
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
- - 0
8
- - 1
9
7
  - 1
10
- version: 0.1.1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Hunter
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-27 00:00:00 -05:00
18
+ date: 2012-02-04 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -104,6 +104,34 @@ dependencies:
104
104
  prerelease: false
105
105
  type: :development
106
106
  requirement: *id006
107
+ - !ruby/object:Gem::Dependency
108
+ name: jeweler
109
+ version_requirements: &id007 !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ hash: 3
115
+ segments:
116
+ - 0
117
+ version: "0"
118
+ prerelease: false
119
+ type: :development
120
+ requirement: *id007
121
+ - !ruby/object:Gem::Dependency
122
+ name: jeweler
123
+ version_requirements: &id008 !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ prerelease: false
133
+ type: :development
134
+ requirement: *id008
107
135
  description: ""
108
136
  email: hunterae@gmail.com
109
137
  executables: []
@@ -119,7 +147,7 @@ files:
119
147
  - lib/building-blocks.rb
120
148
  - lib/building_blocks/base.rb
121
149
  - lib/building_blocks/container.rb
122
- - lib/building_blocks/helper_methods.rb
150
+ - lib/building_blocks/view_additions.rb
123
151
  - rails/init.rb
124
152
  - spec/building-blocks/base_spec.rb
125
153
  - spec/spec_helper.rb
@@ -1,7 +0,0 @@
1
- module BuildingBlocks
2
- module HelperMethods
3
- def blocks
4
- @blocks ||= BuildingBlocks::Base.new(self)
5
- end
6
- end
7
- end