Reputation: 557
I've been given a string. First, I transform it into a array and then I try to capitalize only words into the condition. One of the conditions is that the first string is capitalized. And it's just the one that is left
class Book
# write your code her
attr_reader :title
def title=(new_title)
words = new_title.split(" ")
if words.length > 1
final_title = ""
final_title = words.map! {|a| ((a != "and" && a != "the") && a.length > 2) ? a.capitalize : a}
@title = final_title.join(" ")
else
@title = new_title.capitalize
end
end
end
That's what I've done until now.
I tried to use each_with_index
but map!
doesn't work with it.
I expected:
"To Kill a Mockingbird"
but I got:
"to Kill a Mockingbird"
Upvotes: 2
Views: 825
Reputation: 54233
Here's a much shorter version, using gsub
with block :
new_title
: that way, the first word is capitalized and all the others are lowercase before the processing.Here's the method :
OMIT_CAPITALIZE = %w(the and)
new_title.capitalize.gsub(/\S{3,}/) do |word|
OMIT_CAPITALIZE.include?(word) ? word : word.capitalize
end
Here's a way to integrate it into your class. title
has been added as a parameter to initialize
for easier use of Book
:
class Book
OMIT_CAPITALIZE = %w(the and)
attr_reader :title
def initialize(title)
self.title = title
end
def title=(new_title)
@title = new_title.capitalize.gsub(/\S{3,}/) do |word|
OMIT_CAPITALIZE.include?(word) ? word : word.capitalize
end
end
end
puts Book.new('to kill a mockingbird').title
# To Kill a Mockingbird
puts Book.new('ThE beauty and THE beast').title
# The Beauty and the Beast
puts Book.new('TO BE OR NOT TO BE').title
# To be or Not to be
Upvotes: 2
Reputation: 5213
You can map over an array with an index, but you have to do it like this:
class Book
attr_reader :title
def title=(new_title)
words = new_title.split
final_title = words.map.with_index { |word, i| primary_word?(word) || i == 0 ? word.capitalize : word }
@title = final_title.join(' ')
end
def primary_word?(word)
((word != 'and' && word != 'the') && word.length > 2)
end
end
For clarity, I also extracted the logic for determining if a word should be capitalized into its own method.
Upvotes: 2
Reputation: 343
Since version 1.9.3, Ruby has had Enumerator#with_index. The method map
without a block returns an Enumerator
, so you can do the following:
final_title = words.map.with_index do |word, i|
if i != 0 && (word == "and" || word == "the" || word.length < 3)
word.downcase
else
word.capitalize
end
end
Clearly, you should make sure your title is lowercase to begin with, or the code checking for "and" and "the" won't work.
Upvotes: 3
Reputation: 114188
I'd start by separating the first word from the remaining words:
first, *rest = new_title.split(' ')
Then I would capitalize the first word:
first.capitalize!
Afterwards, I would capitalize each remaining word matching the conditions:
rest.select { |w| w != 'and' && w != 'the' && w.length > 2 }.each(&:capitalize!)
And finally put everything back together:
[first, *rest].join(' ')
Upvotes: 8