Trying to create a titleize method manually

I have been trying to create a titleize method that takes a variable
string and puts that string in titlecase, not capitalizing all the
little words.

This is what I have so far:

def titleize(x)

"#{x.split.each{|x| x.capitalize!}.join(' ')}"

end

Example of desired outcome: “On the Road”
Example of current outcome: “On The Road”

I am well aware that this method only capitalizes every word and does
not put little words in lower case.

(Also don’t want to use titleize gem)

My question is what code do I have to add in order to get Ruby to
recognize which words are little words and which words aren’t?

On Tue, Aug 27, 2013 at 10:49 AM, trying 2 learn [email protected]
wrote:

My question is what code do I have to add in order to get Ruby to
recognize which words are little words and which words aren’t?

I suppose that depends on how you’re defining “little words” :slight_smile:

Hassan S. wrote in post #1119754:

On Tue, Aug 27, 2013 at 10:49 AM, trying 2 learn [email protected]
wrote:

My question is what code do I have to add in order to get Ruby to
recognize which words are little words and which words aren’t?

I suppose that depends on how you’re defining “little words” :slight_smile:

Yes that is true. My goal is titlecase. I just don’t really understand
how to do that when the string is a variable.

I mean if it wasn’t could use .gsub or something like that.

Any ideas?

On Tue, Aug 27, 2013 at 11:31 AM, trying 2 learn [email protected]
wrote:

Yes that is true. My goal is titlecase. I just don’t really understand
how to do that when the string is a variable.

I mean if it wasn’t could use .gsub or something like that.

Your reply makes no sense. The point is that in order to capitalize
some words and not others, you have to be able to define which
are which.

Again, how are you defining “little words”?

What differentiates a “little word” from a “big word”? How do you, or
rather how does your program, recognize one?

Ok I tinkered around with it a little bit and came up with this

def titleize(x)
words = x.split
words.each do |word|
if word.length <3
word.downcase
elsif word.length >3
word.capitalize!
end
words.join ’ ’
end
end

My next question is the outcome is desirable, but it comes out like this

[Title]

Is there anyway to eliminate those brackets?

On Tue, Aug 27, 2013 at 1:49 PM, trying 2 learn [email protected]
wrote:

I have been trying to create a titleize method that takes a variable
string and puts that string in titlecase, not capitalizing all the
little words.

“#{x.split.each{|x| x.capitalize!}.join(’ ')}”

My question is what code do I have to add in order to get Ruby to
recognize which words are little words and which words aren’t?

First, as others have pointed out, you need to define what you mean by
“little word”. This is completely separate from any code! Is it
those of three letters or fewer? Or a specific list? (Hint: Google
“noise words” or “stop words”.) Or will you be looking at some
context?

THEN comes the question of how you would detect, in code, that you
have a little word. Of course this will depend on what’s your answer
to the previous question. If it’s just length, the answer is obvious,
but if it’s a list, then are many choices. List out a few, and pick
the one that seems to fit your needs best. That may be the one that’s
the most readable, flexible, reliable, etc.

Lastly comes the question of what to do when you have one. Again
there are many possibilities; again, list out a few and pick the one
that best fits your needs. Don’t forget to account for the case that
a little word may be the very first word, and thus still capitalized!

Work on these pieces one at a time. Ask questions if you get stuck on
them. Just as you’ve done above, show us what you’ve tried and why it
doesn’t meet your needs.

In general, this thought process of breaking a problem down into
subproblems will help you greatly, and not just in programming.
Remember, all programs break down eventually into a very small set of
instructions to the CPU! :slight_smile: You don’t have to break it down THAT
far, just far enough that you can think up a reasonable idea how to do
it.

-Dave

I think you should write the code as below:

def titleize(x)
words = x.split
words.each do |word|
if word.length <3
word.downcase!
elsif word.length >3
word.capitalize!
end
end
words.join ’ ’
end

titleize(“title”)

=> “Title”

Oh thank you for that. I didn’t realize I forgot the exclamation point
on downcase. Also I should not have had the words.join in the if
statement.

I also realize that this program is not particularly flexible.

Thank you all so much for your help so far.

I am also trying to get the program to capitalize the 1st word if it is
3 letters, but only if its the 1st word.

I created a method for the 1st word below :

def first_word(x)
x.split[0…1].join(",")
end

def titleize(x)
words = x.split
words.each do |word|
if word.length <3
word.downcase!
end
elsif word.length >3
word.capitalize!
end
end
words.join ’ ’
end

I tried:

adding an and argument

def titleize(x)
words = x.split
words.each do |word|
if word.length <3
word.downcase!
end
elsif word.length >3 && word == first_word
word.capitalize!
end
end
words.join ’ ’
end

