lib/sinatra/base.rb in bmizerany-sinatra-0.9.0 vs lib/sinatra/base.rb in bmizerany-sinatra-0.9.0.2
- old
+ new
@@ -2,20 +2,27 @@
require 'uri'
require 'rack'
require 'rack/builder'
module Sinatra
- VERSION = '0.9.0'
+ VERSION = '0.9.0.2'
class Request < Rack::Request
def user_agent
@env['HTTP_USER_AGENT']
end
def accept
@env['HTTP_ACCEPT'].split(',').map { |a| a.strip }
end
+
+ # Override Rack 0.9.x's #params implementation (see #72 in lighthouse)
+ def params
+ self.GET.update(self.POST)
+ rescue EOFError => boom
+ self.GET
+ end
end
class Response < Rack::Response
def initialize
@status, @body = 200, []
@@ -68,11 +75,11 @@
# Halt processing and redirect to the URI provided.
def redirect(uri, *args)
status 302
response['Location'] = uri
- halt *args
+ halt(*args)
end
# Halt processing and return the error status provided.
def error(code, body=nil)
code, body = 500, code.to_str if code.respond_to? :to_str
@@ -133,11 +140,11 @@
end
class StaticFile < ::File #:nodoc:
alias_method :to_path, :path
def each
- while buf = read(8196)
+ while buf = read(8192)
yield buf
end
end
end
@@ -208,10 +215,11 @@
end
end
def lookup_layout(engine, options)
return if options[:layout] == false
+ options.delete(:layout) if options[:layout] == true
template = options[:layout] || :layout
data = lookup_template(engine, template, options)
[template, data]
rescue Errno::ENOENT
nil
@@ -296,14 +304,14 @@
end
attr_accessor :env, :request, :response, :params
def call!(env)
- @env = env
- @request = Request.new(env)
+ @env = env
+ @request = Request.new(env)
@response = Response.new
- @params = nil
+ @params = nil
error_detection { dispatch! }
@response.finish
end
def options
@@ -318,17 +326,20 @@
throw :pass
end
private
def dispatch!
- self.class.filters.each {|block| instance_eval(&block)}
+ self.class.filters.each do |block|
+ res = catch(:halt) { instance_eval(&block) ; :continue }
+ return unless res == :continue
+ end
+
if routes = self.class.routes[@request.request_method]
path = @request.path_info
- original_params = Hash.new{ |hash,k| hash[k.to_s] if Symbol === k }
- original_params.merge! @request.params
+ original_params = nested_params(@request.params)
- routes.each do |pattern, keys, conditions, block|
+ routes.each do |pattern, keys, conditions, method_name|
if pattern =~ path
values = $~.captures.map{|val| val && unescape(val) }
params =
if keys.any?
keys.zip(values).inject({}) do |hash,(k,v)|
@@ -342,26 +353,43 @@
elsif values.any?
{'captures' => values}
else
{}
end
- @params = original_params.dup
- @params.merge!(params)
+ @params = original_params.merge(params)
catch(:pass) {
conditions.each { |cond|
throw :pass if instance_eval(&cond) == false }
- return invoke(block)
+ return invoke(method_name)
}
end
end
end
raise NotFound
end
+ def nested_params(params)
+ return indifferent_hash.merge(params) if !params.keys.join.include?('[')
+ params.inject indifferent_hash do |res, (key,val)|
+ if key =~ /\[.*\]/
+ splat = key.scan(/(^[^\[]+)|\[([^\]]+)\]/).flatten.compact
+ head, last = splat[0..-2], splat[-1]
+ head.inject(res){ |s,v| s[v] ||= indifferent_hash }[last] = val
+ end
+ res
+ end
+ end
+
+ def indifferent_hash
+ Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
+ end
+
def invoke(block)
res = catch(:halt) { instance_eval(&block) }
+ return if res.nil?
+
case
when res.respond_to?(:to_str)
@response.body = [res]
when res.respond_to?(:to_ary)
res = res.to_ary
@@ -377,21 +405,16 @@
raise TypeError, "#{res.inspect} not supported"
end
else
@response.body = res
end
- when res.kind_of?(Symbol) # TODO: deprecate this.
- @response.body = __send__(res)
when res.respond_to?(:each)
@response.body = res
when (100...599) === res
@response.status = res
- when res.nil?
- @response.body = []
- else
- raise TypeError, "#{res.inspect} not supported"
end
+
res
end
def error_detection
errmap = self.class.errors
@@ -402,10 +425,16 @@
@response.body = ['<h1>Not Found</h1>']
handler = errmap[boom.class] || errmap[NotFound]
invoke handler unless handler.nil?
rescue ::Exception => boom
@env['sinatra.error'] = boom
+
+ if options.dump_errors?
+ msg = ["#{boom.class} - #{boom.message}:", *boom.backtrace].join("\n ")
+ @env['rack.errors'] << msg
+ end
+
raise boom if options.raise_errors?
@response.status = 500
invoke errmap[boom.class] || errmap[Exception]
ensure
if @response.status >= 400 && errmap.key?(response.status)
@@ -454,24 +483,33 @@
else
@errors[codes] = block
end
end
+ def not_found(&block)
+ error 404, &block
+ end
+
def template(name, &block)
templates[name] = block
end
def layout(name=:layout, &block)
template name, &block
end
def use_in_file_templates!
- line = caller.detect { |s| s !~ /lib\/sinatra.*\.rb/ &&
- s !~ /\(.*\)/ }
+ line = caller.detect do |s|
+ [
+ /lib\/sinatra.*\.rb/,
+ /\(.*\)/,
+ /rubygems\/custom_require\.rb/
+ ].all? { |x| s !~ x }
+ end
file = line.sub(/:\d+.*$/, '')
if data = ::IO.read(file).split('__END__')[1]
- data.gsub! /\r\n/, "\n"
+ data.gsub!(/\r\n/, "\n")
template = nil
data.each_line do |line|
if line =~ /^@@\s*(.*)/
template = templates[$1.to_sym] = ''
elsif template
@@ -526,11 +564,11 @@
}
end
def get(path, opts={}, &block)
conditions = @conditions.dup
- route 'GET', path, opts, &block
+ route('GET', path, opts, &block)
@conditions = conditions
head(path, opts) { invoke(block) ; [] }
end
@@ -538,19 +576,24 @@
def post(path, opts={}, &bk); route 'POST', path, opts, &bk; end
def delete(path, opts={}, &bk); route 'DELETE', path, opts, &bk; end
def head(path, opts={}, &bk); route 'HEAD', path, opts, &bk; end
private
- def route(method, path, opts={}, &block)
+ def route(verb, path, opts={}, &block)
host_name opts[:host] if opts.key?(:host)
user_agent opts[:agent] if opts.key?(:agent)
accept_mime_types opts[:provides] if opts.key?(:provides)
pattern, keys = compile(path)
conditions, @conditions = @conditions, []
- (routes[method] ||= []).
- push [pattern, keys, conditions, block]
+
+ define_method "#{verb} #{path}", &block
+ unbound_method = instance_method("#{verb} #{path}")
+ block = lambda { unbound_method.bind(self).call }
+
+ (routes[verb] ||= []).
+ push([pattern, keys, conditions, block]).last
end
def compile(path)
keys = []
if path.respond_to? :to_str
@@ -645,10 +688,11 @@
send :define_method, message, &block
end
end
set :raise_errors, true
+ set :dump_errors, false
set :sessions, false
set :logging, false
set :methodoverride, false
set :static, false
set :environment, (ENV['RACK_ENV'] || :development).to_sym
@@ -738,10 +782,11 @@
end
end
class Default < Base
set :raise_errors, false
+ set :dump_errors, true
set :sessions, false
set :logging, true
set :methodoverride, true
set :static, true
set :run, false
@@ -761,9 +806,10 @@
end
def self.reload!
@reloading = true
superclass.send :inherited, self
+ $LOADED_FEATURES.delete("sinatra.rb")
::Kernel.load app_file
@reloading = false
end
end