Class: Otto
- Inherits:
-
Object
- Object
- Otto
- Defined in:
- lib/otto.rb,
lib/otto.rb
Defined Under Namespace
Modules: RequestHelpers, ResponseHelpers, Static, VERSION Classes: Route
Constant Summary collapse
- LIB_HOME =
File. File.dirname(__FILE__)
Instance Attribute Summary collapse
-
#not_found ⇒ Object
Returns the value of attribute not_found.
-
#option ⇒ Object
(also: #options)
readonly
Returns the value of attribute option.
-
#route_definitions ⇒ Object
readonly
Returns the value of attribute route_definitions.
-
#routes ⇒ Object
readonly
Returns the value of attribute routes.
-
#routes_literal ⇒ Object
readonly
Returns the value of attribute routes_literal.
-
#routes_static ⇒ Object
readonly
Returns the value of attribute routes_static.
-
#server_error ⇒ Object
Returns the value of attribute server_error.
-
#static_route ⇒ Object
readonly
Returns the value of attribute static_route.
Class Method Summary collapse
- .default ⇒ Object
- .env?(*guesses) ⇒ Boolean
- .load(path) ⇒ Object
- .path(definition, params = {}) ⇒ Object
- .routes ⇒ Object
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(path = nil, opts = {}) ⇒ Otto
constructor
A new instance of Otto.
- #load(path) ⇒ Object
- #safe_file?(path) ⇒ Boolean
-
#uri(route_definition, params = {}) ⇒ Object
Return the URI path for the given
route_definition
e.g.
Constructor Details
#initialize(path = nil, opts = {}) ⇒ Otto
Returns a new instance of Otto.
30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/otto.rb', line 30 def initialize path=nil, opts={} @routes_static = { :GET => {} } @routes = { :GET => [] } @routes_literal = { :GET => {} } @route_definitions = {} @option = opts.merge({ :public => nil }) load(path) unless path.nil? super() end |
Instance Attribute Details
#not_found ⇒ Object
Returns the value of attribute not_found.
29 30 31 |
# File 'lib/otto.rb', line 29 def not_found @not_found end |
#option ⇒ Object (readonly) Also known as: options
Returns the value of attribute option.
28 29 30 |
# File 'lib/otto.rb', line 28 def option @option end |
#route_definitions ⇒ Object (readonly)
Returns the value of attribute route_definitions.
27 28 29 |
# File 'lib/otto.rb', line 27 def route_definitions @route_definitions end |
#routes ⇒ Object (readonly)
Returns the value of attribute routes.
27 28 29 |
# File 'lib/otto.rb', line 27 def routes @routes end |
#routes_literal ⇒ Object (readonly)
Returns the value of attribute routes_literal.
27 28 29 |
# File 'lib/otto.rb', line 27 def routes_literal @routes_literal end |
#routes_static ⇒ Object (readonly)
Returns the value of attribute routes_static.
27 28 29 |
# File 'lib/otto.rb', line 27 def routes_static @routes_static end |
#server_error ⇒ Object
Returns the value of attribute server_error.
29 30 31 |
# File 'lib/otto.rb', line 29 def server_error @server_error end |
#static_route ⇒ Object (readonly)
Returns the value of attribute static_route.
28 29 30 |
# File 'lib/otto.rb', line 28 def static_route @static_route end |
Class Method Details
.default ⇒ Object
287 288 289 290 |
# File 'lib/otto.rb', line 287 def default @default ||= Otto.new @default end |
.env?(*guesses) ⇒ Boolean
300 301 302 |
# File 'lib/otto.rb', line 300 def env? *guesses !guesses.flatten.select { |n| ENV['RACK_ENV'].to_s == n.to_s }.empty? end |
.load(path) ⇒ Object
291 292 293 |
# File 'lib/otto.rb', line 291 def load path default.load path end |
.path(definition, params = {}) ⇒ Object
294 295 296 |
# File 'lib/otto.rb', line 294 def path definition, params={} default.path definition, params end |
.routes ⇒ Object
297 298 299 |
# File 'lib/otto.rb', line 297 def routes default.routes end |
Instance Method Details
#call(env) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/otto.rb', line 69 def call env if option[:public] && File.owned?(option[:public]) @static_route ||= Rack::File.new(option[:public]) end path_info = Rack::Utils.unescape(env['PATH_INFO']) path_info = '/' if path_info.to_s.empty? path_info_clean = path_info.gsub /\/$/, '' base_path = File.split(path_info).first # Files in the root directory can refer to themselves base_path = path_info if base_path == '/' http_verb = env['REQUEST_METHOD'].upcase.to_sym literal_routes = routes_literal[http_verb] || {} literal_routes.merge! routes_literal[:GET] if http_verb == :HEAD if static_route && http_verb == :GET && routes_static[:GET].member?(base_path) #STDERR.puts " request: #{path_info} (static)" static_route.call(env) elsif literal_routes.has_key?(path_info_clean) route = literal_routes[path_info_clean] #STDERR.puts " request: #{http_verb} #{path_info} (literal route: #{route.verb} #{route.path})" route.call(env) elsif static_route && http_verb == :GET && safe_file?(path_info) static_path = File.join(option[:public], base_path) STDERR.puts " new static route: #{base_path} (#{path_info})" routes_static[:GET][base_path] = base_path static_route.call(env) else extra_params = {} found_route = nil valid_routes = routes[http_verb] || [] valid_routes.push *routes[:GET] if http_verb == :HEAD valid_routes.each { |route| #STDERR.puts " request: #{http_verb} #{path_info} (trying route: #{route.verb} #{route.pattern})" if (match = route.pattern.match(path_info)) values = match.captures.to_a # The first capture returned is the entire matched string b/c # we wrapped the entire regex in parens. We don't need it to # the full match. full_match = values.shift extra_params = if route.keys.any? route.keys.zip(values).inject({}) do |hash,(k,v)| if k == 'splat' (hash[k] ||= []) << v else hash[k] = v end hash end elsif values.any? {'captures' => values} else {} end found_route = route break end } found_route ||= literal_routes['/404'] if found_route found_route.call env, extra_params else @not_found || Otto::Static.not_found end end rescue => ex STDERR.puts ex., ex.backtrace if found_route = literal_routes['/500'] found_route.call env else @server_error || Otto::Static.server_error end end |
#load(path) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/otto.rb', line 42 def load path path = File.(path) raise ArgumentError, "Bad path: #{path}" unless File.exists?(path) raw = File.readlines(path).select { |line| line =~ /^\w/ }.collect { |line| line.strip.split(/\s+/) } raw.each { |entry| begin verb, path, definition = *entry route = Otto::Route.new verb, path, definition route.otto = self path_clean = path.gsub /\/$/, '' @route_definitions[route.definition] = route STDERR.puts "route: #{route.pattern}" @routes[route.verb] ||= [] @routes[route.verb] << route @routes_literal[route.verb] ||= {} @routes_literal[route.verb][path_clean] = route rescue => ex STDERR.puts "Bad route in #{path}: #{entry}" end } self end |
#safe_file?(path) ⇒ Boolean
64 65 66 67 68 |
# File 'lib/otto.rb', line 64 def safe_file?(path) globstr = File.join(option[:public], '*') pathstr = File.join(option[:public], path) File.fnmatch?(globstr, pathstr) && File.owned?(pathstr) && !File.directory?(pathstr) end |
#uri(route_definition, params = {}) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/otto.rb', line 148 def uri route_definition, params={} #raise RuntimeError, "Not working" route = @route_definitions[route_definition] unless route.nil? local_params = params.clone local_path = route.path.clone if objid = local_params.delete(:id) || local_params.delete('id') local_path.gsub! /\*/, objid end local_params.each_pair { |k,v| next unless local_path.match(":#{k}") local_path.gsub!(":#{k}", local_params.delete(k)) } uri = Addressable::URI.new uri.path = local_path uri.query_values = local_params uri.to_s end end |