Skip to content

plural? and singular? methods for String #6802

Closed
wants to merge 1 commit into from

7 participants

@butzopower

I wanted to know if a string was plural or singular, so I added string extensions.

@frodsan frodsan commented on the diff Jun 20, 2012
...ort/lib/active_support/core_ext/string/inflections.rb
@@ -41,6 +41,26 @@ def singularize
ActiveSupport::Inflector.singularize(self)
end
+ # Returns true if the string is singular
+ #
+ # 'post'.singular? # => true
+ # 'posts'.singular? # => false
+ # 'sheep'.singular? # => true
+
@frodsan
frodsan added a note Jun 20, 2012

I think you should delete the empty lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dmathieu

Actually, it's not that trivial. We could expect that any plural value is not singular.
Though, it you add a test checking that, you'll see that some inflected values will be considered both as singular and plural.

@butzopower
@butzopower

Sorry, reading my original description, I see where this may have been a bit confusing. I didn't mean I wanted to check if a word was exclusively either singular or was plural, having it return true in both cases for words with the same form would be okay.

@chancancode
Ruby on Rails member

I looked at this I thought, "Hey, I tried to do this before and I thought this is not supposed to work...". In case someone else is wondering about the same thing, here's why:

In Rails <= 3.2:

>> "address".singularize
=> "addres"

For the longest time, (given the "frozen" status of the inflector) I thought this is how it's supposed to be (i.e. singularize is not idempotent), hence what @butzopower proposed would not work.

It turns out this is actually a bug and it was fixed in master in #4719. Based on the test cases in activesupport/test/inflector_test.rb, it does appear the infectors are supposed to be idempotent - at least that's the intention. Therefore what @butzopower proposed is supposed to work on master.

@chancancode
Ruby on Rails member

However, we need to make sure people who uses this understands that this is only as reliable as the infector itself. Edge cases that would normally break the infector would break this also. (Couldn't think of any off the top of my head, most infector "bugs" are around x.pluralize.singularize != x, or the other way around.)

The implications are:

  1. If this doesn't work for you, you would have to fix it yourself by adding your own infector rule. [Unless your problem affects > 50K users. See #2457 ;) ]

  2. This really isn't meant for general purpose use cases (validating user input), because it is not guaranteed that it would work correctly on arbitrary input. Just like the infector itself, it's really designed for things like Rails model names - a limited set of things in your code that you have control over, so that when things do not work the way you expected you can add custom inflector rules to address the problem.

Edit:

Finally I have an example "edge case" for you:

>> 'bonus'.singularize == 'bonus'
=> false

This proves my point that people should not expect this to work for arbitrary input. If you try, you definitely will run into problems very quickly.

@chancancode chancancode and 1 other commented on an outdated diff Jun 21, 2012
activesupport/test/core_ext/string_ext_test.rb
@@ -70,6 +70,24 @@ def test_singularize
end
end
+ def test_plural
+ SingularToPlural.values.each do |plural|
+ assert(plural.plural?)
+ end
+
+ assert(!"search".plural?)
+ assert("fish".plural?)
@chancancode
Ruby on Rails member
chancancode added a note Jun 21, 2012
  1. Why these extra assertions? They should be covered in SingularToPlural already.

  2. Consider mirroring the test cases in https://github.com/rails/rails/blob/master/activesupport/test/inflector_test.rb#L45-71, so that when each of the words are tested separately in their own test case. i.e. When one or more of them failed, the rest will still be tested instead of skipped.

Edit: Nvm my point #2. I was looking at the wrong file (inflector_test.rb). What you are doing here seems to be the norm for this file, so that's probably fine. The extra "search" and "fish" should still be removed though.

@butzopower
butzopower added a note Jun 21, 2012

I realized later that the fish test was redundant.

For "search" I was trying to assert that the method returns false when the string is not the plural form, just to have a negative assertion so that I couldn't make the test pass by just always returning true. I could mock the inflector call to return a different string, if that's preferred.

@chancancode
Ruby on Rails member
chancancode added a note Jun 21, 2012

Ah, that makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@chancancode chancancode and 1 other commented on an outdated diff Jun 21, 2012
...ort/lib/active_support/core_ext/string/inflections.rb
@@ -41,6 +41,26 @@ def singularize
ActiveSupport::Inflector.singularize(self)
end
+ # Returns true if the string is singular
+ #
+ # 'post'.singular? # => true
+ # 'posts'.singular? # => false
+ # 'sheep'.singular? # => true
+
+ def singular?
+ ActiveSupport::Inflector.singularize(self) == self
@chancancode
Ruby on Rails member
chancancode added a note Jun 21, 2012

Having looked at other methods in the file, this logic probably belongs to Active::Support::Infector. I would consider implementing Active::Support::Inflector.singular? and delegate String#singular? to that. (Same thing for plural?) That way, you can still use this even if you prefer to not include the core extensions.

@butzopower
butzopower added a note Jun 21, 2012

Sounds good, thanks for the suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@butzopower

Is there anything else needed on this? I agree that people should not be using it in validations or really any place that has to do with managing persistance. I think some useful cases would be in helpers / presenters. I can up the documentation to make this more clear, but I think there's already a pretty implicit heed to be cautious around the inflector in general.

The issue with bonus seems like a separate issue around inflections, and these methods would return valid results if it were fixed.

@carlosantoniodasilva carlosantoniodasilva and 1 other commented on an outdated diff Jun 25, 2012
activesupport/test/core_ext/string_ext_test.rb
@@ -70,6 +70,22 @@ def test_singularize
end
end
+ def test_plural
+ SingularToPlural.values.each do |plural|
+ assert(plural.plural?)
+ end
+
+ assert(!"search".plural?)
+ end
+
+ def test_singular
+ SingularToPlural.keys.each do |singular|
+ assert(singular.singular?)
+ end
+
+ assert(!"searches".singular?)
+ end
@carlosantoniodasilva
Ruby on Rails member

I think these assertions would look better without (), as in the inflector, wdyt?

@butzopower
butzopower added a note Jun 25, 2012

Sounds good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva
Ruby on Rails member

I think it's a fine addition since we have pluralize and singularize, but I'd like to hear @fxn's feedback first. In any case, some guide updates and a changelog entry would be great :). Thanks!

@butzopower

I assumed this goes in the in the 4.0 changelog, that was right, right?

@chancancode
Ruby on Rails member

Since you branched off master, yes it should go into 4.0 changelog. You might also want to get ready for a clean merge by rebasing against master and squashing commits. Also, take a look at the new instructions for formatting the commit message at http://guides.rubyonrails.org/contributing_to_ruby_on_rails.html#commit-your-changes :)

@butzopower

Alright, squashed and rebased on top of latest rails/master. Lemme know if there's anything else I need to do.

@butzopower

/cc @fxn We'd like to hear your feedback.

@frodsan
frodsan commented Oct 27, 2012

:+1: This needs a rebase.

@fxn fxn was assigned Oct 27, 2012
@butzopower butzopower Adding plural? and singular? to AS:Inflector
Methods to determine if a String is plural or singular by comparing it
to its inflected form.  The methods are defined in the Inflector itself
and then called from methods in the String core extension.
07ed5da
@butzopower

@frodsan Done.

@rafaelfranca
Ruby on Rails member

I'm not a fan of this feature because I don't think a lot of applications will get advantages of it. Also the implementation is so simple that you can add in your application.

The inflector can return some false positive results and this feature will break, leading more pull requests "fixing" the inflectors.

That said I'm closing this one.

Thank you so much for the contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.