16 map { |k,v| "#{k}=#{URI.escape(v)}" }.join('&')
20 self.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
24 reject { |k,v| !keys.include?(k) }
30 Proc.new { |*args| args.shift.__send__(self, *args) }
36 self.inject({}) { |h, (k, v)| h[k] = v; h }
40 Proc.new { |*args| args.shift.__send__(self[0], args + self[1..-1]) }
52 find { |e| result = block[e] and break result }
59 EventContext = Struct.new(:request, :response) do
60 def method_missing(name, *args)
61 if args.size == 1 && response.respond_to?("#{name}=")
62 response.send("#{name}=", args.first)
64 response.send(name, *args)
69 def setup_default_events!
71 "#{$!.message}\n\t#{$!.backtrace.join("\n\t")}"
81 @request_types ||= [:get, :put, :post, :delete]
85 @routes ||= Hash.new do |hash, key|
86 hash[key] = [] if request_types.include?(key)
91 @config ||= @default_config
101 :raise_errors => false,
106 def determine_route(verb, path)
107 routes[verb].eject { |r| r.match(path) } || routes[404]
111 request = Rack::Request.new(env)
112 response = Rack::Response.new
113 route = determine_route(
114 request.request_method.downcase.to_sym,
117 context = EventContext.new(request, response)
120 result = context.instance_eval(&route.block)
121 context.status ||= route.default_status
122 context.body = Array(result.to_s)
125 raise e if config[:raise_errors]
126 route = Sinatra.routes[500]
128 context.body Array(context.instance_eval(&route.block))
133 def define_route(verb, path, &b)
134 routes[verb] << route = Route.new(path, &b)
138 def define_error(code, &b)
139 routes[code] = Error.new(code, &b)
144 URI_CHAR = '[^/?:,&#]'.freeze unless defined?(URI_CHAR)
145 PARAM = /:(#{URI_CHAR}+)/.freeze unless defined?(PARAM)
147 attr_reader :block, :path
149 def initialize(path, &b)
150 @path, @block = path, b
152 regex = path.to_s.gsub(PARAM) do
153 @param_keys << $1.intern
156 @pattern = /^#{regex}$/
157 @struct = Struct.new(:block, :params, :default_status)
161 return nil unless path =~ @pattern
162 params = @param_keys.zip($~.captures.map(&:from_param)).to_hash
163 @struct.new(@block, params, 200)
172 def initialize(code, &b)
173 @code, @block = code, b
185 Sinatra.define_route(:get, path, &b)
188 def error(*codes, &b)
189 raise 'You must specify a block to assciate with an error' if b.nil?
190 codes.each { |code| Sinatra.define_error(code, &b) }
193 Sinatra.setup_default_events!