don't rely on template engine internals to capture a block, makes yield_content usage consistent in erb and haml, allows combining the two

This commit is contained in:
Konstantin Haase 2011-03-28 16:06:17 +02:00
parent 7fa95253e3
commit 7e72a34a3a
4 changed files with 30 additions and 26 deletions

View File

@ -9,7 +9,7 @@ module Sinatra
# <chunk of="html">...</chunk> # <chunk of="html">...</chunk>
# <% end %> # <% end %>
# #
# <% yield_content :some_key %> # <%= yield_content :some_key %>
# #
# This allows you to capture blocks inside views to be rendered later # This allows you to capture blocks inside views to be rendered later
# in this request. For example, to populate different parts of your # in this request. For example, to populate different parts of your
@ -23,12 +23,6 @@ module Sinatra
# #
# = yield_content :some_key # = yield_content :some_key
# #
# <b>Note</b> that with ERB <tt>yield_content</tt> is called <b>without</b>
# an '=' block (<tt><%= %></tt>), but with Haml it uses <tt>= yield_content</tt>.
#
# Using an '=' block in ERB will output the content twice for each block,
# so if you have problems with that, make sure to check for this.
#
# == Usage # == Usage
# #
# If you're writing "classic" style apps, then requring # If you're writing "classic" style apps, then requring
@ -64,14 +58,15 @@ module Sinatra
# Your blocks can also receive values, which are passed to them # Your blocks can also receive values, which are passed to them
# by <tt>yield_content</tt> # by <tt>yield_content</tt>
def content_for(key, &block) def content_for(key, &block)
content_blocks[key.to_sym] << block @current_engine ||= :ruby
content_blocks[key.to_sym] << [@current_engine, block]
end end
# Render the captured blocks for a given key. For example: # Render the captured blocks for a given key. For example:
# #
# <head> # <head>
# <title>Example</title> # <title>Example</title>
# <% yield_content :head %> # <%= yield_content :head %>
# </head> # </head>
# #
# Would render everything you declared with <tt>content_for # Would render everything you declared with <tt>content_for
@ -80,25 +75,38 @@ module Sinatra
# You can also pass values to the content blocks by passing them # You can also pass values to the content blocks by passing them
# as arguments after the key: # as arguments after the key:
# #
# <% yield_content :head, 1, 2 %> # <%= yield_content :head, 1, 2 %>
# #
# Would pass <tt>1</tt> and <tt>2</tt> to all the blocks registered # Would pass <tt>1</tt> and <tt>2</tt> to all the blocks registered
# for <tt>:head</tt>. # for <tt>:head</tt>.
#
# *NOTICE* that you call this without an <tt>=</tt> sign. IE,
# in a <tt><% %></tt> block, and not in a <tt><%= %></tt> block.
def yield_content(key, *args) def yield_content(key, *args)
content_blocks[key.to_sym].map do |content| content_blocks[key.to_sym].map { |e,b| capture(e, args, b) }.join
if respond_to?(:block_is_haml?) && block_is_haml?(content) end
capture_haml(*args, &content)
else def self.capture(name, template = nil)
content.call(*args) @capture ||= {}
end @capture[name] = template if template
end.join @capture[name]
end end
private private
# generated templates will be cached by Sinatra in production
capture :haml, "= capture_haml(*args, &block)"
capture :erb, "<% block.call(*args) %>"
def capture(engine, args, block)
render(engine, Sinatra::ContentFor.capture(engine), {},
:args => args, :block => block)
end
def render(engine, *)
@current_engine, engine_was = engine.to_sym, @current_engine
super
ensure
@current_engine = engine_was
end
def content_blocks def content_blocks
@content_blocks ||= Hash.new {|h,k| h[k] = [] } @content_blocks ||= Hash.new {|h,k| h[k] = [] }
end end

View File

@ -1 +1 @@
<% yield_content :foo %> <%= yield_content :foo %>

View File

@ -1 +1 @@
<% yield_content :foo, 1, 2 %> <%= yield_content :foo, 1, 2 %>

View File

@ -11,10 +11,6 @@ describe Sinatra::ContentFor do
super.gsub(/\s/, '') super.gsub(/\s/, '')
end end
before do
pending "different layout engines not supported yet" unless inner == outer
end
before :all do before :all do
begin begin
require inner require inner