4 require 'swiftcore/swiftiplied_mongrel'
5 puts "Using Swiftiplied Mongrel"
7 require 'swiftcore/evented_mongrel'
8 puts "Using Evented Mongrel"
15 def dslify_writter(*syms)
17 class_eval <<-end_eval
19 self.send "#{sym}=", v if v
30 Result = Struct.new(:block, :params, :status) unless defined?(Result)
33 @app ||= Application.new
41 application.options.port
45 application.options.env
51 puts "== Sinatra has taken the stage on port #{port} for #{env}"
53 Rack::Handler::Mongrel.run(application, :Port => port) do |server|
56 puts "\n== Sinatra has ended his set (crowd applauds)"
59 rescue Errno::EADDRINUSE => e
60 puts "== Someone is already performing on port #{port}!"
67 URI_CHAR = '[^/?:,&#]'.freeze unless defined?(URI_CHAR)
68 PARAM = /:(#{URI_CHAR}+)/.freeze unless defined?(PARAM)
70 attr_reader :path, :block, :param_keys, :pattern
72 def initialize(path, &b)
76 regex = @path.to_s.gsub(PARAM) do
77 @param_keys << $1.intern
80 @pattern = /^#{regex}$/
84 return unless pattern =~ env['PATH_INFO'].squeeze('/')
85 params = param_keys.zip($~.captures.map(&:from_param)).to_hash
86 Result.new(block, params, 200)
93 attr_reader :code, :block
95 def initialize(code, &b)
96 @code, @block = code, b
100 Result.new(block, {}, 404)
105 module ResponseHelpers
108 throw :halt, Redirect.new(path)
113 module RenderingHelpers
115 def render(content, options={})
116 template = resolve_template(content, options)
117 @content = _evaluate_render(template)
118 layout = resolve_layout(options[:layout], options)
119 @content = _evaluate_render(layout) if layout
125 def _evaluate_render(content, options={})
128 instance_eval(%Q{"#{content}"})
130 instance_eval(&content)
132 instance_eval(%Q{"#{content.read}"})
136 def resolve_template(content, options={})
141 File.new(filename_for(content, options))
145 def resolve_layout(name, options={})
146 return if name == false
147 if layout = layouts[name || :layout]
150 if File.file?(filename = filename_for(name, options))
155 def filename_for(name, options={})
156 (options[:views_directory] || 'views') + "/#{name}.#{ext}"
164 Sinatra.application.layouts
171 include ResponseHelpers
172 include RenderingHelpers
174 attr_accessor :request, :response
176 dslify_writter :status, :body
178 def initialize(request, response, route_params)
181 @route_params = route_params
186 @params ||= @route_params.merge(@request.params).symbolize_keys
193 def complete(returned)
194 @response.body || returned
199 def method_missing(name, *args, &b)
200 @response.send(name, *args, &b)
210 def to_result(cx, *args)
212 cx.header.merge!('Location' => @path)
219 attr_reader :events, :layouts, :default_options
221 def self.default_options
222 @@default_options ||= {
230 self.class.default_options
234 @events = Hash.new { |hash, key| hash[key] = [] }
238 def define_event(method, path, &b)
239 events[method] << event = Event.new(path, &b)
243 def define_layout(name=:layout, &b)
247 def define_error(code, &b)
248 events[:errors][code] = Error.new(code, &b)
252 e = events[env['REQUEST_METHOD'].downcase.to_sym].eject(&[:invoke, env])
253 e ||= (events[:errors][404] || basic_not_found).invoke(env)
263 @options ||= OpenStruct.new(default_options)
268 context = EventContext.new(
269 Rack::Request.new(env),
273 context.status(result.status)
274 returned = catch(:halt) do
275 [:complete, context.instance_eval(&result.block)]
277 result = returned.to_result(context)
278 context.body = String === result ? [*result] : result
287 Sinatra.application.define_event(:get, path, &b)
291 Sinatra.application.define_event(:post, path, &b)
295 Sinatra.application.define_event(:put, path, &b)
299 Sinatra.application.define_event(:delete, path, &b)
303 Sinatra::EventContext.class_eval(&b)
307 Sinatra.application.define_error(code, &b)
310 def layout(name = :layout, &b)
311 Sinatra.application.define_layout(name, &b)
314 ### Misc Core Extensions
319 old_verbose, $VERBOSE = $VERBOSE, nil
322 $VERBOSE = old_verbose
329 # Converts +self+ to an escaped URI parameter value
330 # 'Foo Bar'.to_param # => 'Foo%20Bar'
335 # Converts +self+ from an escaped URI parameter value
336 # 'Foo%20Bar'.from_param # => 'Foo Bar'
346 map { |k,v| "#{k}=#{URI.escape(v)}" }.join('&')
350 self.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
354 reject { |k,v| !keys.include?(k) }
362 Proc.new { |*args| args.shift.__send__(self, *args) }
370 self.inject({}) { |h, (k, v)| h[k] = v; h }
374 Proc.new { |*args| args.shift.__send__(self[0], *(args + self[1..-1])) }
382 find { |e| result = block[e] and break result }
387 ### Core Extension results for throw :halt
390 def to_result(cx, *args)
391 cx.instance_eval(&self)
396 def to_result(cx, *args)
402 def to_result(cx, *args)
403 self.shift.to_result(cx, *self)
408 def to_result(cx, *args)
414 def to_result(cx, *args)
421 def to_result(cx, *args)
428 Sinatra.run if Sinatra.application.options.run