Skip to content

Commit

Permalink
Adds ability to specify custom small words and acronyms
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Santry committed Apr 13, 2017
1 parent 185a433 commit 1847ca8
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 12 deletions.
58 changes: 51 additions & 7 deletions lib/titleize.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,25 @@ module Titleize
#
# "notes on a scandal" # => "Notes on a Scandal"
# "the good german" # => "The Good German"
def titleize(title)
#
# Pass additional small words in opts[:small_words]
#
# titleize("coffee w cream", small_words: ['w']) # => "Coffee w Cream"
#
# For strings in ALL CAPS, specify acronyms to be preserved in opts[:acronyms]
#
# titleize("SMITH TO HEAD SEC", acronyms: ['SEC']) # => "Smith to Head SEC"
#
def titleize(title, opts={})
title = title.dup
title.downcase! unless title[/[[:lower:]]/] # assume all-caps need fixing

small_words = SMALL_WORDS + (opts[:small_words] || [])
small_words = small_words + small_words.map { |small| small.capitalize }

acronyms = opts[:acronyms] || []
acronyms = acronyms + acronyms.map { |acronym| acronym.downcase }

phrases(title).map do |phrase|
words = phrase.split
words.map.with_index do |word, index|
Expand All @@ -40,12 +55,14 @@ def word.capitalize
word
when /^[[:digit:]]/ # first character is a number
word
when *(SMALL_WORDS + SMALL_WORDS.map {|small| small.capitalize })
when *small_words
if index == 0 || index == words.size - 1
word.capitalize
else
word.downcase
end
when *acronyms
word.upcase
else
word.capitalize
end
Expand Down Expand Up @@ -87,17 +104,26 @@ class String
#
# "notes on a scandal" # => "Notes on a Scandal"
# "the good german" # => "The Good German"
#
# Pass additional small words in opts[:small_words]
#
# titleize("coffee w cream", small_words: ['w']) # => "Coffee w Cream"
#
# For strings in ALL CAPS, specify acronyms to be preserved in opts[:acronyms]
#
# titleize("SMITH TO HEAD SEC", acronyms: ['SEC']) # => "Smith to Head SEC"
#
def titleize(opts={})
if defined? ActiveSupport::Inflector
ActiveSupport::Inflector.titleize(self, opts)
else
Titleize.titleize(self)
Titleize.titleize(self, opts)
end
end
alias_method :titlecase, :titleize

def titleize!
replace(titleize)
def titleize!(opts={})
replace(titleize(opts))
end
alias_method :titlecase!, :titleize!
end
Expand All @@ -114,19 +140,37 @@ module ActiveSupport::Inflector
# This replaces the default Rails titleize. Like the default, it uses
# Inflector.underscore and Inflector.humanize to convert
# underscored_names and CamelCaseNames to a more human form. However, you can change
# this behavior by passing :humanize => false or :underscore => false as options.
# this behavior by passing :humanize => false or :underscore => false as options.
# This can be useful when dealing with words like "iPod" and "GPS".
#
# titleize is also aliased as titlecase.
#
# "notes on an active_record" # => "Notes on an Active Record"
# "the GoodGerman" # => "The Good German"
#
# Pass additional small words in opts[:small_words]
#
# titleize("coffee w cream", small_words: ['w']) # => "Coffee w Cream"
#
# For strings in ALL CAPS, acronyms specified in
# ActiveSupport::Inflector.inflections.acronyms will be properly
# capitalized. To override the set of acronyms used, pass in
# opts[:acronyms]
#
# titleize("SMITH TO HEAD SEC", acronyms: ['SEC']) # => "Smith to Head SEC"
#
def titleize(title, opts={})
opts = {:humanize => true, :underscore => true}.merge(opts)
title = ActiveSupport::Inflector.underscore(title) if opts[:underscore]
title = ActiveSupport::Inflector.humanize(title) if opts[:humanize]

Titleize.titleize(title)
# prioritize passed-in acronyms, fall back to those configured
# for ActiveSupport::Inflector
opts[:acronyms] ||= ActiveSupport::Inflector.inflections.acronyms

passthru_opts = opts.select { |k, _| [:acronyms, :small_words].include?(k) }

Titleize.titleize(title, passthru_opts)
end
alias_method :titlecase, :titleize
end
Expand Down
38 changes: 33 additions & 5 deletions spec/titleize_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# -*- coding: utf-8 -*-

module ActiveSupport
module Inflector
require 'ostruct'

#stub
def underscore(string) string; end
def humanize(string) string; end
def inflections
OpenStruct.new(acronyms: [])
end
end
end

Expand Down Expand Up @@ -102,11 +106,29 @@ def humanize(string) string; end
end
end

it "should not capitalize custom small words specified in opts[:small_words]" do
titleize("first w last", small_words: ['w']).should == "First w Last"
end

it "should not screw up acronyms" do
titleize("the SEC's decision").should == "The SEC's Decision"
end

it "should not capitalize words with dots" do
context "handling acronyms" do
context "in a mixed-case string" do
it "should not screw up acronyms" do
titleize("the SEC's decision").should == "The SEC's Decision"
end
end

context "in an uppercase string with the acronyms option specified" do
it 'keeps the acronyms in upper case' do
titleize("SMITH TO HEAD SEC", acronyms: ['SEC']).should == "Smith to Head SEC"
end
end
end

it "should not capitalize words with dots" do
titleize("del.icio.us web site").should == "del.icio.us Web Site"
end

Expand All @@ -115,7 +137,7 @@ def humanize(string) string; end
titleize("ends with 'quotation.'").should == "Ends With 'Quotation.'"
end

it "should not capitalize words that have a lowercase first letter" do
it "should not capitalize words that have a lowercase first letter" do
titleize("iTunes").should == "iTunes"
end

Expand Down Expand Up @@ -263,7 +285,7 @@ def humanize(string) string; end
end

it "should replace Inflector.titleize" do
Titleize.should_receive(:titleize).with(@title)
Titleize.should_receive(:titleize).with(@title, acronyms: [])
ActiveSupport::Inflector.stub!(:underscore).and_return(@title)
ActiveSupport::Inflector.stub!(:humanize).and_return(@title)
ActiveSupport::Inflector.titleize(@title)
Expand Down Expand Up @@ -326,6 +348,12 @@ def humanize(string) string; end
ActiveSupport::Inflector.should_not_receive(:humanize)
"title".titleize(:humanize => false)
end

it "should properly capitalize acronyms configured in Inflector.inflections.acronyms" do
inflections = double(acronyms: ['SEC'])
ActiveSupport::Inflector.stub!(:inflections).and_return(inflections)
"SMITH TO HEAD SEC".titleize.should == 'Smith to Head SEC'
end
end

context "when ActiveSupport is not loaded" do
Expand All @@ -338,7 +366,7 @@ def humanize(string) string; end
end

it "should call Titleize#titleize" do
Titleize.should_receive(:titleize).with("title")
Titleize.should_receive(:titleize).with("title", {})
"title".titleize
end
end
Expand Down

0 comments on commit 1847ca8

Please sign in to comment.