mirror of
https://github.com/sinatra/sinatra
synced 2023-03-27 23:18:01 -04:00
Builder Rendering Helper (.builder templates) w/ doco and tests.
This commit is contained in:
parent
327c6ece36
commit
caf4857024
6 changed files with 200 additions and 1 deletions
|
@ -406,6 +406,97 @@ module Sinatra
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generating conservative XML content using Builder templates.
|
||||||
|
#
|
||||||
|
# Builder templates can be inline by passing a block to the builder method, or in
|
||||||
|
# external files with +.builder+ extension by passing the name of the template
|
||||||
|
# to the +builder+ method as a Symbol.
|
||||||
|
#
|
||||||
|
# === Inline Rendering
|
||||||
|
#
|
||||||
|
# If the builder method is given a block, the block is called directly with an
|
||||||
|
# +XmlMarkup+ instance and the result is returned as String:
|
||||||
|
# get '/who.xml' do
|
||||||
|
# builder do |xml|
|
||||||
|
# xml.instruct!
|
||||||
|
# xml.person do
|
||||||
|
# xml.name "Francis Albert Sinatra",
|
||||||
|
# :aka => "Frank Sinatra"
|
||||||
|
# xml.email 'frank@capitolrecords.com'
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Yields the following XML:
|
||||||
|
# <?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
# <person>
|
||||||
|
# <name aka='Frank Sinatra'>Francis Albert Sinatra</name>
|
||||||
|
# <email>Frank Sinatra</email>
|
||||||
|
# </person>
|
||||||
|
#
|
||||||
|
# === Builder Template Files
|
||||||
|
#
|
||||||
|
# Builder templates can be stored in separate files with a +.builder+
|
||||||
|
# extension under the view path. An +XmlMarkup+ object named +xml+ is automatically
|
||||||
|
# made available to template.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# get '/bio.xml' do
|
||||||
|
# builder :bio
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# The "views/bio.builder" file might contain the following:
|
||||||
|
# xml.instruct! :xml, :version => '1.1'
|
||||||
|
# xml.person do
|
||||||
|
# xml.name "Francis Albert Sinatra"
|
||||||
|
# xml.aka "Frank Sinatra"
|
||||||
|
# xml.aka "Ol' Blue Eyes"
|
||||||
|
# xml.aka "The Chairman of the Board"
|
||||||
|
# xml.born 'date' => '1915-12-12' do
|
||||||
|
# xml.text! "Hoboken, New Jersey, U.S.A."
|
||||||
|
# end
|
||||||
|
# xml.died 'age' => 82
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# And yields the following output:
|
||||||
|
# <?xml version='1.1' encoding='UTF-8'?>
|
||||||
|
# <person>
|
||||||
|
# <name>Francis Albert Sinatra</name>
|
||||||
|
# <aka>Frank Sinatra</aka>
|
||||||
|
# <aka>Ol' Blue Eyes</aka>
|
||||||
|
# <aka>The Chairman of the Board</aka>
|
||||||
|
# <born date='1915-12-12'>Hoboken, New Jersey, U.S.A.</born>
|
||||||
|
# <died age='82' />
|
||||||
|
# </person>
|
||||||
|
#
|
||||||
|
# NOTE: Builder must be installed or a LoadError will be raised the first time an
|
||||||
|
# attempt is made to render a builder template.
|
||||||
|
#
|
||||||
|
# See http://builder.rubyforge.org/ for comprehensive documentation on Builder.
|
||||||
|
module Builder
|
||||||
|
|
||||||
|
def builder(content=nil, options={}, &block)
|
||||||
|
options, content = content, nil if content.is_a?(Hash)
|
||||||
|
content = Proc.new { block } if content.nil?
|
||||||
|
render(:builder, content, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def render_builder(content, &b)
|
||||||
|
require 'builder'
|
||||||
|
xml = ::Builder::XmlMarkup.new(:indent => 2)
|
||||||
|
case content
|
||||||
|
when String
|
||||||
|
eval(content, binding, '<BUILDER>', 1)
|
||||||
|
when Proc
|
||||||
|
content.call(xml)
|
||||||
|
end
|
||||||
|
xml.target!
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
class EventContext
|
class EventContext
|
||||||
|
|
||||||
include ResponseHelpers
|
include ResponseHelpers
|
||||||
|
@ -413,6 +504,7 @@ module Sinatra
|
||||||
include RenderingHelpers
|
include RenderingHelpers
|
||||||
include Erb
|
include Erb
|
||||||
include Haml
|
include Haml
|
||||||
|
include Builder
|
||||||
|
|
||||||
attr_accessor :request, :response
|
attr_accessor :request, :response
|
||||||
|
|
||||||
|
|
101
test/builder_test.rb
Normal file
101
test/builder_test.rb
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
require File.dirname(__FILE__) + '/helper'
|
||||||
|
|
||||||
|
context "Builder" do
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Sinatra.application = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
context "without layouts" do
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Sinatra.application = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "should render" do
|
||||||
|
|
||||||
|
get '/no_layout' do
|
||||||
|
builder 'xml.instruct!'
|
||||||
|
end
|
||||||
|
|
||||||
|
get_it '/no_layout'
|
||||||
|
should.be.ok
|
||||||
|
body.should == %(<?xml version="1.0" encoding="UTF-8"?>\n)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "should render inline block" do
|
||||||
|
|
||||||
|
get '/no_layout_and_inlined' do
|
||||||
|
@name = "Frank & Mary"
|
||||||
|
builder do |xml|
|
||||||
|
xml.couple @name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
get_it '/no_layout_and_inlined'
|
||||||
|
should.be.ok
|
||||||
|
body.should == %(<couple>Frank & Mary</couple>\n)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
context "Templates (in general)" do
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Sinatra.application = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "are read from files if Symbols" do
|
||||||
|
|
||||||
|
get '/from_file' do
|
||||||
|
@name = 'Blue'
|
||||||
|
builder :foo, :views_directory => File.dirname(__FILE__) + "/views"
|
||||||
|
end
|
||||||
|
|
||||||
|
get_it '/from_file'
|
||||||
|
should.be.ok
|
||||||
|
body.should.equal %(<exclaim>You rock Blue!</exclaim>\n)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "use layout.ext by default if available" do
|
||||||
|
|
||||||
|
get '/' do
|
||||||
|
builder :foo, :views_directory => File.dirname(__FILE__) + "/views/layout_test"
|
||||||
|
end
|
||||||
|
|
||||||
|
get_it '/'
|
||||||
|
should.be.ok
|
||||||
|
body.should.equal "<layout>\n<this>is foo!</this>\n</layout>\n"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "renders without layout" do
|
||||||
|
|
||||||
|
get '/' do
|
||||||
|
builder :no_layout, :views_directory => File.dirname(__FILE__) + "/views/no_layout"
|
||||||
|
end
|
||||||
|
|
||||||
|
get_it '/'
|
||||||
|
should.be.ok
|
||||||
|
body.should.equal "<foo>No Layout!</foo>\n"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "raises error if template not found" do
|
||||||
|
|
||||||
|
get '/' do
|
||||||
|
builder :not_found
|
||||||
|
end
|
||||||
|
|
||||||
|
lambda { get_it '/' }.should.raise(Errno::ENOENT)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
1
test/views/foo.builder
Normal file
1
test/views/foo.builder
Normal file
|
@ -0,0 +1 @@
|
||||||
|
xml.exclaim "You rock #{@name}!"
|
1
test/views/layout_test/foo.builder
Normal file
1
test/views/layout_test/foo.builder
Normal file
|
@ -0,0 +1 @@
|
||||||
|
xml.this "is foo!"
|
3
test/views/layout_test/layout.builder
Normal file
3
test/views/layout_test/layout.builder
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
xml.layout do
|
||||||
|
xml << yield
|
||||||
|
end
|
1
test/views/no_layout/no_layout.builder
Normal file
1
test/views/no_layout/no_layout.builder
Normal file
|
@ -0,0 +1 @@
|
||||||
|
xml.foo "No Layout!"
|
Loading…
Reference in a new issue