* test test
[sinatra.git] / lib / sinatra.rb
blobbf85e404a00f0587598ce0f064af38e8fa3dff88
1 require "rubygems"
2 require "rack"
4 class String
5   def to_param
6     URI.escape(self)
7   end
8   
9   def from_param
10     URI.unescape(self)
11   end
12 end
14 class Hash
15   def to_params
16     map { |k,v| "#{k}=#{URI.escape(v)}" }.join('&')
17   end
18   
19   def symbolize_keys
20     self.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
21   end
22   
23   def pass(*keys)
24     reject { |k,v| !keys.include?(k) }
25   end
26 end
28 class Symbol
29   def to_proc 
30     Proc.new { |*args| args.shift.__send__(self, *args) }
31   end
32 end
34 class Array
35   def to_hash
36     self.inject({}) { |h, (k, v)|  h[k] = v; h }
37   end
38   
39   def to_proc
40     Proc.new { |*args| args.shift.send(self[0], args + self[1..-1]) }
41   end
42 end
44 class Proc
45   def block
46     self
47   end
48 end
50 module Enumerable
51   def eject(&block)
52     find { |e| result = block[e] and break result }
53   end
54 end
56 module Sinatra
57   extend self
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)
63       else
64         response.send(name, *args)
65       end
66     end
67   end
68   
69   def setup_default_events!
70     error 500 do
71       "#{$!.message}\n\t#{$!.backtrace.join("\n\t")}"
72     end
74     error 404 do
75       status 404
76       "<h1>Not Found</h1>"
77     end
78   end
79   
80   def request_types
81     @request_types ||= [:get, :put, :post, :delete]
82   end
83   
84   def routes
85     @routes ||= Hash.new do |hash, key|
86       hash[key] = [] if request_types.include?(key)
87     end
88   end
89   
90   def config
91     @config ||= {}
92   end
93   
94   def config=(c)
95     @config = c
96   end
97   
98   def determine_route(verb, path)
99     found = routes[verb].eject { |r| r.match(path) }
100     found || routes[404]
101   end
102   
103   def call(env)
104     request = Rack::Request.new(env)
105     response = Rack::Response.new
106     route = determine_route(
107       request.request_method.downcase.to_sym, 
108       request.path_info
109     )
110     context = EventContext.new(request, response)
111     begin
112       result = context.instance_eval(&route.block)
113       context.body = Array(result.to_s)
114       context.finish
115     rescue => e
116       raise e if config[:raise_errors]
117       route = Sinatra.routes[500]
118       context.status 500
119       context.body Array(context.instance_eval(&route.block))
120       context.finish
121     end
122   end
123   
124   def define_route(verb, path, &b)
125     routes[verb] << route = Route.new(path, &b)
126     route
127   end
128   
129   def define_error_route(num, &b)
130     routes[num] = b
131   end
132   
133   class Route
134     
135     URI_CHAR = '[^/?:,&#]'.freeze unless defined?(URI_CHAR)
136     PARAM = /:(#{URI_CHAR}+)/.freeze unless defined?(PARAM)
137     
138     attr_reader :block, :path
139     
140     def initialize(path, &b)
141       @path, @block = path, b
142       @param_keys = []
143       regex = path.to_s.gsub(PARAM) do
144         @param_keys << $1.intern
145         "(#{URI_CHAR}+)"
146       end
147       @pattern = /^#{regex}$/
148       @struct = Struct.new(:block, :params)
149     end
150     
151     def match(path)
152       return nil unless path =~ @pattern
153       params = @param_keys.zip($~.captures.map(&:from_param)).to_hash
154       @struct.new(@block, params)
155     end
156     
157   end
158     
161 def get(path, &b)
162   Sinatra.define_route(:get, path, &b)
165 def error(num, &b)
166   raise 'You must specify a block to assciate with an error' if b.nil?
167   Sinatra.define_error_route(num, &b)
170 Sinatra.setup_default_events!