Skip to content

Commit 337d64b

Browse files
ericproulxclaude
andcommitted
Precompute prefix list in Versioner::Path
`Versioner::Path#before` built `[mount_path, Grape::Router.normalize_path(prefix)]` on every request and iterated it, filtering nil/empty/'/' entries with a guard clause on each element. Both `mount_path` and `prefix` are fixed at mount time, so this work is redundant. Memoize a pre-filtered `@prefixes` array in `initialize` (the middleware dup in `Middleware::Base#call` shallow-copies ivars, so the frozen array is shared across request dups for free). The per-request loop simplifies to `if path_info.start_with?(path)`. current 1.09 M i/s, 80KB / 2k objects variant A (memoize normalize) 1.34 M i/s, 80KB / 2k objects variant B (memoize list) 2.61 M i/s, 40KB / 1k objects (2.38x faster, 2x fewer) Shipping variant B. No behavior change; all 2,236 specs pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 66aadad commit 337d64b

2 files changed

Lines changed: 8 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* [#2688](https://github.com/ruby-grape/grape/pull/2688): Consolidate user-registered rescue handler lookup into `Middleware::Error#registered_rescue_handler` backed by a shared `rescue_handler_from` primitive - [@ericproulx](https://github.com/ericproulx).
1313
* [#2689](https://github.com/ruby-grape/grape/pull/2689): Avoid empty-hash merges on request hot paths - [@ericproulx](https://github.com/ericproulx).
1414
* [#2690](https://github.com/ruby-grape/grape/pull/2690): Avoid allocating an empty array on every `StackableValues#[]` miss - [@ericproulx](https://github.com/ericproulx).
15+
* [#2691](https://github.com/ruby-grape/grape/pull/2691): Precompute the prefix list in `Middleware::Versioner::Path` - [@ericproulx](https://github.com/ericproulx).
1516
* Your contribution here.
1617

1718
#### Fixes

lib/grape/middleware/versioner/path.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ module Versioner
1717
# env['api.version'] => 'v1'
1818
#
1919
class Path < Base
20+
def initialize(app, **options)
21+
super
22+
@prefixes = [mount_path, Grape::Router.normalize_path(prefix)].select { |p| p.present? && p != '/' }.freeze
23+
end
24+
2025
def before
2126
path_info = Grape::Router.normalize_path(env[Rack::PATH_INFO])
2227
return if path_info == '/'
2328

24-
[mount_path, Grape::Router.normalize_path(prefix)].each do |path|
25-
path_info = path_info.delete_prefix(path) if path.present? && path != '/' && path_info.start_with?(path)
29+
path_info = @prefixes.reduce(path_info) do |pi, path|
30+
pi.start_with?(path) ? pi.delete_prefix(path) : pi
2631
end
2732

2833
slash_position = path_info.index('/', 1) # omit the first one

0 commit comments

Comments
 (0)