Class: Nicetitle::Titlecase

Inherits:
Object
  • Object
show all
Defined in:
lib/nicetitle/titlecase.rb

Constant Summary collapse

SMALL_WORDS =
Regexp.new('\b(a(nd|n|s|t)?|b(ut|y)|en|for|i(f|n)|o(f|n|r)|t(he|o)|vs?\.?)\b').freeze

Class Method Summary collapse

Class Method Details

.is_small_word?(word) ⇒ Boolean

Returns:

  • (Boolean)


5
6
7
# File 'lib/nicetitle/titlecase.rb', line 5

def self.is_small_word?(word)
  SMALL_WORDS.match(word)
end

.titlecase(str) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/nicetitle/titlecase.rb', line 24

def self.titlecase(str)
  # Replace tabs by single space
  # Replace weird spaces by regular space
  str = (str || '').gsub(/\t/, ' ').gsub("\u{2011}", ' ').strip
  return '' if str.empty?

  # Downcase an all-upcase sentence
  str.downcase! if str.scan(/[A-Z]|\s|\W/).length == str.length

  # Split sentence at space boundaries
  word_arr = str.split(' ')

  # Initialize operand array
  operand_arr = Array.new(word_arr.size, :capitalize)

  word_arr.each_with_index do |word, idx|
    # Don't capitalize small words...
    # ... unless it's first word
    # ... unless it's last word
    # ... unless word is preceded by word ending with colon
    operand_arr[idx] = :do_not_upcase  if idx != 0 && idx != word_arr.size - 1 && is_small_word?(word) && word_arr[idx - 1][-1] != ':'
    # Don't simply capitalize first letter if word starts with (, _, ', or "
    operand_arr[idx] = :upcase_later   if word[0].match(/\(|_|'|"/)
    # Capitalize first letter and letters preceded by -
    operand_arr[idx] = :upcase_dashed  if word.count('-') > 0
    # Capitalize letters preceded by / inside word
    operand_arr[idx] = :upcase_slashed if word[1..].count('/') > 0
    # Don't capitalize word if it starts with /
    operand_arr[idx] = :do_not_upcase  if word[0] == '/'
    # Don't capitalize URLs
    operand_arr[idx] = :do_not_upcase  if word.match(/https?:\/\//i)
    # Don't capitalize words containing capitals besides first letter
    # Don't capitalize words containing dots inside word
    operand_arr[idx] = :do_not_upcase  if word[1..].match(/[A-Z]/) || word[1..-3].match(/\.|&/)
  end

  word_arr.each_with_index do |word, idx|
    word_arr[idx] = upcase_first_real_letter(word) if operand_arr[idx] == :upcase_later
    word_arr[idx] = upcase_word_with_dashes(word)  if operand_arr[idx] == :upcase_dashed
    word_arr[idx] = upcase_word_with_slashes(word) if operand_arr[idx] == :upcase_slashed
    word_arr[idx] = word.capitalize                if operand_arr[idx] == :capitalize
  end

  word_arr.join(' ')
end

.upcase_first_real_letter(word) ⇒ Object

“__foo” => “__Foo”



10
11
12
# File 'lib/nicetitle/titlecase.rb', line 10

def self.upcase_first_real_letter(word)
  word.sub(/[a-zA-Z0-9]/, &:upcase)
end

.upcase_word_with_dashes(word) ⇒ Object

step-by-step => Step-by-Step



15
16
17
# File 'lib/nicetitle/titlecase.rb', line 15

def self.upcase_word_with_dashes(word)
  word.split('-').map { |part| is_small_word?(part) ? part : part.capitalize }.join("-")
end

.upcase_word_with_slashes(word) ⇒ Object

before/after => Before/After



20
21
22
# File 'lib/nicetitle/titlecase.rb', line 20

def self.upcase_word_with_slashes(word)
  word.split('/').map(&:capitalize).join('/')
end