Skip to content

Commit 2ab34cd

Browse files
committed
Optimize access to the en inflections
The `en` inflector is almost always the one used for itnernal framework inflections, hence it's called much more than any other. Hence it's worth having a fast path for it. Before: ``` ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +YJIT +PRISM [arm64-darwin24] Calculating ------------------------------------- regular 278.450k (± 1.1%) i/s (3.59 μs/i) - 1.401M in 5.030803s irregular 1.320M (± 0.9%) i/s (757.36 ns/i) - 6.617M in 5.012038s uncountable 2.417M (± 0.5%) i/s (413.72 ns/i) - 12.172M in 5.035810s ``` After: ``` ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +YJIT +PRISM [arm64-darwin24] Calculating ------------------------------------- regular 297.666k (± 1.3%) i/s (3.36 μs/i) - 1.509M in 5.068638s irregular 1.975M (± 0.6%) i/s (506.28 ns/i) - 9.939M in 5.031926s uncountable 6.078M (± 0.5%) i/s (164.54 ns/i) - 30.504M in 5.019120s ``` Benchmark: ``` require "bundler/inline" gemfile do gem "rails", path: "." gem "benchmark-ips" end Benchmark.ips do |x| x.report("regular") { ActiveSupport::Inflector.pluralize("test") } x.report("irregular") { ActiveSupport::Inflector.pluralize("zombie") } x.report("uncountable") { ActiveSupport::Inflector.pluralize("sheep") } end ```
1 parent a758c22 commit 2ab34cd

File tree

2 files changed

+12
-3
lines changed

2 files changed

+12
-3
lines changed

activesupport/lib/active_support/inflector/inflections.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ module Inflector
3030
# before any of the rules that may already have been loaded.
3131
class Inflections
3232
@__instance__ = Concurrent::Map.new
33+
@__en_instance__ = nil
3334

3435
class Uncountables # :nodoc:
3536
include Enumerable
@@ -74,10 +75,14 @@ def uncountable?(str)
7475
end
7576

7677
def self.instance(locale = :en)
78+
return @__en_instance__ ||= new if locale == :en
79+
7780
@__instance__[locale] ||= new
7881
end
7982

8083
def self.instance_or_fallback(locale)
84+
return @__en_instance__ ||= new if locale == :en
85+
8186
I18n.fallbacks[locale].each do |k|
8287
return @__instance__[k] if @__instance__.key?(k)
8388
end

activesupport/test/inflector_test.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@ def setup
1616
# This helper is implemented by setting @__instance__ because in some tests
1717
# there are module functions that access ActiveSupport::Inflector.inflections,
1818
# so we need to replace the singleton itself.
19-
@original_inflections = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en]
20-
ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: @original_inflections.dup)
19+
@original_inflections = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)
20+
@original_inflection_en = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__en_instance__)
21+
22+
ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, {})
23+
ActiveSupport::Inflector::Inflections.instance_variable_set(:@__en_instance__, @original_inflection_en.dup)
2124
end
2225

2326
def teardown
24-
ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: @original_inflections)
27+
ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, @original_inflections)
28+
ActiveSupport::Inflector::Inflections.instance_variable_set(:@__en_instance__, @original_inflection_en)
2529
end
2630

2731
def test_pluralize_plurals

0 commit comments

Comments
 (0)