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)
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)
93 module ResponseHelpers
96 throw :halt, Redirect.new(path)
100 include ResponseHelpers
102 module RenderingHelpers
104 def render(content, options={})
105 template = resolve_template(content, options)
106 @content = _evaluate_render(template)
107 layout = resolve_layout(options[:layout], options)
108 @content = _evaluate_render(layout) if layout
114 def _evaluate_render(content, options={})
117 instance_eval(%Q{"#{content}"})
119 instance_eval(&content)
121 instance_eval(%Q{"#{content.read}"})
125 def resolve_template(content, options={})
130 File.new(filename_for(content, options))
134 def resolve_layout(name, options={})
135 return if name == false
136 if layout = layouts[name || :layout]
139 if File.file?(filename = filename_for(name, options))
144 def filename_for(name, options={})
145 (options[:views_directory] || 'views') + "/#{name}.#{ext}"
153 Sinatra.application.layouts
157 include RenderingHelpers
159 attr_accessor :request, :response
161 dslify_writter :status, :body
163 def initialize(request, response, route_params)
166 @route_params = route_params
171 @params ||= @route_params.merge(@request.params).symbolize_keys
178 def complete(returned)
179 @response.body || returned
184 def method_missing(name, *args, &b)
185 @response.send(name, *args, &b)
195 def to_result(cx, *args)
197 cx.header.merge!('Location' => @path)
204 attr_reader :events, :layouts, :default_options
206 def self.default_options
207 @@default_options = {
210 :environment => :development
219 @events = Hash.new { |hash, key| hash[key] = [] }
223 def define_event(method, path, &b)
224 events[method] << event = Event.new(path, &b)
228 def define_layout(name=:layout, &b)
233 events[env['REQUEST_METHOD'].downcase.to_sym].eject(&[:invoke, env])
237 @options ||= OpenStruct.new(default_options)
241 return [404, {}, 'Not Found'] unless result = lookup(env)
242 context = EventContext.new(
243 Rack::Request.new(env),
247 returned = catch(:halt) do
248 [:complete, context.instance_eval(&result.block)]
250 result = returned.to_result(context)
251 context.body = String === result ? [*result] : result
260 Sinatra.application.define_event(:get, path, &b)
264 Sinatra.application.define_event(:post, path, &b)
268 Sinatra.application.define_event(:put, path, &b)
272 Sinatra.application.define_event(:delete, path, &b)
276 Sinatra::EventContext.class_eval(&b)
279 def layout(name = :layout, &b)
280 Sinatra.application.define_layout(name, &b)
283 ### Misc Core Extensions
288 old_verbose, $VERBOSE = $VERBOSE, nil
291 $VERBOSE = old_verbose
298 # Converts +self+ to an escaped URI parameter value
299 # 'Foo Bar'.to_param # => 'Foo%20Bar'
304 # Converts +self+ from an escaped URI parameter value
305 # 'Foo%20Bar'.from_param # => 'Foo Bar'
315 map { |k,v| "#{k}=#{URI.escape(v)}" }.join('&')
319 self.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
323 reject { |k,v| !keys.include?(k) }
331 Proc.new { |*args| args.shift.__send__(self, *args) }
339 self.inject({}) { |h, (k, v)| h[k] = v; h }
343 Proc.new { |*args| args.shift.__send__(self[0], *(args + self[1..-1])) }
351 find { |e| result = block[e] and break result }
356 ### Core Extension results for throw :halt
359 def to_result(cx, *args)
360 cx.instance_eval(&self)
365 def to_result(cx, *args)
371 def to_result(cx, *args)
372 self.shift.to_result(cx, *self)
377 def to_result(cx, *args)
383 def to_result(cx, *args)
390 def to_result(cx, *args)
397 Sinatra.run if Sinatra.application.options.run