Merge commit 'bmizerany/master'
This commit is contained in:
commit
b73450982a
|
@ -2,4 +2,5 @@ doc
|
||||||
pkg
|
pkg
|
||||||
*.log
|
*.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Manifest
|
Manifest
|
||||||
|
x.rb
|
479
lib/sinatra.rb
479
lib/sinatra.rb
|
@ -96,19 +96,15 @@ module Sinatra
|
||||||
def options
|
def options
|
||||||
application.options
|
application.options
|
||||||
end
|
end
|
||||||
|
|
||||||
def application
|
def application
|
||||||
unless @app
|
@app ||= Application.new
|
||||||
@app = Application.new
|
|
||||||
Sinatra::Environment.setup!
|
|
||||||
end
|
|
||||||
@app
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def application=(app)
|
def application=(app)
|
||||||
@app = app
|
@app = app
|
||||||
end
|
end
|
||||||
|
|
||||||
def port
|
def port
|
||||||
application.options.port
|
application.options.port
|
||||||
end
|
end
|
||||||
|
@ -116,14 +112,10 @@ module Sinatra
|
||||||
def env
|
def env
|
||||||
application.options.env
|
application.options.env
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_application
|
# Deprecated: use application instead of build_application.
|
||||||
app = application
|
alias :build_application :application
|
||||||
app = Rack::Session::Cookie.new(app) if Sinatra.options.sessions == true
|
|
||||||
app = Rack::CommonLogger.new(app) if Sinatra.options.logging == true
|
|
||||||
app
|
|
||||||
end
|
|
||||||
|
|
||||||
def server
|
def server
|
||||||
@server ||= case options.server
|
@server ||= case options.server
|
||||||
when "mongrel"
|
when "mongrel"
|
||||||
|
@ -145,11 +137,10 @@ module Sinatra
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
|
||||||
begin
|
begin
|
||||||
puts "== Sinatra has taken the stage on port #{port} for #{env} with backup by #{server.name}"
|
puts "== Sinatra has taken the stage on port #{port} for #{env} with backup by #{server.name}"
|
||||||
require 'pp'
|
require 'pp'
|
||||||
server.run(build_application, :Port => port) do |server|
|
server.run(application, :Port => port) do |server|
|
||||||
trap(:INT) do
|
trap(:INT) do
|
||||||
server.stop
|
server.stop
|
||||||
puts "\n== Sinatra has ended his set (crowd applauds)"
|
puts "\n== Sinatra has ended his set (crowd applauds)"
|
||||||
|
@ -158,9 +149,8 @@ module Sinatra
|
||||||
rescue Errno::EADDRINUSE => e
|
rescue Errno::EADDRINUSE => e
|
||||||
puts "== Someone is already performing on port #{port}!"
|
puts "== Someone is already performing on port #{port}!"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class Event
|
class Event
|
||||||
|
|
||||||
URI_CHAR = '[^/?:,&#\.]'.freeze unless defined?(URI_CHAR)
|
URI_CHAR = '[^/?:,&#\.]'.freeze unless defined?(URI_CHAR)
|
||||||
|
@ -830,17 +820,83 @@ module Sinatra
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# The Application class represents the top-level working area of a
|
||||||
|
# Sinatra app. It provides the DSL for defining various aspects of the
|
||||||
|
# application and implements a Rack compatible interface for dispatching
|
||||||
|
# requests.
|
||||||
|
#
|
||||||
|
# Many of the instance methods defined in this class (#get, #post,
|
||||||
|
# #put, #delete, #layout, #before, #error, #not_found, etc.) are
|
||||||
|
# available at top-level scope. When invoked from top-level, the
|
||||||
|
# messages are forwarded to the "default application" (accessible
|
||||||
|
# at Sinatra::application).
|
||||||
class Application
|
class Application
|
||||||
|
|
||||||
attr_reader :events, :errors, :templates, :filters
|
# Hash of event handlers with request method keys and
|
||||||
attr_reader :clearables, :reloading
|
# arrays of potential handlers as values.
|
||||||
|
attr_reader :events
|
||||||
attr_writer :options
|
|
||||||
|
# Hash of error handlers with error status codes as keys and
|
||||||
|
# handlers as values.
|
||||||
|
attr_reader :errors
|
||||||
|
|
||||||
|
# Hash of template name mappings.
|
||||||
|
attr_reader :templates
|
||||||
|
|
||||||
|
# Hash of filters with event name keys (:before) and arrays of
|
||||||
|
# handlers as values.
|
||||||
|
attr_reader :filters
|
||||||
|
|
||||||
|
# Array of objects to clear during reload. The objects in this array
|
||||||
|
# must respond to :clear.
|
||||||
|
attr_reader :clearables
|
||||||
|
|
||||||
|
# Object including open attribute methods for modifying Application
|
||||||
|
# configuration.
|
||||||
|
attr_reader :options
|
||||||
|
|
||||||
|
# List of methods available from top-level scope. When invoked from
|
||||||
|
# top-level the method is forwarded to the default application
|
||||||
|
# (Sinatra::application).
|
||||||
|
FORWARD_METHODS = %w[
|
||||||
|
get put post delete head template layout before error not_found
|
||||||
|
configures configure set_options set_option enable disable use
|
||||||
|
]
|
||||||
|
|
||||||
|
# Create a new Application with a default configuration taken
|
||||||
|
# from the default_options Hash.
|
||||||
|
#
|
||||||
|
# NOTE: A default Application is automatically created the first
|
||||||
|
# time any of Sinatra's DSL related methods is invoked so there
|
||||||
|
# is typically no need to create an instance explicitly. See
|
||||||
|
# Sinatra::application for more information.
|
||||||
|
def initialize
|
||||||
|
@reloading = false
|
||||||
|
@clearables = [
|
||||||
|
@events = Hash.new { |hash, key| hash[key] = [] },
|
||||||
|
@errors = Hash.new,
|
||||||
|
@filters = Hash.new { |hash, key| hash[key] = [] },
|
||||||
|
@templates = Hash.new,
|
||||||
|
@middleware = []
|
||||||
|
]
|
||||||
|
@options = OpenStruct.new(self.class.default_options)
|
||||||
|
load_default_configuration!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Hash of default application configuration options. When a new
|
||||||
|
# Application is created, the #options object takes its initial values
|
||||||
|
# from here.
|
||||||
|
#
|
||||||
|
# Changes to the default_options Hash effect only Application objects
|
||||||
|
# created after the changes are made. For this reason, modifications to
|
||||||
|
# the default_options Hash typically occur at the very beginning of a
|
||||||
|
# file, before any DSL related functions are invoked.
|
||||||
def self.default_options
|
def self.default_options
|
||||||
|
return @default_options unless @default_options.nil?
|
||||||
root = File.expand_path(File.dirname($0))
|
root = File.expand_path(File.dirname($0))
|
||||||
@@default_options ||= {
|
@default_options = {
|
||||||
:run => true,
|
:run => true,
|
||||||
:port => 4567,
|
:port => 4567,
|
||||||
:env => :development,
|
:env => :development,
|
||||||
|
@ -848,19 +904,18 @@ module Sinatra
|
||||||
:views => root + '/views',
|
:views => root + '/views',
|
||||||
:public => root + '/public',
|
:public => root + '/public',
|
||||||
:sessions => false,
|
:sessions => false,
|
||||||
:logging => true
|
:logging => true,
|
||||||
|
:raise_errors => false
|
||||||
}
|
}
|
||||||
end
|
load_default_options_from_command_line!
|
||||||
|
@default_options
|
||||||
def default_options
|
|
||||||
self.class.default_options
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Search ARGV for command line arguments and update the
|
||||||
##
|
# Sinatra::default_options Hash accordingly. This method is
|
||||||
# Load all options given on the command line
|
# invoked the first time the default_options Hash is accessed.
|
||||||
# NOTE: Ignores --name so unit/spec tests can run individually
|
# NOTE: Ignores --name so unit/spec tests can run individually
|
||||||
def load_options!
|
def self.load_default_options_from_command_line! #:nodoc:
|
||||||
require 'optparse'
|
require 'optparse'
|
||||||
OptionParser.new do |op|
|
OptionParser.new do |op|
|
||||||
op.on('-p port') { |port| default_options[:port] = port }
|
op.on('-p port') { |port| default_options[:port] = port }
|
||||||
|
@ -870,39 +925,104 @@ module Sinatra
|
||||||
end.parse!(ARGV.dup.select { |o| o !~ /--name/ })
|
end.parse!(ARGV.dup.select { |o| o !~ /--name/ })
|
||||||
end
|
end
|
||||||
|
|
||||||
# Called immediately after the application is initialized or reloaded to
|
# Determine whether the application is in the process of being
|
||||||
# register default events. Events added here have dibs on requests since
|
# reloaded.
|
||||||
# they appear first in the list.
|
def reloading?
|
||||||
def load_default_events!
|
@reloading == true
|
||||||
events[:get] << Static.new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize
|
# Yield to the block for configuration if the current environment
|
||||||
@clearables = [
|
# matches any included in the +envs+ list. Always yield to the block
|
||||||
@events = Hash.new { |hash, key| hash[key] = [] },
|
# when no environment is specified.
|
||||||
@errors = Hash.new,
|
#
|
||||||
@filters = Hash.new { |hash, key| hash[key] = [] },
|
# NOTE: configuration blocks are not executed during reloads.
|
||||||
@templates = Hash.new
|
def configures(*envs, &b)
|
||||||
]
|
return if reloading?
|
||||||
load_options!
|
yield self if envs.empty? || envs.include?(options.env)
|
||||||
load_default_events!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def define_event(method, path, options = {}, &b)
|
alias :configure :configures
|
||||||
events[method] << event = Event.new(path, options, &b)
|
|
||||||
event
|
# When both +option+ and +value+ arguments are provided, set the option
|
||||||
|
# specified. With a single Hash argument, set all options specified in
|
||||||
|
# Hash. Options are available via the Application#options object.
|
||||||
|
#
|
||||||
|
# Setting individual options:
|
||||||
|
# set :port, 80
|
||||||
|
# set :env, :production
|
||||||
|
# set :views, '/path/to/views'
|
||||||
|
#
|
||||||
|
# Setting multiple options:
|
||||||
|
# set :port => 80,
|
||||||
|
# :env => :production,
|
||||||
|
# :views => '/path/to/views'
|
||||||
|
#
|
||||||
|
def set(option, value=self)
|
||||||
|
if value == self && option.kind_of?(Hash)
|
||||||
|
option.each { |key,val| set(key, val) }
|
||||||
|
else
|
||||||
|
options.send("#{option}=", value)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def define_template(name=:layout, &b)
|
alias :set_option :set
|
||||||
templates[name] = b
|
alias :set_options :set
|
||||||
|
|
||||||
|
# Enable the options specified by setting their values to true. For
|
||||||
|
# example, to enable sessions and logging:
|
||||||
|
# enable :sessions, :logging
|
||||||
|
def enable(*opts)
|
||||||
|
opts.each { |key| set(key, true) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def define_error(code, options = {}, &b)
|
# Disable the options specified by setting their values to false. For
|
||||||
errors[code] = Error.new(code, &b)
|
# example, to disable logging and automatic run:
|
||||||
|
# disable :logging, :run
|
||||||
|
def disable(*opts)
|
||||||
|
opts.each { |key| set(key, false) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def define_filter(type, &b)
|
# Define an event handler for the given request method and path
|
||||||
filters[:before] << b
|
# spec. The block is executed when a request matches the method
|
||||||
|
# and spec.
|
||||||
|
#
|
||||||
|
# NOTE: The #get, #post, #put, and #delete helper methods should
|
||||||
|
# be used to define events when possible.
|
||||||
|
def event(method, path, options = {}, &b)
|
||||||
|
events[method].push(Event.new(path, options, &b)).last
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define an event handler for GET requests.
|
||||||
|
def get(path, options={}, &b)
|
||||||
|
event(:get, path, options, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define an event handler for POST requests.
|
||||||
|
def post(path, options={}, &b)
|
||||||
|
event(:post, path, options, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define an event handler for HEAD requests.
|
||||||
|
def head(path, options={}, &b)
|
||||||
|
event(:head, path, options, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define an event handler for PUT requests.
|
||||||
|
#
|
||||||
|
# NOTE: PUT events are triggered when the HTTP request method is
|
||||||
|
# PUT and also when the request method is POST and the body includes a
|
||||||
|
# "_method" parameter set to "PUT".
|
||||||
|
def put(path, options={}, &b)
|
||||||
|
event(:put, path, options, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define an event handler for DELETE requests.
|
||||||
|
#
|
||||||
|
# NOTE: DELETE events are triggered when the HTTP request method is
|
||||||
|
# DELETE and also when the request method is POST and the body includes a
|
||||||
|
# "_method" parameter set to "DELETE".
|
||||||
|
def delete(path, options={}, &b)
|
||||||
|
event(:delete, path, options, &b)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Visits and invokes each handler registered for the +request_method+ in
|
# Visits and invokes each handler registered for the +request_method+ in
|
||||||
|
@ -920,27 +1040,96 @@ module Sinatra
|
||||||
errors[NotFound].invoke(request)
|
errors[NotFound].invoke(request)
|
||||||
end
|
end
|
||||||
|
|
||||||
def options
|
|
||||||
@options ||= OpenStruct.new(default_options)
|
# Define a named template. The template may be referenced from
|
||||||
|
# event handlers by passing the name as a Symbol to rendering
|
||||||
|
# methods. The block is executed each time the template is rendered
|
||||||
|
# and the resulting object is passed to the template handler.
|
||||||
|
#
|
||||||
|
# The following example defines a HAML template named hello and
|
||||||
|
# invokes it from an event handler:
|
||||||
|
#
|
||||||
|
# template :hello do
|
||||||
|
# "h1 Hello World!"
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# get '/' do
|
||||||
|
# haml :hello
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
def template(name, &b)
|
||||||
|
templates[name] = b
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Define a layout template.
|
||||||
|
def layout(name=:layout, &b)
|
||||||
|
template(name, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define a custom error handler for the exception class +type+. The block
|
||||||
|
# is invoked when the specified exception type is raised from an error
|
||||||
|
# handler and can manipulate the response as needed:
|
||||||
|
#
|
||||||
|
# error MyCustomError do
|
||||||
|
# status 500
|
||||||
|
# 'So what happened was...' + request.env['sinatra.error'].message
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# The Sinatra::ServerError handler is used by default when an exception
|
||||||
|
# occurs and no matching error handler is found.
|
||||||
|
def error(type=ServerError, options = {}, &b)
|
||||||
|
errors[type] = Error.new(type, &b)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define a custom error handler for '404 Not Found' responses. This is a
|
||||||
|
# shorthand for:
|
||||||
|
# error NotFound do
|
||||||
|
# ..
|
||||||
|
# end
|
||||||
|
def not_found(options={}, &b)
|
||||||
|
error NotFound, options, &b
|
||||||
|
end
|
||||||
|
|
||||||
|
# Define a request filter. When +type+ is +:before+, execute the block
|
||||||
|
# in the context of each request before matching event handlers.
|
||||||
|
def filter(type, &b)
|
||||||
|
filters[type] << b
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invoke the block in the context of each request before invoking
|
||||||
|
# matching event handlers.
|
||||||
|
def before(&b)
|
||||||
|
filter :before, &b
|
||||||
|
end
|
||||||
|
|
||||||
def development?
|
def development?
|
||||||
options.env == :development
|
options.env == :development
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Clear all events, templates, filters, and error handlers
|
||||||
|
# and then reload the application source file. This occurs
|
||||||
|
# automatically before each request is processed in development.
|
||||||
def reload!
|
def reload!
|
||||||
clearables.each(&:clear)
|
clearables.each(&:clear)
|
||||||
Environment.setup!
|
load_default_configuration!
|
||||||
|
@pipeline = nil
|
||||||
@reloading = true
|
@reloading = true
|
||||||
load_default_events!
|
|
||||||
Kernel.load $0
|
Kernel.load $0
|
||||||
@reloading = false
|
@reloading = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Determine whether the application is in the process of being
|
||||||
|
# reloaded.
|
||||||
|
def reloading?
|
||||||
|
@reloading == true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Mutex instance used for thread synchronization.
|
||||||
def mutex
|
def mutex
|
||||||
@@mutex ||= Mutex.new
|
@@mutex ||= Mutex.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Yield to the block with thread synchronization
|
||||||
def run_safely
|
def run_safely
|
||||||
if options.mutex
|
if options.mutex
|
||||||
mutex.synchronize { yield }
|
mutex.synchronize { yield }
|
||||||
|
@ -948,16 +1137,74 @@ module Sinatra
|
||||||
yield
|
yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Add a piece of Rack middleware to the pipeline leading to the
|
||||||
|
# application.
|
||||||
|
def use(klass, *args, &block)
|
||||||
|
fail "#{klass} must respond to 'new'" unless klass.respond_to?(:new)
|
||||||
|
@pipeline = nil
|
||||||
|
@middleware.push([ klass, args, block ]).last
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Rack middleware derived from current state of application options.
|
||||||
|
# These components are plumbed in at the very beginning of the
|
||||||
|
# pipeline.
|
||||||
|
def optional_middleware
|
||||||
|
[
|
||||||
|
([ Rack::CommonLogger, [], nil ] if options.logging),
|
||||||
|
([ Rack::Session::Cookie, [], nil ] if options.sessions)
|
||||||
|
].compact
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rack middleware explicitly added to the application with #use. These
|
||||||
|
# components are plumbed into the pipeline downstream from
|
||||||
|
# #optional_middle.
|
||||||
|
def explicit_middleware
|
||||||
|
@middleware
|
||||||
|
end
|
||||||
|
|
||||||
|
# All Rack middleware used to construct the pipeline.
|
||||||
|
def middleware
|
||||||
|
optional_middleware + explicit_middleware
|
||||||
|
end
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
# An assembled pipeline of Rack middleware that leads eventually to
|
||||||
|
# the Application#invoke method. The pipeline is built upon first
|
||||||
|
# access. Defining new middleware with Application#use or manipulating
|
||||||
|
# application options may cause the pipeline to be rebuilt.
|
||||||
|
def pipeline
|
||||||
|
@pipeline ||=
|
||||||
|
middleware.inject(method(:dispatch)) do |app,(klass,args,block)|
|
||||||
|
klass.new(app, *args, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rack compatible request invocation interface.
|
||||||
def call(env)
|
def call(env)
|
||||||
reload! if development?
|
reload! if development?
|
||||||
|
pipeline.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Request invocation handler - called at the end of the Rack pipeline
|
||||||
|
# for each request.
|
||||||
|
#
|
||||||
|
# 1. Create Rack::Request, Rack::Response helper objects.
|
||||||
|
# 2. Lookup event handler based on request method and path.
|
||||||
|
# 3. Create new EventContext to house event handler evaluation.
|
||||||
|
# 4. Invoke each #before filter in context of EventContext object.
|
||||||
|
# 5. Invoke event handler in context of EventContext object.
|
||||||
|
# 6. Return response to Rack.
|
||||||
|
#
|
||||||
|
# See the Rack specification for detailed information on the
|
||||||
|
# +env+ argument and return value.
|
||||||
|
def dispatch(env)
|
||||||
request = Rack::Request.new(env)
|
request = Rack::Request.new(env)
|
||||||
result = lookup(request)
|
result = lookup(request)
|
||||||
context = EventContext.new(
|
context = EventContext.new(request, Rack::Response.new, result.params)
|
||||||
request,
|
|
||||||
Rack::Response.new,
|
|
||||||
result.params
|
|
||||||
)
|
|
||||||
context.status(result.status)
|
context.status(result.status)
|
||||||
begin
|
begin
|
||||||
returned = run_safely do
|
returned = run_safely do
|
||||||
|
@ -983,14 +1230,15 @@ module Sinatra
|
||||||
context.body = body.kind_of?(String) ? [*body] : body
|
context.body = body.kind_of?(String) ? [*body] : body
|
||||||
context.finish
|
context.finish
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
# Called immediately after the application is initialized or reloaded to
|
||||||
|
# register default events, templates, and error handlers.
|
||||||
|
def load_default_configuration!
|
||||||
module Environment
|
|
||||||
extend self
|
# The static event is always executed first.
|
||||||
|
events[:get] << Static.new
|
||||||
def setup!
|
|
||||||
|
# Default configuration for all environments.
|
||||||
configure do
|
configure do
|
||||||
error do
|
error do
|
||||||
raise request.env['sinatra.error'] if Sinatra.options.raise_errors
|
raise request.env['sinatra.error'] if Sinatra.options.raise_errors
|
||||||
|
@ -1087,50 +1335,27 @@ end<pre>
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private :load_default_configuration!
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(path, options ={}, &b)
|
# Delegate DSLish methods to the currently active Sinatra::Application
|
||||||
Sinatra.application.define_event(:get, path, options, &b)
|
# instance.
|
||||||
end
|
Sinatra::Application::FORWARD_METHODS.each do |method|
|
||||||
|
eval(<<-EOS, binding, '(__DSL__)', 1)
|
||||||
def post(path, options ={}, &b)
|
def #{method}(*args, &b)
|
||||||
Sinatra.application.define_event(:post, path, options, &b)
|
Sinatra.application.#{method}(*args, &b)
|
||||||
end
|
end
|
||||||
|
EOS
|
||||||
def put(path, options ={}, &b)
|
|
||||||
Sinatra.application.define_event(:put, path, options, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete(path, options ={}, &b)
|
|
||||||
Sinatra.application.define_event(:delete, path, options, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def before(&b)
|
|
||||||
Sinatra.application.define_filter(:before, &b)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def helpers(&b)
|
def helpers(&b)
|
||||||
Sinatra::EventContext.class_eval(&b)
|
Sinatra::EventContext.class_eval(&b)
|
||||||
end
|
end
|
||||||
|
|
||||||
def error(type = Sinatra::ServerError, options = {}, &b)
|
|
||||||
Sinatra.application.define_error(type, options, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def not_found(options = {}, &b)
|
|
||||||
Sinatra.application.define_error(Sinatra::NotFound, options, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def layout(name = :layout, &b)
|
|
||||||
Sinatra.application.define_template(name, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def template(name, &b)
|
|
||||||
Sinatra.application.define_template(name, &b)
|
|
||||||
end
|
|
||||||
|
|
||||||
def use_in_file_templates!
|
def use_in_file_templates!
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
templates = IO.read(caller.first.split(':').first).split('__FILE__').last
|
templates = IO.read(caller.first.split(':').first).split('__FILE__').last
|
||||||
|
@ -1146,22 +1371,6 @@ def use_in_file_templates!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def configures(*envs, &b)
|
|
||||||
yield if !Sinatra.application.reloading &&
|
|
||||||
(envs.include?(Sinatra.application.options.env) ||
|
|
||||||
envs.empty?)
|
|
||||||
end
|
|
||||||
alias :configure :configures
|
|
||||||
|
|
||||||
def set_options(opts)
|
|
||||||
Sinatra::Application.default_options.merge!(opts)
|
|
||||||
Sinatra.application.options = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_option(key, value)
|
|
||||||
set_options(key => value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def mime(ext, type)
|
def mime(ext, type)
|
||||||
Rack::File::MIME_TYPES[ext.to_s] = type
|
Rack::File::MIME_TYPES[ext.to_s] = type
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,4 +10,4 @@ Sinatra::Application.default_options.merge!(
|
||||||
:logging => false
|
:logging => false
|
||||||
)
|
)
|
||||||
|
|
||||||
Sinatra.application.options = nil
|
Sinatra.application = nil
|
||||||
|
|
|
@ -5,7 +5,14 @@ context "Sinatra" do
|
||||||
setup do
|
setup do
|
||||||
Sinatra.application = nil
|
Sinatra.application = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
specify "should put all DSL methods on (main)" do
|
||||||
|
object = Object.new
|
||||||
|
Sinatra::Application::FORWARD_METHODS.each do |method|
|
||||||
|
object.private_methods.should.include(method)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
specify "should handle result of nil" do
|
specify "should handle result of nil" do
|
||||||
get '/' do
|
get '/' do
|
||||||
nil
|
nil
|
||||||
|
|
|
@ -97,7 +97,53 @@ context "An app returns" do
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "Application#configure blocks" do
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Sinatra.application = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "run when no environment specified" do
|
||||||
|
ref = false
|
||||||
|
configure { ref = true }
|
||||||
|
ref.should.equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "run when matching environment specified" do
|
||||||
|
ref = false
|
||||||
|
configure(:test) { ref = true }
|
||||||
|
ref.should.equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "do not run when no matching environment specified" do
|
||||||
|
configure(:foo) { flunk "block should not have been executed" }
|
||||||
|
configure(:development, :production, :foo) { flunk "block should not have been executed" }
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "accept multiple environments" do
|
||||||
|
ref = false
|
||||||
|
configure(:foo, :test, :bar) { ref = true }
|
||||||
|
ref.should.equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Default Application Configuration" do
|
||||||
|
|
||||||
|
specify "includes 404 and 500 error handlers" do
|
||||||
|
Sinatra.application.errors.should.include(Sinatra::ServerError)
|
||||||
|
Sinatra.application.errors[Sinatra::ServerError].should.not.be.nil
|
||||||
|
Sinatra.application.errors.should.include(Sinatra::NotFound)
|
||||||
|
Sinatra.application.errors[Sinatra::NotFound].should.not.be.nil
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "includes Static event" do
|
||||||
|
assert Sinatra.application.events[:get].any? { |e| Sinatra::Static === e }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
context "Events in an app" do
|
context "Events in an app" do
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
|
@ -173,3 +219,69 @@ context "Events in an app" do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
context "Options in an app" do
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Sinatra.application = nil
|
||||||
|
@app = Sinatra::application
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be set singly on app" do
|
||||||
|
@app.set :foo, 1234
|
||||||
|
@app.options.foo.should.equal 1234
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be set singly from top-level" do
|
||||||
|
set_option :foo, 1234
|
||||||
|
@app.options.foo.should.equal 1234
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be set multiply on app" do
|
||||||
|
@app.options.foo.should.be.nil
|
||||||
|
@app.set :foo => 1234,
|
||||||
|
:bar => 'hello, world'
|
||||||
|
@app.options.foo.should.equal 1234
|
||||||
|
@app.options.bar.should.equal 'hello, world'
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be set multiply from top-level" do
|
||||||
|
@app.options.foo.should.be.nil
|
||||||
|
set_options :foo => 1234,
|
||||||
|
:bar => 'hello, world'
|
||||||
|
@app.options.foo.should.equal 1234
|
||||||
|
@app.options.bar.should.equal 'hello, world'
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be enabled on app" do
|
||||||
|
@app.options.foo.should.be.nil
|
||||||
|
@app.enable :sessions, :foo, :bar
|
||||||
|
@app.options.sessions.should.equal true
|
||||||
|
@app.options.foo.should.equal true
|
||||||
|
@app.options.bar.should.equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be enabled from top-level" do
|
||||||
|
@app.options.foo.should.be.nil
|
||||||
|
enable :sessions, :foo, :bar
|
||||||
|
@app.options.sessions.should.equal true
|
||||||
|
@app.options.foo.should.equal true
|
||||||
|
@app.options.bar.should.equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be disabled on app" do
|
||||||
|
@app.options.foo.should.be.nil
|
||||||
|
@app.disable :sessions, :foo, :bar
|
||||||
|
@app.options.sessions.should.equal false
|
||||||
|
@app.options.foo.should.equal false
|
||||||
|
@app.options.bar.should.equal false
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "can be enabled from top-level" do
|
||||||
|
@app.options.foo.should.be.nil
|
||||||
|
disable :sessions, :foo, :bar
|
||||||
|
@app.options.sessions.should.equal false
|
||||||
|
@app.options.foo.should.equal false
|
||||||
|
@app.options.bar.should.equal false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
require File.dirname(__FILE__) + '/helper'
|
||||||
|
|
||||||
|
class UpcaseMiddleware
|
||||||
|
def initialize(app, *args, &block)
|
||||||
|
@app = app
|
||||||
|
@args = args
|
||||||
|
@block = block
|
||||||
|
end
|
||||||
|
def call(env)
|
||||||
|
env['PATH_INFO'] = env['PATH_INFO'].to_s.upcase
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Middleware Pipelines" do
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Sinatra.application = nil
|
||||||
|
@app = Sinatra.application
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
Sinatra.application = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "includes default middleware with options set" do
|
||||||
|
@app.set_options :sessions => true, :logging => true
|
||||||
|
@app.send(:optional_middleware).should.include([Rack::Session::Cookie, [], nil])
|
||||||
|
@app.send(:optional_middleware).should.include([Rack::CommonLogger, [], nil])
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "does not include default middleware with options unset" do
|
||||||
|
@app.set_options :sessions => false, :logging => false
|
||||||
|
@app.send(:optional_middleware).should.not.include([Rack::Session::Cookie, [], nil])
|
||||||
|
@app.send(:optional_middleware).should.not.include([Rack::CommonLogger, [], nil])
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "includes only optional middleware when no explicit middleware added" do
|
||||||
|
@app.set_options :sessions => true, :logging => true
|
||||||
|
@app.send(:middleware).should.equal @app.send(:optional_middleware)
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "should clear middleware before reload" do
|
||||||
|
@app.clearables.should.include(@app.send(:explicit_middleware))
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "should add middleware with use" do
|
||||||
|
block = Proc.new { |env| }
|
||||||
|
@app.use UpcaseMiddleware
|
||||||
|
@app.use UpcaseMiddleware, "foo", "bar"
|
||||||
|
@app.use UpcaseMiddleware, "foo", "bar", &block
|
||||||
|
@app.send(:middleware).should.include([UpcaseMiddleware, [], nil])
|
||||||
|
@app.send(:middleware).should.include([UpcaseMiddleware, ["foo", "bar"], nil])
|
||||||
|
@app.send(:middleware).should.include([UpcaseMiddleware, ["foo", "bar"], block])
|
||||||
|
end
|
||||||
|
|
||||||
|
specify "should run middleware added with use" do
|
||||||
|
get('/foo') { "FAIL!" }
|
||||||
|
get('/FOO') { "PASS!" }
|
||||||
|
use UpcaseMiddleware
|
||||||
|
get_it '/foo'
|
||||||
|
should.be.ok
|
||||||
|
body.should.equal "PASS!"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,10 +1,10 @@
|
||||||
require File.dirname(__FILE__) + '/helper'
|
require File.dirname(__FILE__) + '/helper'
|
||||||
|
|
||||||
context "Sessions" do
|
context "Sessions" do
|
||||||
|
|
||||||
specify "should be off by default" do
|
|
||||||
Sinatra.application = nil
|
|
||||||
|
|
||||||
|
setup { Sinatra.application = nil }
|
||||||
|
|
||||||
|
specify "should be off by default" do
|
||||||
get '/asdf' do
|
get '/asdf' do
|
||||||
session[:test] = true
|
session[:test] = true
|
||||||
"asdf"
|
"asdf"
|
||||||
|
@ -18,10 +18,9 @@ context "Sessions" do
|
||||||
assert ok?
|
assert ok?
|
||||||
assert !include?('Set-Cookie')
|
assert !include?('Set-Cookie')
|
||||||
end
|
end
|
||||||
|
|
||||||
specify "should be able to store data accross requests" do
|
specify "should be able to store data accross requests" do
|
||||||
set_options(:sessions => true)
|
set_option :sessions, true
|
||||||
Sinatra.application = nil
|
|
||||||
|
|
||||||
get '/foo' do
|
get '/foo' do
|
||||||
session[:test] = true
|
session[:test] = true
|
||||||
|
|
Loading…
Reference in New Issue