And didn’t get anywhere. I am wondering can you set a variable equal to
the output of a method?

On Tue, Aug 27, 2013 at 5:37 PM, trying 2 learn [email protected]
wrote:

words.each do |word|
    if word.length <3
        word.downcase
    elsif word.length >3
        word.capitalize!
    end

What if it’s exactly 3? Then this does nothing.

Also, you don’t store the results of “word.downcase” anywhere. If you
want it to affect it, you have to put a ! on the end.

    words.join ' '

This is inside the loop, so you’re doing it every time. Also, it has
no effect, even the last time, since you’re not storing the results
anywhere, and it won’t be the return value of .each either, since that
returns the array passed in.

Try this approach: take baby steps, either from the outside in, or
vice-versa. First write a function that will split up a string, do
SOMETHING to each word (upcase it or whatever), and put it back
together. (You might also want to take baby steps WHILE writing that
one.) Write another function that will do SOMETHING to a word (eg
downcase it) if it is “little”, else something ELSE (eg upcase it).
Hook the two together by making the second one what the first one does
to each word. You’re done!

If you REALLY want to learn how to Do It Right, you can write some
unit tests for each of those functions… BEFORE you write them… to
verify that they return the right thing in various cases, including
boundaries.

-Dave

If your desired outcome is “On the Road”, then you’re disobeying your
own rules. “On” is a small word, but is capitalised.

Also, your current code ignores words 3 letters long.

Here’s a simple rule enforcer which only runs on length and doesn’t mess
with punctuation:

def titleize( x )
x.gsub( /\w+/ ) { |w| w.length > 3 ? w.capitalize : w.downcase
}.capitalize
end

If you want to do this with a word list of “small” words, you’ll
probably want Array#include?

trying 2 learn wrote in post #1119779:

I am wondering can you set a variable equal to
the output of a method?

Of course you can, every Ruby method returns something.

def my_method
‘Hi!’
end

a = my_method

puts a

You’re overthinking the first word thing… just capitalize the entire
String after dealing with the individual words, and it’ll uppercase the
first letter for you.

Dave,

Baby steps it is.

Step 1

def titleize(x)
x.capitalize.split

end

Questions

  1. This splits and capitalizes the word right?
  2. Word encased in [], how do we get rid of that?
  3. What do you mean when you say but it back together?

On Tue, Aug 27, 2013 at 7:27 PM, trying 2 learn [email protected]
wrote:

Baby steps it is.

Step 1

def titleize(x)
x.capitalize.split
end

You’re not taking baby steps here. A baby step would be something like:

def do_something_to_word(word)
word.upcase!
end

and then:

def do_something_to_each_word_in_phrase(phrase)
words = phrase.split
words.each { |word| do_something_to_word(word) }
words
end

(there are shorter and more Ruby-idiomatic ways to do that sort of
construct, which make it more of a baby-step, but we’ll save those for
later), and then:

def do_something_to_phrase(phrase)
do_something_to_each_word_in_phrase(phrase).join(“-”)
end

and finally you can put it all together if you like, as:

def do_something_to_phrase(phrase)
words = []
phrase.split.each { |word| words << word.upcase }
words.join(“-”)
end

Idiomatic Ruby would reduce this to one line (inside the method), BTW;
look up “map” (also called “collect”) if interested.

Also, you need to understand the difference between the methods that
end in a bang (!), versus those with the exact same name without the
bang. As luck would have it, I just wrote a blog post on that a few
days ago, including about another big bad gotcha lurking in them to
getcha:

Attack of the Codosaurus!: The Big Bad Bang, or, The OTHER Gotcha with Ruby's Bang Methods

You could use either bunch in this problem, but you have to know how
to handle them either way.

Questions

  1. This splits and capitalizes the word right?

It capitalizes the string you pass in, and then splits it. The
order of typing is, in this case, also the order of execution. You
want the other way around.

  1. Word encased in [], how do we get rid of that?

Think a second about what the square brackets signify. Then think why
that would happen. (It’s much more obvious if you pass it multiple
words.) If you’re intending this to only act on single words at a
time, yes, that would be more of a baby step – but then there’s no
need for split.

  1. What do you mean when you say but it back together?

Make the square brackets go away… even with multiple words.

Don’t be ashamed to take baby steps, like it’s not grown-up or
something. We do it all the time. It’s the best way to keep clear in
your head what you’re trying to do right now, and make sure you’re
doing (or, when finished, have done) it right.

Also, don’t think small steps mean slow progress; I can’t think of a
good analogy, but think of it like the further you’re going at one
shot, the more of a (mental) burden you have to bear. Like a rocket,
which needs to haul more fuel the further it’s going, and more fuel to
haul that fuel, and so on, to the point where on trips far into space,
the fuel winds up being most of the total mass… while the proportion
of fuel in a little toy rocket is very small.

