This project is archived and is in readonly mode.

#6093 ✓resolved
John Paul Ashenfelter

[PATCH] Uncountable singularize uses regex match while pluralize uses exact match leading leading to unexpected collisions

Reported by John Paul Ashenfelter | November 30th, 2010 @ 06:37 PM | in 3.0.5

I have an model named "ors" which is both singular and plural (e.g. it's uncountable)

ActiveSupport::Inflector.inflections do |inflect|
  inflect.uncountable %w( ors )

The inflector works beautifully

"ors".pluralize => "ors"
"ors".singularize => "ors"
"ors".pluralize.singularize => "ors"

Then I add some scaffolding for my Sponsor model and everything goes crazy with the tests -- long story short the pluralization/singularization is not right. I try the same inflecting:

"sponsor".pluralize => "sponsors"
"sponsors".singularize => "sponsors"
"sponsor".pluralize.singularize => "sponsors"

After some WTF time, I try a clean Rails3 project and "sponsors".singularize => "sponsor" as expected, so I realize it might be the "ors" inflection. I add the uncountable "ors" inflection to the clean Rails3 project and get the problematic "sponsors" singular inflection. I remove it, problem stops. I verify it with "razors" to make sure I'm not crazy:

"razor".pluralize => "razors"
"razors".singularize => "razors"
"razor".pluralize.singularize => "razors"

I'm going to assume this was not the intended behavior but I know there's lots of back and forth discussion on inflections and lack of interest in changing them. The core problem for me here was that setting an uncountable inflection had the side effect of changing a number of other inflections (sponsor, donor, razor). The reason I think it's a bug is that it's not reflexive -- "string".pluralize.singularize == "string" IMHO.

The problem is in #singularize on line 151 of

151 if inflections.uncountables.any? { |inflection| result =~ /#{inflection}\Z/i }

The matching #pluralize is specific

132 if word.empty? || inflections.uncountables.include?(result.downcase)

For what it's worth, I couldn't get "ors" to work as an irregular either since that generates ending/suffix matches instead of word matches.

I looked at the tests in ActiveSupport::Inflections and it's also silent on the details of irregular words:

jeans => jeans
funky jeans => funky jeans
bluejeans => ... (it's not there to settle the issue)

If the intention is matching the ending fragment, as #singularize is currently written, then

bluejeans => bluejeans
sponsors => sponsors

given inflect.uncountables = %w( jeans ors)

This is definitely broken for the word "sponsors" since there is a singular that's different.

If instead, the intention is the word, as "funky jeans" suggests, then adding a word boundary to the regex fixes "sponsors" and retains "funky jeans". But it breaks "bluejeans"

It seems like I'm making a big deal, bit the key thing for me is that I can't use "ors" as an @uncountable without breaking things and I can't use it as an irregular because the singular and plurals generated from that match and word containing /or(s)/. Right now, my only solution other than refactoring the name of the object is to manually set the singular and plural

inflect.plural /^(ors)$/i, '\1'
inflect.singular /^(ors)$/i, '\1'

I would have thought that was what uncountable was supposed to do.

Comments and changes to this ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href=""></a>