Skip to content

Commit 1847ca8

Browse files
author
Sean Santry
committed
Adds ability to specify custom small words and acronyms
1 parent 185a433 commit 1847ca8

2 files changed

Lines changed: 84 additions & 12 deletions

File tree

lib/titleize.rb

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,25 @@ module Titleize
1717
#
1818
# "notes on a scandal" # => "Notes on a Scandal"
1919
# "the good german" # => "The Good German"
20-
def titleize(title)
20+
#
21+
# Pass additional small words in opts[:small_words]
22+
#
23+
# titleize("coffee w cream", small_words: ['w']) # => "Coffee w Cream"
24+
#
25+
# For strings in ALL CAPS, specify acronyms to be preserved in opts[:acronyms]
26+
#
27+
# titleize("SMITH TO HEAD SEC", acronyms: ['SEC']) # => "Smith to Head SEC"
28+
#
29+
def titleize(title, opts={})
2130
title = title.dup
2231
title.downcase! unless title[/[[:lower:]]/] # assume all-caps need fixing
2332

33+
small_words = SMALL_WORDS + (opts[:small_words] || [])
34+
small_words = small_words + small_words.map { |small| small.capitalize }
35+
36+
acronyms = opts[:acronyms] || []
37+
acronyms = acronyms + acronyms.map { |acronym| acronym.downcase }
38+
2439
phrases(title).map do |phrase|
2540
words = phrase.split
2641
words.map.with_index do |word, index|
@@ -40,12 +55,14 @@ def word.capitalize
4055
word
4156
when /^[[:digit:]]/ # first character is a number
4257
word
43-
when *(SMALL_WORDS + SMALL_WORDS.map {|small| small.capitalize })
58+
when *small_words
4459
if index == 0 || index == words.size - 1
4560
word.capitalize
4661
else
4762
word.downcase
4863
end
64+
when *acronyms
65+
word.upcase
4966
else
5067
word.capitalize
5168
end
@@ -87,17 +104,26 @@ class String
87104
#
88105
# "notes on a scandal" # => "Notes on a Scandal"
89106
# "the good german" # => "The Good German"
107+
#
108+
# Pass additional small words in opts[:small_words]
109+
#
110+
# titleize("coffee w cream", small_words: ['w']) # => "Coffee w Cream"
111+
#
112+
# For strings in ALL CAPS, specify acronyms to be preserved in opts[:acronyms]
113+
#
114+
# titleize("SMITH TO HEAD SEC", acronyms: ['SEC']) # => "Smith to Head SEC"
115+
#
90116
def titleize(opts={})
91117
if defined? ActiveSupport::Inflector
92118
ActiveSupport::Inflector.titleize(self, opts)
93119
else
94-
Titleize.titleize(self)
120+
Titleize.titleize(self, opts)
95121
end
96122
end
97123
alias_method :titlecase, :titleize
98124

99-
def titleize!
100-
replace(titleize)
125+
def titleize!(opts={})
126+
replace(titleize(opts))
101127
end
102128
alias_method :titlecase!, :titleize!
103129
end
@@ -114,19 +140,37 @@ module ActiveSupport::Inflector
114140
# This replaces the default Rails titleize. Like the default, it uses
115141
# Inflector.underscore and Inflector.humanize to convert
116142
# underscored_names and CamelCaseNames to a more human form. However, you can change
117-
# this behavior by passing :humanize => false or :underscore => false as options.
143+
# this behavior by passing :humanize => false or :underscore => false as options.
118144
# This can be useful when dealing with words like "iPod" and "GPS".
119145
#
120146
# titleize is also aliased as titlecase.
121147
#
122148
# "notes on an active_record" # => "Notes on an Active Record"
123149
# "the GoodGerman" # => "The Good German"
150+
#
151+
# Pass additional small words in opts[:small_words]
152+
#
153+
# titleize("coffee w cream", small_words: ['w']) # => "Coffee w Cream"
154+
#
155+
# For strings in ALL CAPS, acronyms specified in
156+
# ActiveSupport::Inflector.inflections.acronyms will be properly
157+
# capitalized. To override the set of acronyms used, pass in
158+
# opts[:acronyms]
159+
#
160+
# titleize("SMITH TO HEAD SEC", acronyms: ['SEC']) # => "Smith to Head SEC"
161+
#
124162
def titleize(title, opts={})
125163
opts = {:humanize => true, :underscore => true}.merge(opts)
126164
title = ActiveSupport::Inflector.underscore(title) if opts[:underscore]
127165
title = ActiveSupport::Inflector.humanize(title) if opts[:humanize]
128166

