diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index b1544f6eac1d38d80625f2c0bba0b2b0b2c1a325..9e63a2bb17319ff968d50539920c829f32f47ec9 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,10 @@ +* Add `capitalize` option to Inflector.humanize, so strings can be humanized without being capitalized: + + 'employee_salary'.humanize # => "Employee salary" + 'employee_salary'.humanize(capitalize: false) # => "employee salary" + + *claudiob* + * Fixed Object#as_json and Struct#as_json not working properly with options. They now take the same options as Hash#as_json: diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 56e8a5f98dc001704002b7283f125545390e78fb..b7b750c77b7b0fc47edfe8c0cd3c69e75d9eb52f 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -190,13 +190,19 @@ def classify ActiveSupport::Inflector.classify(self) end - # Capitalizes the first word, turns underscores into spaces, and strips '_id'. + # Capitalizes the first word, turns underscores into spaces, and strips a + # trailing '_id' if present. # Like +titleize+, this is meant for creating pretty output. # - # 'employee_salary'.humanize # => "Employee salary" - # 'author_id'.humanize # => "Author" - def humanize - ActiveSupport::Inflector.humanize(self) + # The capitalization of the first word can be turned off by setting the + # optional parameter +capitalize+ to false. + # By default, this parameter is true. + # + # 'employee_salary'.humanize # => "Employee salary" + # 'author_id'.humanize # => "Author" + # 'author_id'.humanize(capitalize: false) # => "author" + def humanize(options = {}) + ActiveSupport::Inflector.humanize(self, options) end # Creates a foreign key name from a class name. diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index ffdb7b53c479e2175d500c89667555b6ae450dc6..0f7ae98a8a5914e65afd1bd9a8392c95b64b990a 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -98,20 +98,26 @@ def underscore(camel_cased_word) word end - # Capitalizes the first word and turns underscores into spaces and strips a - # trailing "_id", if any. Like +titleize+, this is meant for creating pretty - # output. - # - # 'employee_salary'.humanize # => "Employee salary" - # 'author_id'.humanize # => "Author" - def humanize(lower_case_and_underscored_word) + # Capitalizes the first word, turns underscores into spaces, and strips a + # trailing '_id' if present. + # Like +titleize+, this is meant for creating pretty output. + # + # The capitalization of the first word can be turned off by setting the + # optional parameter +capitalize+ to false. + # By default, this parameter is true. + # + # humanize('employee_salary') # => "Employee salary" + # humanize('author_id') # => "Author" + # humanize('author_id', capitalize: false) # => "author" + def humanize(lower_case_and_underscored_word, options = {}) result = lower_case_and_underscored_word.to_s.dup inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) } result.gsub!(/_id$/, "") result.tr!('_', ' ') - result.gsub(/([a-z\d]*)/i) { |match| + result.gsub!(/([a-z\d]*)/i) { |match| "#{inflections.acronyms[match] || match.downcase}" - }.gsub(/^\w/) { $&.upcase } + } + options.fetch(:capitalize, true) ? result.gsub(/^\w/) { $&.upcase } : result end # Capitalizes all the words and replaces some characters in the string to diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 3cb66d4eec5d52fe2bffba588dd9ad8e0fa7d84f..20e3d4802e223fa4c263c26911c8477d5803a8f2 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -155,6 +155,12 @@ def test_humanize end end + def test_humanize_without_capitalize + UnderscoreToHumanWithoutCapitalize.each do |underscore, human| + assert_equal(human, underscore.humanize(capitalize: false)) + end + end + def test_ord assert_equal 97, 'a'.ord assert_equal 97, 'abc'.ord @@ -270,7 +276,7 @@ def test_truncate_multibyte def test_truncate_should_not_be_html_safe assert !"Hello World!".truncate(12).html_safe? end - + def test_remove assert_equal "Summer", "Fast Summer".remove(/Fast /) assert_equal "Summer", "Fast Summer".remove!(/Fast /) diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 32739d45a93cc3a960d202399c15b33babd2214f..6184df481fe717eae9df973604c118d4b5d66c71 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -287,6 +287,12 @@ def test_humanize end end + def test_humanize_without_capitalize + UnderscoreToHumanWithoutCapitalize.each do |underscore, human| + assert_equal(human, ActiveSupport::Inflector.humanize(underscore, capitalize: false)) + end + end + def test_humanize_by_rule ActiveSupport::Inflector.inflections do |inflect| inflect.human(/_cnt$/i, '\1_count') diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index cc36d621381c341216791b9a9710f57bd111ca4d..b34a946baf5c36d28e29a4c1538f7b0026953c57 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -212,6 +212,12 @@ module InflectorTestCases "underground" => "Underground" } + UnderscoreToHumanWithoutCapitalize = { + "employee_salary" => "employee salary", + "employee_id" => "employee", + "underground" => "underground" + } + MixtureToTitleCase = { 'active_record' => 'Active Record', 'ActiveRecord' => 'Active Record', diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 0370e400125ee0eac73eb692429a033002b0ca32..b72ebd63eeb1de9d34be3b2ebdba45af53c28cdc 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -1772,6 +1772,12 @@ The method `humanize` gives you a sensible name for display out of an attribute "comments_count".humanize # => "Comments count" ``` +The capitalization of the first word can be turned off by setting the optional parameter `capitalize` to false: + +```ruby +"author_id".humanize(capitalize: false) # => "author" +``` + The helper method `full_messages` uses `humanize` as a fallback to include attribute names: ```ruby