-Dave

Dave,

I have a couple of questions:

  1. You used .upcase!, and maybe you were just providing an example, but
    doesn’t that make every letter capital, not just the 1st one? Wouldn’t
    .capitalize! be more appropriate?

  2. If I am not mistaken, I believe the square brackets refer to an
    array. My intention for the program to react with a varying amount of
    words at a time.

  3. I read your blog post, and if I understand the bang(!) correctly it
    actually modifies the string of text for the entire method. In this
    context, using the ! for capitalize would modify the array so that every
    value passed through would be capitalized. This is why you said the
    .capitalize comes before the .split, because if it were the other way
    around you would only capitalize the 1st word. Correct?

I also understood your metaphor and understand what you are saying, in
terms of attacking each obstacle one at a time in order to create
something. I am fairly new to this, and really appreciate your
responses, your time and your patience.

if it was me, I think this is how I’d go about it, not saying its the
greatest, or the best way to do it, just what came to mind…

module Grammer
def titleize(string)
words_not_to_capitalize = [“the”,“and”,“if”,“or”,“of”]
s = string.split.each{|str| str.capitalize! unless
words_not_to_capitalize.include?(str.downcase) }
s[0].capitalize + " " + s[1…-1].join(" ")
end
end

include Grammer
s = “the lord of the rings”
puts titleize(s)

You should probably make “words_not_to_capitalize” a constant because of
the way it’s declared. Or for flexibility, you could make it an optional
argument:

module Grammar
DefaultWordsNotToCapitalize = [“the”,“and”,“if”,“or”,“of”]

def titleize( string, small_words=nil )
small_words ||= DefaultWordsNotToCapitalize

...

end
end

I’d try to avoid using split, since you’ll end up with punctuation
counted in words, which alters their length:

“of off of. off.”.split
=> [“of”, “off”, “of.”, “off.”]

ok, had to revise that a bit…

module Grammer
def titleize(string)
words_not_to_capitalize = [“the”,“and”,“if”,“or”,“of”]
s = string.split.each do |str|
str.downcase!
str.capitalize! unless
words_not_to_capitalize.include?(str.downcase)
end
s[0].capitalize + " " + s[1…-1].join(" ")
end
end

include Grammer
s = “THE LORD OF THE RINGS”
puts titleize(s)

should now take into account strings in all caps

I’d still go with the block form of String#gsub. It has all the elements
to make this work, Regexp for detailed scanning and a block to test
things like String#length or Array#include?.

excellent points, was not thinking of punctuation when I wrote that, it
could definitly use some tweaking, buts its a general idea of how I
would
do it.

trying 2 learn [email protected] wrote:

  1. You used .upcase!, and maybe you were just providing an example, but
    doesn’t that make every letter capital, not just the 1st one? Wouldn’t
    .capitalize! be more appropriate?

Quite so. I’m trying to teach you the concepts involved, without
handing you too much of a ready-made solution.

  1. If I am not mistaken, I believe the square brackets refer to an
    array. My intention for the program to react with a varying amount of
    words at a time.

Right… but you want the response to be a string. So, you have turn
it back into a string before you’re done. I think you’ve already used
the method you need, in a previous try; now you just need to bring it
back in. It’s much more obvious when you use multiple words.

  1. I read your blog post, and if I understand the bang(!) correctly it
    actually modifies the string of text for the entire method.

Right. It modifies the string of text, whereas “upcase” (with no
bang) returns a modified copy of it. In real life analogy, “upcase”
would a person that you show a slip of paper, and he copies down the
contents in uppercase on a new slip and gives that to you. It’s up to
you to put that with the rest of your slips (i.e., record it in a
variable), versus just letting it drop to the floor. By contrast,
“upcase!” takes your slip of paper, erases each lowercase letter and
replaces it with its uppercase version, and puts the slip back on the
table with the rest of your slips.

(I would have said that upcase! “hands you back your original slip”,
but that’s exactly the oversimplification that my blog post was
warning about. It’s more like he reads it to you if there were any
changes, else he says nothing, and it’s up to you to record the
response (or lack thereof) or ignore it (the usual course of action).)

In this
context, using the ! for capitalize would modify the array

Technically, modify each element (at least, those needing mods), but
yes, I think you’ve got the basic idea.

so that every
value passed through would be capitalized. This is why you said the
.capitalize comes before the .split, because if it were the other way
around you would only capitalize the 1st word. Correct?

“before” is how you already had it, as x.capitalize.split. You want
to split it first, then capitalize each word (except “little words”,
which get different treatment, and even then, capitalize it if it’s
the first, but I think we can leave that for later), then put it all
back together.

-Dave