129-
Titleize.titleize(title)
167+
# prioritize passed-in acronyms, fall back to those configured
168+
# for ActiveSupport::Inflector
169+
opts[:acronyms] ||= ActiveSupport::Inflector.inflections.acronyms
170+
171+
passthru_opts = opts.select { |k, _| [:acronyms, :small_words].include?(k) }
172+
173+
Titleize.titleize(title, passthru_opts)
130174
end
131175
alias_method :titlecase, :titleize
132176
end

spec/titleize_spec.rb

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# -*- coding: utf-8 -*-
2-
32
module ActiveSupport
43
module Inflector
4+
require 'ostruct'
5+
56
#stub
67
def underscore(string) string; end
78
def humanize(string) string; end
9+
def inflections
10+
OpenStruct.new(acronyms: [])
11+
end
812
end
913
end
1014

@@ -102,11 +106,29 @@ def humanize(string) string; end
102106
end
103107
end
104108

109+
it "should not capitalize custom small words specified in opts[:small_words]" do
110+
titleize("first w last", small_words: ['w']).should == "First w Last"
111+
end
112+
105113
it "should not screw up acronyms" do
106114
titleize("the SEC's decision").should == "The SEC's Decision"
107115
end
108116

109-
it "should not capitalize words with dots" do
117+
context "handling acronyms" do
118+
context "in a mixed-case string" do
119+
it "should not screw up acronyms" do
120+
titleize("the SEC's decision").should == "The SEC's Decision"
121+
end
122+
end
123+
124+
context "in an uppercase string with the acronyms option specified" do
125+
it 'keeps the acronyms in upper case' do
126+
titleize("SMITH TO HEAD SEC", acronyms: ['SEC']).should == "Smith to Head SEC"
127+
end
128+
end
129+
end
130+
131+
it "should not capitalize words with dots" do
110132
titleize("del.icio.us web site").should == "del.icio.us Web Site"
111133
end
112134

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

118-
it "should not capitalize words that have a lowercase first letter" do
140+
it "should not capitalize words that have a lowercase first letter" do
119141
titleize("iTunes").should == "iTunes"
120142
end
121143

@@ -263,7 +285,7 @@ def humanize(string) string; end
263285
end
264286

265287
it "should replace Inflector.titleize" do
266-
Titleize.should_receive(:titleize).with(@title)
288+
Titleize.should_receive(:titleize).with(@title, acronyms: [])
267289
ActiveSupport::Inflector.stub!(:underscore).and_return(@title)
268290
ActiveSupport::Inflector.stub!(:humanize).and_return(@title)
269291
ActiveSupport::Inflector.titleize(@title)
@@ -326,6 +348,12 @@ def humanize(string) string; end
326348
ActiveSupport::Inflector.should_not_receive(:humanize)
327349
"title".titleize(:humanize => false)
328350
end
351+
352+
it "should properly capitalize acronyms configured in Inflector.inflections.acronyms" do
353+
inflections = double(acronyms: ['SEC'])
354+
ActiveSupport::Inflector.stub!(:inflections).and_return(inflections)
355+
"SMITH TO HEAD SEC".titleize.should == 'Smith to Head SEC'
356+
end
329357
end
330358

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

340368
it "should call Titleize#titleize" do
341-
Titleize.should_receive(:titleize).with("title")
369+
Titleize.should_receive(:titleize).with("title", {})
342370
"title".titleize
343371
end
344372
end

0 commit comments

Comments
 (0)