Skip to content

Commit 84f542c

Browse files
authored
Merge pull request rails#55485 from byroot/uncountables-avoid-genivar
Optimize `#pluralize`
2 parents ae614d3 + 2ab34cd commit 84f542c

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

activesupport/lib/active_support/inflector/inflections.rb

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require "concurrent/map"
4+
require "active_support/core_ext/module/delegation"
45
require "active_support/i18n"
56

67
module ActiveSupport
@@ -29,44 +30,59 @@ module Inflector
2930
# before any of the rules that may already have been loaded.
3031
class Inflections
3132
@__instance__ = Concurrent::Map.new
33+
@__en_instance__ = nil
34+
35+
class Uncountables # :nodoc:
36+
include Enumerable
37+
38+
delegate :each, :pop, :empty?, :to_s, :==, :to_a, :to_ary, to: :@members
3239

33-
class Uncountables < Array
3440
def initialize
35-
@regex_array = []
36-
super
41+
@members = []
42+
@pattern = nil
3743
end
3844

3945
def delete(entry)
40-
super entry
41-
@regex_array.delete(to_regex(entry))
46+
@members.delete(entry)
47+
@pattern = nil
48+
end
49+
50+
def <<(word)
51+
word = word.downcase
52+
@members << word
53+
@pattern = nil
54+
self
4255
end
4356

44-
def <<(*word)
45-
add(word)
57+
def flatten
58+
@members.dup
4659
end
4760

4861
def add(words)
4962
words = words.flatten.map(&:downcase)
50-
concat(words)
51-
@regex_array += words.map { |word| to_regex(word) }
63+
@members.concat(words)
64+
@pattern = nil
5265
self
5366
end
5467

5568
def uncountable?(str)
56-
@regex_array.any? { |regex| regex.match? str }
57-
end
58-
59-
private
60-
def to_regex(string)
61-
/\b#{::Regexp.escape(string)}\Z/i
69+
if @pattern.nil?
70+
members_pattern = Regexp.union(@members.map { |w| /#{Regexp.escape(w)}/i })
71+
@pattern = /\b#{members_pattern}\Z/i
6272
end
73+
@pattern.match?(str)
74+
end
6375
end
6476

6577
def self.instance(locale = :en)
78+
return @__en_instance__ ||= new if locale == :en
79+
6680
@__instance__[locale] ||= new
6781
end
6882

6983
def self.instance_or_fallback(locale)
84+
return @__en_instance__ ||= new if locale == :en
85+
7086
I18n.fallbacks[locale].each do |k|
7187
return @__instance__[k] if @__instance__.key?(k)
7288
end

activesupport/test/inflector_test.rb

Lines changed: 8 additions & 4 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
@@ -623,7 +627,7 @@ def test_clear_all_resets_camelize_and_underscore_regexes
623627

624628
assert_equal [], inflect.singulars
625629
assert_equal [], inflect.plurals
626-
assert_equal [], inflect.uncountables
630+
assert_equal [], inflect.uncountables.to_a
627631

628632
# restore all the inflections
629633
singulars.reverse_each { |singular| inflect.singular(*singular) }

0 commit comments

Comments
 (0)