#!/usr/bin/env ruby
# This filter changes all words to Title Caps, and attempts to be clever
# about *un*capitalizing small words like a/an/the in the input.
#
# The list of "small words" which are not capped comes from
# the New York Times Manual of Style, plus 'vs' and 'v'.
#
# John Gruber
# http://daringfireball.net/
# 10 May 2008
#
# Ruby version: Jeremy Ashkenas
# http://ashkenas.com/
# 21 May 2008
#
# License: http://www.opensource.org/licenses/mit-license.php
@small_words = %w(a an and as at but by en for if in of on or the to v[.]? via vs[.]?)
@small_regex = @small_words.join("|")
# Function to capitalize the first character.
def capit(word)
word.sub(/./) { |l| l.upcase }
end
lines = STDIN.readlines
lines.each do |line|
parts = line.split( /( [:.;?!][ ] | (?:[ ]|^)["“] )/x )
parts.each do |part|
part.gsub!(/\b([a-z.'’]+)\b/) do |s|
s =~ /[a-z]\.[a-z]/i ? s : capit(s)
end
# Lowercase the small words
part.gsub!(/\b(#{@small_regex})\b/i) { |w| w.downcase }
# If the first word is a small word, capitalize it.
part.gsub!(/^([^\w\s]*)(#{@small_regex})\b/) { $1 + capit($2) }
# If the last word is a small word, capitalize it.
part.gsub!(/\b(#{@small_regex})([^\w\s]*)$/) { capit($1) + $2 }
end
line = parts.join
# Special cases:
line.gsub!(/ V(s?)\. /, ' v\1. ') # "v." and "vs."
line.gsub!(/(['’])S\b/, '\1s') # 'S (otherwise you get "the SEC'S decision")
line.gsub!(/\b(AT&T|Q&A)\b/i) { |w| w.upcase } # "AT&T" and "Q&A", which get tripped up.
puts line
end