1

This is almost certainly a duplicate, but I can't find the original - I don't know the search terms to use. Which is why I'm on Stackoverflow instead of Google :)

Anyhow, here's my code:

def titleize(say)
  index = 0
  words = say.split
  words.each do |word|
    unless word == "and" || "or" || "over" || "the" || "for"
        word.capitalize!
    end
    if index == 0
        word.capitalize!
    end
    index += 1
  end
  say = words.join(" ")
end

Because index is declared before the loop, my if index == 0 is not working. How do I let Ruby know about and use my object index? Also: what is this called?

5
  • 1
    Are you sure you don't just want to use titleize? It would capitalize some of your conjunctions, though Commented Jul 31, 2014 at 20:22
  • It's a learning exercise where we basically recreate the titleize method, but yes, that would be much easier! Commented Jul 31, 2014 at 20:34
  • Note that word == "and" || "or" || "over" || "the" || "for" parses as (word == "and") || ("or") || ("over") || ("the") || ("for"), which will always return a truthy value. Commented Jul 31, 2014 at 20:48
  • 1
    Best not to have unnecessary tags (here "ruby-on-rails") as some readers may filter out questions with that tag. Commented Jul 31, 2014 at 22:32
  • If you found any the answers helpful, you should select one. Commented Aug 4, 2014 at 21:30

6 Answers 6

8

Using index == 0 is perfectly fine as index is accessible within your loop. Your real problem is probably in this line:

word == "and" || "or" || "over" || "the" || "for"

This is always true-like! What you mean is:

["and", "or", "over", "the", "for"].include? word

Apart form that there is a method called each_with_index, which you can use like this:

words.each_with_index do |word, index|
Sign up to request clarification or add additional context in comments.

Comments

2

I think you want to use with_index. Your word comparison was busted too.

def titleize(say)
  words = say.split
  l = ["and", "or", "over", "the", "for"]

  words.each.with_index do |word, index|
    word.capitalize! if index == 0 || !(l.include? word)
  end

  say = words.join(" ")
end

puts(titleize("hello there for you"))
puts(titleize("hi"))
puts(titleize("for"))

3 Comments

You could also use a unique condition in the loop to avoid code duplication. word.capitalize! if index == 0 || !l.include?(word)
@Yanis You are correct. I tried to keep it in style with the asker.
Technically works, but declaring l inside of each call of this method creates a lot of garbage. That array would be better as a constant that can be recycled.
1

That's not how booleans work. The way this is evaluated is:

x == 'a' || 'b'

Becomes:

(x == 'a') || 'b'

Which is equivalent to:

'b'

What you're intending, translated to more idiomatic Ruby, is:

def titleize(say)
  say.split.each_with_index do |word, index|
    if (index == 0)
      word.capitalize!
    else
      case (word)
      when "a", "and", "or", "over", "the", "for"
        # Leave lower-case
      else
        word.capitalize!
      end
    end
  end.join(' ')
end

titleize('the time this is a test for the things!')
# => "The Time This Is a Test for the Things!"

1 Comment

One more thing to clarify, (x == 'a') || 'b' is not equivalent to 'b', it might return true as well.
0

I would do this it is more flexible and more ruby-esque

def titleize(sentence,exclusions=[])
  sentence.split.map.with_index do |word,index|
    (index == 0 || !exclusions.include?(word)) ? word.capitalize : word
  end.join(' ')
end

For this case i used 'capitalize' without the bang in case any of the words are already capitalized.

"Hello".capitalize! #=> nil
"Hello".capitalize #=> "Hello"

It will also let you re-use the same list of exclusion or change them as you see fit

Call as

exclude = ["and", "or", "over", "the", "for"]
titleize("hello there you are over there", exclude)
#=> "Hello There You Are over There"

Comments

0

Your code returns the modification of say, but does change the contents of the variable. It appears that you want to modify the argument, but I'm not sure about that. I will first suggest a way to return the modified value of say (but not alter the value of say, and then will show how you could change the code to modify the argument.

Notice that I do not employ an index, and use a case statement to determine whether words after the first should be capitalized.

Code

def titleize(say)
  words = say.split
  return "" if words.empty?
  words.first.capitalize!
  return words.first if words.size == 1
  words[1..-1].each do |word|
    case word
    when "and", "or", "over", "the", "for"
    else
      word.capitalize!
    end
  end
  words.join(' ')
end

Examples

say = "and now is the time for all Rubyists to hunker down and code"
titleize(say)
  #=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say
  #=> "and now is the time for all Rubyists to hunker down and code"    

say = "  "
titleize(say)
  #=> ""

say = " and "
titleize(say)
  #=> "And"

Modifying the Argument

If you wish to modify the argument say, use String#replace:

def titleize_and_modify_arg(say)
  words = say.split
  str =
  case words.size
  when 0
    ""
  when 1
    words.first.capitalize
  else
    words.first.capitalize!
    words[1..-1].each do |word|
      case word
      when "and", "or", "over", "the", "for"
      else
        word.capitalize!
      end
    end
    words.join(' ')
  end  
  say.replace(str)
end

say = "and now is the time for all Rubyists to hunker down and code"
titleize_and_modify_arg(say)
  #=> "And Now Is the Time for All Rubyists To Hunker Down and Code"
say
  #=> "And Now Is the Time for All Rubyists To Hunker Down and Code"

say = " and "
titleize_and_modify_arg(say)
  #=> nil
say
  #=> " and "

Notice that in the second example, titleize_and_modify_arg modifies say correctly, but returns nil. Of course, the method could be easily changed to return the value of say, as well as changing it, if that were desired.

Note also that, in the case statement, when words.siz => 1, it's capitalize, not capitalize!, as the latter would return nil if the word is already capitalized. capitalize! is need for the else case, however.

Comments

-3

I recommend using each_index instead of each. See here.

Try this:

def titleize (say)
  words = say.split
  words.each_index do |index|
    word = words[i]
    unless word == "and" || "or" || "over" || "the" || "for"
        word.capitalize!
    end
    if index == 0
        word.capitalize!
    end
  end
  say = words.join(" ")
end

1 Comment

each_index isn't what you want here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.