1
0
Fork 0
mirror of https://github.com/sinatra/sinatra synced 2023-03-27 23:18:01 -04:00

play nice if yield_content or content_for is called from outside a template

This commit is contained in:
Konstantin Haase 2011-04-26 11:05:14 +02:00
parent 17a59f64a0
commit 14a1613013
3 changed files with 179 additions and 45 deletions

View file

@ -14,16 +14,18 @@ module Sinatra
} }
def capture(*args, &block) def capture(*args, &block)
@capture = nil
if current_engine == :ruby if current_engine == :ruby
block[*args] result = block[*args]
else else
eval '_buf.try(:clear) if defined? _buf', block.binding clean_up = eval '_buf, @_buf_was = "", _buf if defined?(_buf)', block.binding
dummy = DUMMIES[Tilt[current_engine]] || DUMMIES.fetch(current_engine) dummy = DUMMIES[Tilt[current_engine]] || DUMMIES.fetch(current_engine)
@capture = nil options = { :layout => false, :locals => {:args => args, :block => block }}
result = render(current_engine, dummy, {}, {:args => args, :block => block}, &block) result = render(current_engine, dummy, options, &block)
result = @capture if result.strip.empty? and @capture
result
end end
result.strip.empty? && @capture ? @capture : result
ensure
eval '_buf = @_buf_was if defined?(_buf)', block.binding if clean_up
end end
def capture_later(&block) def capture_later(&block)

View file

@ -73,7 +73,7 @@ module Sinatra
@current_engine == :creole @current_engine == :creole
end end
def call!(env) def initialize(*)
@current_engine = :ruby @current_engine = :ruby
super super
end end

View file

