Permalink
Browse files

Correctly handle phrases in singularize/pluralize.

Currently, the inflector is not set up correctly to handle phrases
(multi-word strings) as input. This ocasionally works right now, but it
is more or less a coincidence. Since Rails internally depend on this
singularize/pluraize being able to handle phrases (see tableize), this
commit fixes the bug and correctly handle phrases in singularize and
pluralize. The following should work as expected after this patch:

   'MyClass'.pluralize # => 'MyClasses'
   'some-slug'.pluralize # => 'some-slugs'
   'saw_fish'.pluralize # => 'saw_fish'
   'optical mouse'.pluralize # => 'optical mice'
   'funky jeans'.singularize # => 'funky jeans'

See #7134 for discussions.
  • Loading branch information...
1 parent fba8a6a commit ca856d6fbb4dc9e3affb2238ffd6d24d20312bac @chancancode committed Jul 23, 2012
View
22 activesupport/lib/active_support/inflector/methods.rb
@@ -312,12 +312,28 @@ def const_regexp(camel_cased_word) #:nodoc:
# apply_inflections("posts", inflections.singulars) # => "post"
def apply_inflections(word, rules)
result = word.to_s.dup
+ prefix, last_word = split_phrase(result)
- if word.empty? || inflections.uncountables.include?(result.downcase[/[a-z0-9]+\Z/])
+ if word.empty? || inflections.uncountables.include?(last_word.downcase)
result
else
- rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
- result
+ rules.each { |(rule, replacement)| break if last_word.sub!(rule, replacement) }
+ prefix + last_word
+ end
+ end
+
+ # Split a phrase into two chunks for +apply_inflections+:
+ # split_phrase('word') # => ['', 'word']
+ # split_phrase('two words') # => ['two ', 'words']
+ # split_phrase('two_words') # => ['two_', 'words']
+ # split_phrase('two-words') # => ['two-', 'words']
+ # split_phrase('myWord') # => ['my','Word']
+ # split_phrase('many many words') # => ['many many ','words']
+ def split_phrase(phrase)
+ if last_word = underscore(phrase)[/[a-z0-9]+\Z/i]
+ [phrase[0...-last_word.length], phrase[-last_word.length..-1]]
+ else
+ [phrase, '']
end
end
end
View
12 activesupport/test/inflector_test.rb
@@ -17,6 +17,18 @@ def test_pluralize_empty_string
assert_equal "", ActiveSupport::Inflector.pluralize("")
end
+ def test_pluralize_camel_case_string
+ assert_equal "camelCases", ActiveSupport::Inflector.pluralize("camelCase")
+ assert_equal "OpticalMice", ActiveSupport::Inflector.pluralize("OpticalMouse")
+ assert_equal "SawFish", ActiveSupport::Inflector.pluralize("SawFish")
+ end
+
+ def test_singularize_camel_case_string
+ assert_equal "camelCase", ActiveSupport::Inflector.singularize("camelCases")
+ assert_equal "OpticalMouse", ActiveSupport::Inflector.singularize("OpticalMice")
+ assert_equal "SawFish", ActiveSupport::Inflector.singularize("SawFish")
+ end
+
ActiveSupport::Inflector.inflections.uncountable.each do |word|
define_method "test_uncountability_of_#{word}" do
assert_equal word, ActiveSupport::Inflector.singularize(word)
View
2 activesupport/test/inflector_test_cases.rb
@@ -15,6 +15,7 @@ module InflectorTestCases
"jeans" => "jeans",
"funky jeans" => "funky jeans",
"my money" => "my money",
+ "your mouse" => "your mice",
"category" => "categories",
"query" => "queries",
@@ -84,7 +85,6 @@ module InflectorTestCases
"status" => "statuses",
"status_code" => "status_codes",
"mouse" => "mice",
-
"louse" => "lice",
"house" => "houses",
"octopus" => "octopi",

0 comments on commit ca856d6

Please sign in to comment.