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?

···

--
Posted via http://www.ruby-forum.com/.

I suppose that depends on how you're defining "little words" :slight_smile:

···

On Tue, Aug 27, 2013 at 10:49 AM, trying 2 learn <lists@ruby-forum.com> 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?

--
Hassan Schroeder ------------------------ hassan.schroeder@gmail.com

twitter: @hassan

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

···

On Tue, Aug 27, 2013 at 1:49 PM, trying 2 learn <lists@ruby-forum.com> wrote:

--
Dave Aronson, the T. Rex of Codosaurus LLC,
secret-cleared freelance software developer
taking contracts in or near NoVa or remote.
See information at http://www.Codosaur.us/\.

Hassan Schroeder wrote in post #1119754:

···

On Tue, Aug 27, 2013 at 10:49 AM, trying 2 learn <lists@ruby-forum.com> > 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?

--
Posted via http://www.ruby-forum.com/\.

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?

···

--
Posted via http://www.ruby-forum.com/.

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"

···

--
Posted via http://www.ruby-forum.com/.

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?

···

--
Posted via http://www.ruby-forum.com/.

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?

···

--
Posted via http://www.ruby-forum.com/.

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?

···

--
Posted via http://www.ruby-forum.com/.

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.

···

--
Posted via http://www.ruby-forum.com/.

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."]

···

--
Posted via http://www.ruby-forum.com/.

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?.

···

--
Posted via http://www.ruby-forum.com/.

Technically an explicit newline should be followed by a capital letter,
regardless of the preceding punctuation. This is true in poetry, and as
far as I know, everywhere else. "Word wrap" doesn't count as that's down
to the editor.

···

--
Posted via http://www.ruby-forum.com/.

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?

···

On Tue, Aug 27, 2013 at 11:31 AM, trying 2 learn <lists@ruby-forum.com> 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.

--
Hassan Schroeder ------------------------ hassan.schroeder@gmail.com

twitter: @hassan

    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

···

On Tue, Aug 27, 2013 at 5:37 PM, trying 2 learn <lists@ruby-forum.com> wrote:

--
Dave Aronson, the T. Rex of Codosaurus LLC,
secret-cleared freelance software developer
taking contracts in or near NoVa or remote.
See information at http://www.Codosaur.us/\.

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:

  blog.codosaur.us/2013/08/the-big-bad-bang-or-other-gotcha-with.html

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.

2. 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.

3. 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

···

On Tue, Aug 27, 2013 at 7:27 PM, trying 2 learn <lists@ruby-forum.com> wrote:

--
Dave Aronson, the T. Rex of Codosaurus LLC,
secret-cleared freelance software developer
taking contracts in or near NoVa or remote.
See information at http://www.Codosaur.us/\.

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)

···

On Tue, Aug 27, 2013 at 10:06 PM, trying 2 learn <lists@ruby-forum.com>wrote:

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.

--
Posted via http://www.ruby-forum.com/\.

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

···

On Wed, Aug 28, 2013 at 12:09 AM, adam hegge <rahegge@gmail.com> wrote:

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)

On Tue, Aug 27, 2013 at 10:06 PM, trying 2 learn <lists@ruby-forum.com>wrote:

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.

--
Posted via http://www.ruby-forum.com/\.

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.

···

--
Posted via http://www.ruby-forum.com/\.

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.

···

On Wed, Aug 28, 2013 at 3:52 AM, Joel Pearson <lists@ruby-forum.com> wrote:

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."]

--
Posted via http://www.ruby-forum.com/\.