Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Rendering refactoring with layouts

  • Loading branch information...
commit ca5f8f35cb5636ae2d7686a3c265ecfa8a7426bc 1 parent e1b03fb
Blake Mizerany authored
View
72 lib/sinatra/context.rb
@@ -0,0 +1,72 @@
+require File.dirname(__FILE__) + '/context/renderer'
+
+module Sinatra
+
+ class EventContext
+
+ cattr_accessor :logger
+ attr_reader :request
+
+ include Sinatra::Renderer
+
+ def initialize(request)
+ @request = request
+ @headers = {}
+ end
+
+ def status(value = nil)
+ @status = value if value
+ @status || 200
+ end
+
+ def body(value = nil, &block)
+ @body = value if value
+ @body = block.call if block
+ @body
+ end
+
+ def error(value = nil)
+ if value
+ status 500
+ @error = value
+ erb :error, :views_directory => SINATRA_ROOT + '/files/'
+ end
+ @error
+ end
+
+ # This allows for:
+ # header 'Content-Type' => 'text/html'
+ # header 'Foo' => 'Bar'
+ # or
+ # headers 'Content-Type' => 'text/html',
+ # 'Foo' => 'Bar'
+ #
+ # Whatever blows your hair back
+ def headers(value = nil)
+ @headers.merge!(value) if value
+ @headers
+ end
+ alias :header :headers
+
+ def session
+ request.env['rack.session']
+ end
+
+ def params
+ @params ||= @request.params.symbolize_keys
+ end
+
+ def redirect(path)
+ logger.info "Redirecting to: #{path}"
+ status 302
+ header 'Location' => path
+ end
+
+ def log_event
+ logger.info "#{request.request_method} #{request.path_info} | Status: #{status} | Params: #{params.inspect}"
+ logger.exception(error) if error
+ end
+
+ end
+
+end
View
38 lib/sinatra/context/renderer.rb
@@ -0,0 +1,38 @@
+Layouts = Hash.new
+
+module Sinatra
+
+ module Renderer
+
+ DEFAULT_OPTIONS = {
+ :views_directory => 'views',
+ :layout => :layout
+ }
+
+ def render(template, renderer, options = {})
+ options = DEFAULT_OPTIONS.merge(options)
+
+ layout = block_given? ? yield : Layouts[options[:layout]]
+
+ result_method = 'render_%s' % renderer
+
+ if layout
+ send(result_method, layout) { send(result_method, determine_template(template, renderer, options)) }
+ else
+ send(result_method, determine_template(template, renderer, options))
+ end
+ end
+
+ protected
+
+ def determine_template(template, ext, options)
+ if template.is_a?(Symbol)
+ File.read("%s/%s.%s" % [options[:views_directory], template, ext])
+ else
+ template
+ end
+ end
+
+ end
+
+end
View
15 lib/sinatra/core_ext/metaid.rb
@@ -0,0 +1,15 @@
+class Object
+ # The hidden singleton lurks behind everyone
+ def metaclass; class << self; self; end; end
+ def meta_eval &blk; metaclass.instance_eval &blk; end
+
+ # Adds methods to a metaclass
+ def meta_def name, &blk
+ meta_eval { define_method name, &blk }
+ end
+
+ # Defines an instance method within a class
+ def class_def name, &blk
+ class_eval { define_method name, &blk }
+ end
+end
View
85 lib/sinatra/event.rb
@@ -28,98 +28,17 @@ def present_error
def not_found
Event.new(:get, 'not_found', false) do
status 404
- views_dir SINATRA_ROOT + '/files'
if request.path_info == '/' && request.request_method == 'GET'
- erb :default_index
+ erb :default_index, :views_directory => SINATRA_ROOT + '/files'
else
- erb :not_found
+ erb :not_found, :views_directory => SINATRA_ROOT + '/files'
end
end
end
end
-
- class EventContext
-
- cattr_accessor :logger
-
- attr_reader :request
-
- def initialize(request)
- @request = request
- @headers = {}
- end
-
- def status(value = nil)
- @status = value if value
- @status || 200
- end
- def body(value = nil, &block)
- @body = value if value
- @body = block.call if block
- @body
- end
-
- def error(value = nil)
- if value
- status 500
- @error = value
- views_dir SINATRA_ROOT + '/files/'
- erb :error
- end
- @error
- end
-
- # This allows for:
- # header 'Content-Type' => 'text/html'
- # header 'Foo' => 'Bar'
- # or
- # headers 'Content-Type' => 'text/html',
- # 'Foo' => 'Bar'
- #
- # Whatever blows your hair back
- def headers(value = nil)
- @headers.merge!(value) if value
- @headers
- end
- alias :header :headers
-
- def session
- request.env['rack.session']
- end
-
- def params
- @params ||= @request.params.symbolize_keys
- end
-
- def views_dir(value = nil)
- @views_dir = value if value
- @views_dir || File.dirname($0) + '/views'
- end
-
- def redirect(path)
- logger.info "Redirecting to: #{path}"
- status 302
- header 'Location' => path
- end
-
- def determine_template(content, ext)
- if content.is_a?(Symbol)
- File.read("%s/%s.%s" % [views_dir, content, ext])
- else
- content
- end
- end
-
- def log_event
- logger.info "#{request.request_method} #{request.path_info} | Status: #{status} | Params: #{params.inspect}"
- logger.exception(error) if error
- end
-
- end
-
class Event
cattr_accessor :logger
View
47 test/sinatra/renderer_test.rb
@@ -0,0 +1,47 @@
+require File.dirname(__FILE__) + '/../helper'
+
+class Sinatra::EventContext
+
+ def render_foo(template)
+ require 'erb'
+ ERB.new(template).result(binding)
+ end
+
+end
+
+describe "Renderer" do
+
+ before(:each) do
+ Layouts.clear
+ @context = Sinatra::EventContext.new(stub())
+ end
+
+ it "should render render a tempalate" do
+ @context.render('foo', :foo).should.equal 'foo'
+ end
+
+ it "should render with a layout if given" do
+ result = @context.render('content', :foo) do
+ 'X <%= yield %> X'
+ end
+
+ result.should.equal 'X content X'
+ end
+
+ it "should render default layout if it exists and layout if no layout name given" do
+ Layouts[:layout] = 'X <%= yield %> Y'
+ @context.render('foo', :foo).should.equal 'X foo Y'
+
+ Layouts[:foo] = 'Foo <%= yield %> Layout'
+ @context.render('bar', :foo, :layout => :foo).should.equal 'Foo bar Layout'
+ end
+
+ it "should read template from a file if exists" do
+ File.expects(:read).with('views/bar.foo').returns('foo content')
+ @context.render(:bar, :foo).should.equal 'foo content'
+
+ File.expects(:read).with('views2/bar.foo').returns('foo content')
+ @context.render(:bar, :foo, :views_directory => 'views2').should.equal 'foo content'
+ end
+
+end
View
2  vendor/erb/init.rb
@@ -1,3 +1,3 @@
require File.dirname(__FILE__) + '/lib/erb'
-Sinatra::EventContext.send(:include, Sinatra::Erb::InstanceMethods)
+Sinatra::EventContext.send(:include, Sinatra::Erb::EventContext)
View
9 vendor/erb/lib/erb.rb
@@ -2,13 +2,16 @@ module Sinatra
module Erb
- module InstanceMethods
+ module EventContext
- def erb(content)
+ def render_erb(content)
require 'erb'
- body ERB.new(determine_template(content, :erb)).result(binding)
+ body ERB.new(content).result(binding)
end
+ def erb(template, options = {}, &layout)
+ render(template, :erb, options, &layout)
+ end
end
end
View
2  vendor/haml/init.rb
@@ -1,3 +1,3 @@
require File.dirname(__FILE__) + '/lib/haml'
-Sinatra::EventContext.send(:include, Sinatra::Haml::InstanceMethods)
+Sinatra::EventContext.send(:include, Sinatra::Haml::EventContext)
View
11 vendor/haml/lib/haml.rb
@@ -2,13 +2,16 @@ module Sinatra
module Haml
- module InstanceMethods
+ module EventContext
- def haml(content)
- require 'haml'
- body ::Haml::Engine.new(determine_template(content, :haml)).render(self)
+ def render_haml(content)
+ require 'haml'
+ body ::Haml::Engine.new(content).render(self)
end
+ def haml(template, options = {}, &layout)
+ render(template, :haml, options, &layout)
+ end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.