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:
parent
17a59f64a0
commit
14a1613013
3 changed files with 179 additions and 45 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue