Speed up pluralize and singularize by testing rules with match?
apply_inflections tried each rule with sub! until one matched. For a
typical word almost every rule fails ("comment" only matches the last of
the 33 English plural rules), and a failed sub! is more expensive than a
failed match?. Test each rule with match? (or include? for String rules,
which sub! matches literally) and only call sub! on the rule that
applies.
$ ruby /work/ips/exe/ips --markdown --runs 3 --yjit --sha rails/main /work/bench/inflector_bench.rb
| Benchmark | Commit | i/s | ± | vs rails/main (7a78da5a55) |
| :---------------------------------- | :---------------------- | -------: | ---: | :------------------------- |
| `Inflector.pluralize('comment')` | rails/main (7a78da5a55) | 322.818k | 4.3% | baseline |
| | faster-pluralize | 652.395k | 2.4% | **2.02 ± 0.10× faster** |
| `Inflector.singularize('comments')` | rails/main (7a78da5a55) | 261.245k | 3.2% | baseline |
| | faster-pluralize | 501.091k | 2.6% | **1.92 ± 0.08× faster** |
| `'comment'.pluralize` | rails/main (7a78da5a55) | 319.214k | 3.5% | baseline |
| | faster-pluralize | 651.614k | 2.6% | **2.04 ± 0.09× faster** |
| `view.pluralize(2, 'comment')` | rails/main (7a78da5a55) | 292.516k | 4.0% | baseline |
| | faster-pluralize | 535.690k | 1.7% | **1.83 ± 0.08× faster** |
Benchmark code
`/work/bench/inflector_bench.rb`
```ruby
require "bundler/setup"
require "active_support"
require "active_support/core_ext/string/inflections"
require "action_view"
require "ips"
view = ActionView::Base.empty
IPS.run do |x|
x.report("Inflector.pluralize('comment')") { ActiveSupport::Inflector.pluralize("comment") }
x.report("Inflector.singularize('comments')") { ActiveSupport::Inflector.singularize("comments") }
x.report("'comment'.pluralize") { "comment".pluralize }
x.report("view.pluralize(2, 'comment')") { view.pluralize(2, "comment") }
end
```
Environment
```console
$ ips --markdown --runs 3 --yjit --sha rails/main /work/bench/inflector_bench.rb
```
- `ruby 4.0.9 (2026-10-23 revision 3e93b23afc) +YJIT +PRISM [x86_64-linux]`
- 3 runs, each reported value is the mean across runs
- ips 0.5.0
$ chruby ruby-head
$ ruby /work/ips/exe/ips --markdown --runs 3 --yjit --sha rails/main /work/bench/inflector_bench.rb
| Benchmark | Commit | i/s | ± | vs rails/main (7a78da5a55) |
| :---------------------------------- | :---------------------- | -------: | ----: | :------------------------- |
| `Inflector.pluralize('comment')` | rails/main (7a78da5a55) | 554.713k | 1.6% | baseline |
| | faster-pluralize | 692.430k | 0.7% | **1.25 ± 0.02× faster** |
| `Inflector.singularize('comments')` | rails/main (7a78da5a55) | 434.436k | 0.7% | baseline |
| | faster-pluralize | 524.456k | 0.4% | **1.21 ± 0.01× faster** |
| `'comment'.pluralize` | rails/main (7a78da5a55) | 542.292k | 2.9% | baseline |
| | faster-pluralize | 686.153k | 0.1% | **1.27 ± 0.04× faster** |
| `view.pluralize(2, 'comment')` | rails/main (7a78da5a55) | 440.828k | 12.6% | baseline |
| | faster-pluralize | 575.887k | 0.5% | **1.31 ± 0.16× faster** |
Benchmark code
`/work/bench/inflector_bench.rb`
```ruby
require "bundler/setup"
require "active_support"
require "active_support/core_ext/string/inflections"
require "action_view"
require "ips"
view = ActionView::Base.empty
IPS.run do |x|
x.report("Inflector.pluralize('comment')") { ActiveSupport::Inflector.pluralize("comment") }
x.report("Inflector.singularize('comments')") { ActiveSupport::Inflector.singularize("comments") }
x.report("'comment'.pluralize") { "comment".pluralize }
x.report("view.pluralize(2, 'comment')") { view.pluralize(2, "comment") }
end
```
Environment
```console
$ ips --markdown --runs 3 --yjit --sha rails/main /work/bench/inflector_bench.rb
```
- `ruby 4.1.0dev (2026-10-31) +YJIT +PRISM [x86_64-linux]`
- 3 runs, each reported value is the mean across runs
- ips 0.5.0
|