Skip to content

Commit 81f1ca2

Browse files
committed
Avoid #any? since via is usually singular
`Route#matches? currently calls `#any?` to match the Route's array of request method matchers against the request. Even though the array of matching request methods is often only one element, every Route ends up paying the cost of `#any?`. This commit addresses this cost by specializing the matcher to always be a single object. For Routes with only one matching request method, the matcher can be called directly. For Routes with multiple matching request methods, a new Matcher was introduced to iterate the matchers as before.
1 parent 7e0fab6 commit 81f1ca2

File tree

2 files changed

+30
-23
lines changed

2 files changed

+30
-23
lines changed

actionpack/lib/action_dispatch/journey/route.rb

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,29 +38,50 @@ def self.call(_); true; end
3838
def self.verb; ""; end
3939
end
4040

41+
class Or
42+
attr_reader :verb
43+
44+
def initialize(verbs)
45+
@verbs = verbs
46+
@verb = @verbs.map(&:verb).join("|")
47+
end
48+
49+
def call(req)
50+
@verbs.any? { |v| v.call req }
51+
end
52+
end
53+
4154
VERB_TO_CLASS = VERBS.each_with_object(all: All) do |verb, hash|
4255
klass = const_get verb
4356
hash[verb] = klass
4457
hash[verb.downcase] = klass
4558
hash[verb.downcase.to_sym] = klass
4659
end
47-
end
4860

49-
def self.verb_matcher(verb)
50-
VerbMatchers::VERB_TO_CLASS.fetch(verb) do
61+
VERB_TO_CLASS.default_proc = proc do |_, verb|
5162
VerbMatchers::Unknown.new verb.to_s.dasherize.upcase
5263
end
64+
65+
def self.for(verbs)
66+
if verbs.any? { |v| VERB_TO_CLASS[v] == All }
67+
All
68+
elsif verbs.one?
69+
VERB_TO_CLASS[verbs.first]
70+
else
71+
Or.new(verbs.map { |v| VERB_TO_CLASS[v] })
72+
end
73+
end
5374
end
5475

5576
##
5677
# +path+ is a path constraint.
5778
# `constraints` is a hash of constraints to be applied to this route.
58-
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false, source_location: nil)
79+
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, via: nil, precedence: 0, scope_options: {}, internal: false, source_location: nil)
5980
@name = name
6081
@app = app
6182
@path = path
6283

63-
@request_method_match = request_method_match
84+
@request_method_match = via && VerbMatchers.for(via)
6485
@constraints = constraints
6586
@defaults = defaults
6687
@required_defaults = nil
@@ -146,7 +167,7 @@ def dispatcher?
146167
end
147168

148169
def matches?(request)
149-
match_verb(request) &&
170+
@request_method_match.call(request) &&
150171
constraints.all? { |method, value|
151172
case value
152173
when Regexp, String
@@ -168,21 +189,12 @@ def ip
168189
end
169190

170191
def requires_matching_verb?
171-
!@request_method_match.all? { |x| x == VerbMatchers::All }
192+
@request_method_match != VerbMatchers::All
172193
end
173194

174195
def verb
175-
verbs.join("|")
196+
@request_method_match.verb
176197
end
177-
178-
private
179-
def verbs
180-
@request_method_match.map(&:verb)
181-
end
182-
183-
def match_verb(request)
184-
@request_method_match.any? { |m| m.call request }
185-
end
186198
end
187199
end
188200
# :startdoc:

actionpack/lib/action_dispatch/routing/mapper.rb

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def initialize(set:, ast:, controller:, default_action:, to:, formatted:, via:,
183183
def make_route(name, precedence)
184184
Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
185185
required_defaults: required_defaults, defaults: defaults,
186-
request_method_match: request_method, precedence: precedence,
186+
via: @via, precedence: precedence,
187187
scope_options: scope_options, internal: @internal, source_location: route_source_location)
188188
end
189189

@@ -204,11 +204,6 @@ def build_conditions(current_conditions, request_class)
204204
end
205205
private :build_conditions
206206

207-
def request_method
208-
@via.map { |x| Journey::Route.verb_matcher(x) }
209-
end
210-
private :request_method
211-
212207
private
213208
def intern(object)
214209
object.is_a?(String) ? -object : object

0 commit comments

Comments
 (0)