Object
Basic RouteSet initializer.
If a block is given, the set is yielded and finalized.
See other aspects for other valid options:
Generation::RouteSet.new
Recognition::RouteSet.new
# File lib/rack/mount/route_set.rb, line 21 21: def initialize(options = {}, &block) 22: @parameters_key = options.delete(:parameters_key) || 'rack.routing_args' 23: @parameters_key.freeze 24: 25: @named_routes = {} 26: 27: @recognition_key_analyzer = Analysis::Splitting.new 28: @generation_key_analyzer = Analysis::Frequency.new 29: 30: @request_class = options.delete(:request_class) || Rack::Request 31: @valid_conditions = @request_class.public_instance_methods.map! { |m| m.to_sym } 32: 33: extend CodeGeneration unless options[:_optimize] == false 34: @optimized_recognize_defined = false 35: 36: @routes = [] 37: expire! 38: 39: if block_given? 40: yield self 41: rehash 42: end 43: end
Initialize a new RouteSet without optimizations
# File lib/rack/mount/route_set.rb, line 10 10: def self.new_without_optimizations(options = {}, &block) 11: new(options.merge(:_optimize => false), &block) 12: end
Builder method to add a route to the set
app | A valid Rack app to call if the conditions are met. |
conditions | A hash of conditions to match against. Conditions may be expressed as strings or regexps to match against. |
defaults | A hash of values that always gets merged in |
name | Symbol identifier for the route used with named route generations |
# File lib/rack/mount/route_set.rb, line 54 54: def add_route(app, conditions = {}, defaults = {}, name = nil) 55: unless conditions.is_a?(Hash) 56: raise ArgumentError, 'conditions must be a Hash' 57: end 58: 59: unless conditions.all? { |method, pattern| 60: @valid_conditions.include?(method) 61: } 62: raise ArgumentError, 'conditions may only include ' + 63: @valid_conditions.inspect 64: end 65: 66: route = Route.new(app, conditions, defaults, name) 67: @routes << route 68: 69: @recognition_key_analyzer << route.conditions 70: 71: @named_routes[route.name] = route if route.name 72: @generation_key_analyzer << route.generation_keys 73: 74: expire! 75: route 76: end
Rack compatible recognition and dispatching method. Routes are tried until one returns a non-catch status code. If no routes match, the catch status code is returned.
This method can only be invoked after the RouteSet has been finalized.
# File lib/rack/mount/route_set.rb, line 132 132: def call(env) 133: raise 'route set not finalized' unless @recognition_graph 134: 135: env[PATH_INFO] = Utils.normalize_path(env[PATH_INFO]) 136: 137: request = nil 138: req = @request_class.new(env) 139: recognize(req) do |route, matches, params| 140: # TODO: We only want to unescape params from uri related methods 141: params.each { |k, v| params[k] = Utils.unescape_uri(v) if v.is_a?(String) } 142: 143: if route.prefix? 144: env[Prefix::KEY] = matches[:path_info].to_s 145: end 146: 147: env[@parameters_key] = params 148: result = route.app.call(env) 149: return result unless result[1][X_CASCADE] == PASS 150: end 151: 152: request || [404, {'Content-Type' => 'text/html', 'X-Cascade' => 'pass'}, ['Not Found']] 153: end
Finalizes the set and builds optimized data structures. You must freeze the set before you can use call and url. So remember to call freeze after you are done adding routes.
# File lib/rack/mount/route_set.rb, line 261 261: def freeze 262: unless frozen? 263: rehash 264: 265: @recognition_key_analyzer = nil 266: @generation_key_analyzer = nil 267: @valid_conditions = nil 268: 269: @routes.each { |route| route.freeze } 270: @routes.freeze 271: end 272: 273: super 274: end
Number of routes in the set
# File lib/rack/mount/route_set.rb, line 243 243: def length 244: @routes.length 245: end
# File lib/rack/mount/route_set.rb, line 78 78: def recognize(obj) 79: raise 'route set not finalized' unless @recognition_graph 80: 81: cache = {} 82: keys = @recognition_keys.map { |key| 83: if key.respond_to?(:call) 84: key.call(cache, obj) 85: else 86: obj.send(key) 87: end 88: } 89: 90: @recognition_graph[*keys].each do |route| 91: matches = {} 92: params = route.defaults.dup 93: 94: if route.conditions.all? { |method, condition| 95: value = obj.send(method) 96: if condition.is_a?(Regexp) && (m = value.match(condition)) 97: matches[method] = m 98: captures = m.captures 99: route.named_captures[method].each do |k, i| 100: if v = captures[i] 101: params[k] = v 102: end 103: end 104: true 105: elsif value == condition 106: true 107: else 108: false 109: end 110: } 111: if block_given? 112: yield route, matches, params 113: else 114: return route, matches, params 115: end 116: end 117: end 118: 119: nil 120: end
Generates a url from Rack env and identifiers or significant keys.
To generate a url by named route, pass the name in as a Symbol.
url(env, :dashboard) # => "/dashboard"
Additional parameters can be passed in as a hash
url(env, :people, :id => "1") # => "/people/1"
If no name route is given, it will fall back to a slower generation search.
url(env, :controller => "people", :action => "show", :id => "1") # => "/people/1"
# File lib/rack/mount/route_set.rb, line 167 167: def url(env, *args) 168: named_route, params = nil, {} 169: 170: case args.length 171: when 2 172: named_route, params = args[0], args[1].dup 173: when 1 174: if args[0].is_a?(Hash) 175: params = args[0].dup 176: else 177: named_route = args[0] 178: end 179: else 180: raise ArgumentError 181: end 182: 183: only_path = params.delete(:only_path) 184: recall = env[@parameters_key] || {} 185: 186: unless result = generate(:all, named_route, params, recall, 187: :parameterize => lambda { |name, param| Utils.escape_uri(param) }) 188: return 189: end 190: 191: parts, params = result 192: return unless parts 193: 194: params.each do |k, v| 195: if v 196: params[k] = v 197: else 198: params.delete(k) 199: end 200: end 201: 202: req = stubbed_request_class.new(env) 203: req._stubbed_values = parts.merge(:query_string => Utils.build_nested_query(params)) 204: only_path ? req.fullpath : req.url 205: end
# File lib/rack/mount/route_set.rb, line 297 297: def recognition_stats 298: { :keys => @recognition_keys, 299: :keys_size => @recognition_keys.size, 300: :graph_size => @recognition_graph.size, 301: :graph_height => @recognition_graph.height, 302: :graph_average_height => @recognition_graph.average_height } 303: end
# File lib/rack/mount/route_set.rb, line 349 349: def build_generation_graph 350: build_nested_route_set(@generation_keys) { |k, i| 351: throw :skip unless @routes[i].significant_params? 352: 353: if k = @generation_key_analyzer.possible_keys[i][k] 354: k.to_s 355: else 356: nil 357: end 358: } 359: end
# File lib/rack/mount/route_set.rb, line 361 361: def build_generation_keys 362: keys = @generation_key_analyzer.report 363: Utils.debug "generation keys - #{keys.inspect}" 364: keys 365: end
An internal helper method for constructing a nested set from the linear route set.
build_nested_route_set([:request_method, :path_info]) { |route, method|
route.send(method)
}
# File lib/rack/mount/route_set.rb, line 324 324: def build_nested_route_set(keys, &block) 325: graph = Multimap.new 326: @routes.each_with_index do |route, index| 327: catch(:skip) do 328: k = keys.map { |key| block.call(key, index) } 329: Utils.pop_trailing_blanks!(k) 330: k.map! { |key| key || /.*/ } 331: graph[*k] = route 332: end 333: end 334: graph 335: end
# File lib/rack/mount/route_set.rb, line 337 337: def build_recognition_graph 338: build_nested_route_set(@recognition_keys) { |k, i| 339: @recognition_key_analyzer.possible_keys[i][k] 340: } 341: end
# File lib/rack/mount/route_set.rb, line 343 343: def build_recognition_keys 344: keys = @recognition_key_analyzer.report 345: Utils.debug "recognition keys - #{keys.inspect}" 346: keys 347: end
# File lib/rack/mount/route_set.rb, line 367 367: def extract_params!(*args) 368: case args.length 369: when 4 370: named_route, params, recall, options = args 371: when 3 372: if args[0].is_a?(Hash) 373: params, recall, options = args 374: else 375: named_route, params, recall = args 376: end 377: when 2 378: if args[0].is_a?(Hash) 379: params, recall = args 380: else 381: named_route, params = args 382: end 383: when 1 384: if args[0].is_a?(Hash) 385: params = args[0] 386: else 387: named_route = args[0] 388: end 389: else 390: raise ArgumentError 391: end 392: 393: named_route ||= nil 394: params ||= {} 395: recall ||= {} 396: options ||= {} 397: 398: [named_route, params.dup, recall.dup, options.dup] 399: end
# File lib/rack/mount/route_set.rb, line 314 314: def instance_variables_to_serialize 315: instance_variables.map { |ivar| ivar.to_sym } - [:@stubbed_request_class, :@optimized_recognize_defined] 316: end
# File lib/rack/mount/route_set.rb, line 401 401: def stubbed_request_class 402: @stubbed_request_class ||= begin 403: klass = Class.new(@request_class) 404: klass.public_instance_methods.each do |method| 405: next if method =~ /^__|object_id/ 406: klass.class_eval def #{method}(*args, &block) @_stubbed_values[:#{method}] || super end 407: end 408: klass.class_eval { attr_accessor :_stubbed_values } 409: klass 410: end 411: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.