@ -2,64 +2,196 @@ require 'backports'
require_relative 'spec_helper' require_relative 'spec_helper'
describe Sinatra::ContentFor do describe Sinatra::ContentFor do
subject do
Sinatra.new do
helpers Sinatra::ContentFor
set :views, File.expand_path("../content_for", __FILE__)
end.new!
end
extend Forwardable
def_delegators :subject, :content_for, :yield_content
def render(engine, template)
subject.send(:render, engine, template, :layout => false).gsub(/\s/, '')
end
describe "without templates" do
it 'renders blocks declared with the same key you use when rendering' do
content_for(:foo) { "foo" }
yield_content(:foo).should == "foo"
end
it 'renders blocks more than once' do
content_for(:foo) { "foo" }
3.times { yield_content(:foo).should == "foo" }
end
it 'does not render a block with a different key' do
content_for(:bar) { "bar" }
yield_content(:foo).should be_empty
end
it 'renders multiple blocks with the same key' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
yield_content(:foo).should == "foobarbaz"
end
it 'renders multiple blocks more than once' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
3.times { yield_content(:foo).should == "foobarbaz" }
end
it 'passes values to the blocks' do
content_for(:foo) { |a| a.upcase }
yield_content(:foo, 'a').should == "A"
yield_content(:foo, 'b').should == "B"
end
end
# TODO: liquid radius markaby builder nokogiri # TODO: liquid radius markaby builder nokogiri
engines = %w[erb erubis haml slim] engines = %w[erb erubis haml slim]
engines.each do |inner| engines.each do |inner|
engines.each do |outer| describe inner.capitalize do
describe "#{inner.capitalize} templates with #{outer.capitalize} layouts" do before :all do
def body begin
super.gsub(/\s/, '') require inner
end rescue LoadError => e
pending "Skipping: " << e.message
before :all do
begin
require inner
require outer
rescue LoadError => e
pending "Skipping: " << e.message
end
end
before do
mock_app do
helpers Sinatra::ContentFor
set inner, :layout_engine => outer
set :views, File.expand_path("../content_for", __FILE__)
get('/:view') { send(inner, params[:view].to_sym) }
get('/:layout/:view') do
send inner, params[:view].to_sym, :layout => params[:layout].to_sym
end
end
end end
end
describe "with yield_content in Ruby" do
it 'renders blocks declared with the same key you use when rendering' do it 'renders blocks declared with the same key you use when rendering' do
get('/same_key').should be_ok render inner, :same_key
body.should == "foo" yield_content(:foo).strip.should == "foo"
end end
it 'renders blocks more than once' do it 'renders blocks more than once' do
get('/multiple_yields/same_key').should be_ok render inner, :same_key
body.should == "foofoofoo" 3.times { yield_content(:foo).strip.should == "foo" }
end end
it 'does not render a block with a different key' do it 'does not render a block with a different key' do
get('/different_key').should be_ok render inner, :different_key
body.should == "" yield_content(:foo).should be_empty
end end
it 'renders multiple blocks with the same key'do it 'renders multiple blocks with the same key' do
get('/multiple_blocks').should be_ok render inner, :multiple_blocks
body.should == "foobarbaz" yield_content(:foo).gsub(/\s/, '').should == "foobarbaz"
end end
it 'renders multiple blocks more than once' do it 'renders multiple blocks more than once' do
get('/multiple_yields/multiple_blocks').should be_ok render inner, :multiple_blocks
body.should == "foobarbazfoobarbazfoobarbaz" 3.times { yield_content(:foo).gsub(/\s/, '').should == "foobarbaz" }
end end
it 'passes values to the blocks' do it 'passes values to the blocks' do
get('/passes_values/takes_values').should be_ok render inner, :takes_values
body.should == "<i>1</i>2" yield_content(:foo, 1, 2).gsub(/\s/, '').should == "<i>1</i>2"
end
end
describe "with content_for in Ruby" do
it 'renders blocks declared with the same key you use when rendering' do
content_for(:foo) { "foo" }
render(inner, :layout).should == "foo"
end
it 'renders blocks more than once' do
content_for(:foo) { "foo" }
render(inner, :multiple_yields).should == "foofoofoo"
end
it 'does not render a block with a different key' do
content_for(:bar) { "foo" }
render(inner, :layout).should be_empty
end
it 'renders multiple blocks with the same key' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
render(inner, :layout).should == "foobarbaz"
end
it 'renders multiple blocks more than once' do
content_for(:foo) { "foo" }
content_for(:foo) { "bar" }
content_for(:bar) { "WON'T RENDER ME" }
content_for(:foo) { "baz" }
render(inner, :multiple_yields).should == "foobarbazfoobarbazfoobarbaz"
end
it 'passes values to the blocks' do
content_for(:foo) { |a,b| "<i>#{a}</i>#{b}" }
render(inner, :passes_values).should == "<i>1</i>2"
end
end
engines.each do |outer|
describe "with yield_content in #{outer.capitalize}" do
def body
last_response.body.gsub(/\s/, '')
end
before :all do
begin
require outer
rescue LoadError => e
pending "Skipping: " << e.message
end
end
before do
mock_app do
helpers Sinatra::ContentFor
set inner, :layout_engine => outer
set :views, File.expand_path("../content_for", __FILE__)
get('/:view') { send(inner, params[:view].to_sym) }
get('/:layout/:view') do
send inner, params[:view].to_sym, :layout => params[:layout].to_sym
end
end
end
it 'renders blocks declared with the same key you use when rendering' do
get('/same_key').should be_ok
body.should == "foo"
end
it 'renders blocks more than once' do
get('/multiple_yields/same_key').should be_ok
body.should == "foofoofoo"
end
it 'does not render a block with a different key' do
get('/different_key').should be_ok
body.should be_empty
end
it 'renders multiple blocks with the same key' do
get('/multiple_blocks').should be_ok
body.should == "foobarbaz"
end
it 'renders multiple blocks more than once' do
get('/multiple_yields/multiple_blocks').should be_ok
body.should == "foobarbazfoobarbazfoobarbaz"
end
it 'passes values to the blocks' do
get('/passes_values/takes_values').should be_ok
body.should == "<i>1</i>2"
end
end end
end end
end end