require "spec_helper" describe Blocks::Base do before :each do @view = ActionView::Base.new @builder = Blocks::Base.new(@view) end it "should be able change the default global partials directory" do Blocks.template_folder = "shared" Blocks.use_partials = true @builder = Blocks::Base.new(@view) @builder.expects(:render_before_blocks).at_least_once @builder.expects(:render_after_blocks).at_least_once @view.expects(:capture).with(:value1 => 1, :value2 => 2).never @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[])) @view.expects(:render).with("shared/some_block", :value1 => 1, :value2 => 2).once @builder.render :some_block, :value1 => 1, :value2 => 2 end describe "defined? method" do it "should be able to determine if a block by a specific name is already defined" do @builder.defined?(:test_block).should be_false @builder.define :test_block do end @builder.defined?(:test_block).should be_true end it "should not care whether the block name was defined with a string or a symbol" do @builder.defined?(:test_block).should be_false @builder.define "test_block" do end @builder.defined?(:test_block).should be_true @builder.defined?(:test_block2).should be_false @builder.define :test_block2 do end @builder.defined?(:test_block2).should be_true end it "should not care whether the defined? method is passed a string or a symbol" do @builder.defined?("test_block").should be_false @builder.define :test_block do end @builder.defined?("test_block").should be_true end end describe "define method" do it "should be able to define a new block" do block = Proc.new { |options| } @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block test_block = @builder.blocks[:test_block] test_block.options[:option1].should eql("value1") test_block.options[:option2].should eql("value2") test_block.name.should eql(:test_block) test_block.block.should eql(block) end it "should not replace a defined block with another attempted definition" do block1 = Proc.new do |options| end @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block1 block2 = Proc.new do |options| end @builder.define :test_block, :option3 => "value3", :option4 => "value4", &block2 test_block = @builder.blocks[:test_block] test_block.options[:option1].should eql("value1") test_block.options[:option2].should eql("value2") test_block.options[:option3].should be_nil test_block.options[:option4].should be_nil test_block.name.should eql(:test_block) test_block.block.should eql(block1) end end describe "replace method" do it "should be able to replace a defined block" do block1 = Proc.new do |options| end @builder.define :test_block, :option1 => "value1", :option2 => "value2", &block1 block2 = Proc.new do |options| end @builder.replace :test_block, :option3 => "value3", :option4 => "value4", &block2 test_block = @builder.blocks[:test_block] test_block.options[:option1].should be_nil test_block.options[:option2].should be_nil test_block.options[:option3].should eql("value3") test_block.options[:option4].should eql("value4") test_block.name.should eql(:test_block) test_block.block.should eql(block2) end end describe "before method" do it "should be aliased with prepend" do block = Proc.new { |options| } @builder.prepend :some_block, &block @builder.blocks[:before_some_block].should be_present end it "should defined before blocks as the block name with the word 'before_' prepended to it" do block = Proc.new { |options| } @builder.before :some_block, &block @builder.blocks[:before_some_block].should be_present end it "should store a before block in an array" do block = Proc.new { |options| } @builder.before :some_block, &block before_blocks = @builder.blocks[:before_some_block] before_blocks.should be_a(Array) end it "should store a before block as a Blocks::Container" do block = Proc.new { |options| } @builder.before :some_block, :option1 => "some option", &block before_blocks = @builder.blocks[:before_some_block] block_container = before_blocks.first block_container.should be_a(Blocks::Container) block_container.options.should eql :option1 => "some option" block_container.block.should eql block end it "should queue before blocks if there are multiple defined" do block = Proc.new { |options| } block2 = Proc.new { |options| } @builder.before :some_block, &block @builder.before :some_block, &block2 before_blocks = @builder.blocks[:before_some_block] before_blocks.length.should eql 2 end it "should store before blocks in the order in which they are defined" do block = Proc.new { |options| } block2 = Proc.new { |options| } block3 = Proc.new { |options| } @builder.before :some_block, &block @builder.before :some_block, &block2 @builder.before :some_block, &block3 before_blocks = @builder.blocks[:before_some_block] before_blocks.first.block.should eql block before_blocks.second.block.should eql block2 before_blocks.third.block.should eql block3 end end describe "after method" do it "should be aliased with append and for" do block = Proc.new { |options| } @builder.append :some_block, &block @builder.blocks[:after_some_block].should be_present block = Proc.new { |options| } @builder.for :some_block, &block @builder.blocks[:after_some_block].should be_present end it "should defined after blocks as the block name with the word 'after_' prepended to it" do block = Proc.new { |options| } @builder.after :some_block, &block @builder.blocks[:after_some_block].should be_present end it "should store a after block in an array" do block = Proc.new { |options| } @builder.after :some_block, &block after_blocks = @builder.blocks[:after_some_block] after_blocks.should be_a(Array) end it "should store a after block as a Blocks::Container" do block = Proc.new { |options| } @builder.after :some_block, :option1 => "some option", &block after_blocks = @builder.blocks[:after_some_block] block_container = after_blocks.first block_container.should be_a(Blocks::Container) block_container.options.should eql :option1 => "some option" block_container.block.should eql block end it "should queue after blocks if there are multiple defined" do block = Proc.new { |options| } block2 = Proc.new { |options| } @builder.after :some_block, &block @builder.after :some_block, &block2 after_blocks = @builder.blocks[:after_some_block] after_blocks.length.should eql 2 end it "should store after blocks in the order in which they are defined" do block = Proc.new { |options| } block2 = Proc.new { |options| } block3 = Proc.new { |options| } @builder.after :some_block, &block @builder.after :some_block, &block2 @builder.after :some_block, &block3 after_blocks = @builder.blocks[:after_some_block] after_blocks.first.block.should eql block after_blocks.second.block.should eql block2 after_blocks.third.block.should eql block3 end end describe "render method" do it "should alias the render method as use" do block = Proc.new {"output"} @builder.define :some_block, &block @builder.use(:some_block).should eql "output" end it "should be able to use a defined block by its name" do block = Proc.new {"output"} @builder.define :some_block, &block @builder.render(:some_block).should eql "output" end it "should automatically pass in an options hash to a defined block that takes one paramter when that block is used" do block = Proc.new {|options| "Options are #{options.inspect}"} @builder.define :some_block, &block @builder.render(:some_block).should eql "Options are {}" end it "should be able to use a defined block by its name and pass in runtime arguments as a hash" do block = Proc.new do |options| print_hash(options) end @builder.define :some_block, &block @builder.render(:some_block, :param1 => 1, :param2 => "value2").should eql print_hash(:param1 => 1, :param2 => "value2") end it "should be able to use a defined block by its name and pass in runtime arguments one by one" do block = Proc.new do |first_param, second_param, options| "first_param: #{first_param}, second_param: #{second_param}, #{print_hash options}" end @builder.define :some_block, &block @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql("first_param: 3, second_param: 4, #{print_hash(:param1 => 1, :param2 => "value2")}") end it "should match up the number of arguments to a defined block with the parameters passed when a block is used" do block = Proc.new {|first_param| "first_param = #{first_param}"} @builder.define :some_block, &block @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql "first_param = 3" block = Proc.new {|first_param, second_param| "first_param = #{first_param}, second_param = #{second_param}"} @builder.replace :some_block, &block @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql "first_param = 3, second_param = 4" block = Proc.new do |first_param, second_param, options| "first_param: #{first_param}, second_param: #{second_param}, #{print_hash options}" end @builder.replace :some_block, &block @builder.render(:some_block, 3, 4, :param1 => 1, :param2 => "value2").should eql("first_param: 3, second_param: 4, #{print_hash(:param1 => 1, :param2 => "value2")}") end it "should not render anything if using a block that has been defined" do @builder.use_partials = true @view.expects(:capture).never @view.expects(:render).with("some_block", {}).raises(ActionView::MissingTemplate.new([],[],[],[],[])) @view.expects(:render).with("blocks/some_block", {}).raises(ActionView::MissingTemplate.new([],[],[],[],[])) @builder.render :some_block end it "should first attempt to capture a block's contents when blocks.render is called" do block = Proc.new {|options|} @view.expects(:capture).with(:value1 => 1, :value2 => 2) @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).never @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never @builder.define :some_block, &block @builder.render :some_block, :value1 => 1, :value2 => 2 end it "should second attempt to render a local partial by the block's name when blocks.render is called" do @builder.use_partials = true @view.expects(:capture).with(:value1 => 1, :value2 => 2).never @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).once @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never @builder.render :some_block, :value1 => 1, :value2 => 2 end it "should third attempt to render a global partial by the block's name when blocks.render is called" do @builder.use_partials = true @view.expects(:capture).with(:value1 => 1, :value2 => 2).never @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[])) @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).once @builder.render :some_block, :value1 => 1, :value2 => 2 end it "should fourth attempt to render a default block when blocks.render is called" do block = Proc.new {|options|} @builder.use_partials = true @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[])) @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).raises(ActionView::MissingTemplate.new([],[],[],[],[])) @view.expects(:capture).with(:value1 => 1, :value2 => 2) @builder.render :some_block, :value1 => 1, :value2 => 2, &block end it "should not attempt to render a partial if use_partials is set to false" do @builder.use_partials = false block = Proc.new {|options|} @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).never @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never @view.expects(:capture).with(:value1 => 1, :value2 => 2) @builder.render :some_block, :value1 => 1, :value2 => 2, &block end it "should not attempt to render a partial if use_partials is passed in as false as an option to Blocks::Base.new" do mocha_teardown @builder = Blocks::Base.new(@view, :use_partials => false) @builder.expects(:render_before_blocks).at_least_once @builder.expects(:render_after_blocks).at_least_once block = Proc.new {|options|} @view.expects(:render).with("some_block", :value1 => 1, :value2 => 2).never @view.expects(:render).with("blocks/some_block", :value1 => 1, :value2 => 2).never @view.expects(:capture).with(:value1 => 1, :value2 => 2) @builder.render :some_block, :value1 => 1, :value2 => 2, &block end it "should override hash options for a block by merging the runtime options into the define default options into the queue level options into the global options" do block = Proc.new {|options|} @builder.global_options.merge!(:param1 => "global level", :param2 => "global level", :param3 => "global level", :param4 => "global level") block_container = @builder.send(:define_block_container, :my_before_block, :param1 => "queue level", :param2 => "queue level") @builder.define(:my_before_block, :param1 => "define level", :param2 => "define level", :param3 => "define level", &block) @view.expects(:capture).with(:param1 => 'use level', :param2 => 'queue level', :param3 => 'define level', :param4 => 'global level') @builder.render block_container, :param1 => "use level" end it "should render the contents of a defined block when that block is used" do block = Proc.new {} @view.expects(:capture).with(nil).returns("rendered content") @builder.define :some_block, &block buffer = @builder.render :some_block buffer.should eql "rendered content" end it "should be able to render an element surrounding the block" do block = Proc.new {} @view.expects(:capture).with(nil).returns("rendered content") @builder.define :some_block, &block buffer = @builder.render :some_block, :wrap_with => {:tag => "span", :id => "my-id"} buffer.should eql "rendered content" end describe "with a collection passed in" do it "should render a block for each element of the collection with the name of the block used as the name of the element passed into the block" do block = Proc.new {|item, options| "output#{options[:some_block]} "} @builder.define :some_block, &block @builder.render(:some_block, :collection => [1,2,3]).should eql "output1 output2 output3 " end it "should render a block for each element of the collection with the 'as' option specifying the name of the element passed into the block" do block = Proc.new {|item, options| "output#{options[:my_block_name]} "} @builder.define :some_block, &block @builder.render(:some_block, :collection => [1,2,3], :as => "my_block_name").should eql "output1 output2 output3 " end it "should render a block for each element of the collection with a surrounding element if that option is specified" do block = Proc.new {|item, options| "output#{options[:my_block_name]} "} @builder.define :some_block, &block @builder.render(:some_block, :collection => [1,2,3], :wrap_each => {:tag => "div"}).should eql "