Skip to content

Commit

Permalink
Correctly handle phrases in singularize/pluralize.
Browse files Browse the repository at this point in the history
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 rails#7134 for discussions.
  • Loading branch information
chancancode committed Jul 23, 2012
1 parent fba8a6a commit ca856d6
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
22 changes: 19 additions & 3 deletions activesupport/lib/active_support/inflector/methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions activesupport/test/inflector_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion activesupport/test/inflector_test_cases.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module InflectorTestCases
"jeans" => "jeans",
"funky jeans" => "funky jeans",
"my money" => "my money",
"your mouse" => "your mice",

"category" => "categories",
"query" => "queries",
Expand Down Expand Up @@ -84,7 +85,6 @@ module InflectorTestCases
"status" => "statuses",
"status_code" => "status_codes",
"mouse" => "mice",

"louse" => "lice",
"house" => "houses",
"octopus" => "octopi",
Expand Down

0 comments on commit ca856d6

Please sign in to comment.