1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
|
require 'rack/mount/generatable_regexp'
require 'rack/mount/regexp_with_named_groups'
require 'rack/mount/utils'
module Rack::Mount
# Route is an internal class used to wrap a single route attributes.
#
# Plugins should not depend on any method on this class or instantiate
# new Route objects. Instead use the factory method, RouteSet#add_route
# to create new routes and add them to the set.
class Route
# Valid rack application to call if conditions are met
attr_reader :app
# A hash of conditions to match against. Conditions may be expressed
# as strings or regexps to match against.
attr_reader :conditions
# A hash of values that always gets merged into the parameters hash
attr_reader :defaults
# Symbol identifier for the route used with named route generations
attr_reader :name
attr_reader :named_captures
def initialize(app, conditions, defaults, name)
unless app.respond_to?(:call)
raise ArgumentError, 'app must be a valid rack application' \
' and respond to call'
end
@app = app
@name = name ? name.to_sym : nil
@defaults = (defaults || {}).freeze
@conditions = {}
conditions.each do |method, pattern|
next unless method && pattern
pattern = Regexp.compile("\\A#{Regexp.escape(pattern)}\\Z") if pattern.is_a?(String)
if pattern.is_a?(Regexp)
pattern = Utils.normalize_extended_expression(pattern)
pattern = RegexpWithNamedGroups.new(pattern)
pattern.extend(GeneratableRegexp::InstanceMethods)
pattern.defaults = @defaults
end
@conditions[method] = pattern.freeze
end
@named_captures = {}
@conditions.map { |method, condition|
next unless condition.respond_to?(:named_captures)
@named_captures[method] = condition.named_captures.inject({}) { |named_captures, (k, v)|
named_captures[k.to_sym] = v.last - 1
named_captures
}.freeze
}
@named_captures.freeze
@has_significant_params = @conditions.any? { |method, condition|
(condition.respond_to?(:required_params) && condition.required_params.any?) ||
(condition.respond_to?(:required_defaults) && condition.required_defaults.any?)
}
if @conditions.has_key?(:path_info) &&
!Utils.regexp_anchored?(@conditions[:path_info])
@prefix = true
@app = Prefix.new(@app)
else
@prefix = false
end
@conditions.freeze
end
def prefix?
@prefix
end
def generation_keys
@conditions.inject({}) { |keys, (method, condition)|
if condition.respond_to?(:required_defaults)
keys.merge!(condition.required_defaults)
else
keys
end
}
end
def significant_params?
@has_significant_params
end
def generate(method, params = {}, recall = {}, options = {})
if method.nil?
result = @conditions.inject({}) { |h, (m, condition)|
if condition.respond_to?(:generate)
h[m] = condition.generate(params, recall, options)
end
h
}
return nil if result.values.compact.empty?
else
if condition = @conditions[method]
if condition.respond_to?(:generate)
result = condition.generate(params, recall, options)
end
end
end
if result
@defaults.each do |key, value|
params.delete(key) if params[key] == value
end
end
result
end
def inspect #:nodoc:
"#<#{self.class.name} @app=#{@app.inspect} @conditions=#{@conditions.inspect} @defaults=#{@defaults.inspect} @name=#{@name.inspect}>"
end
end
end
|