Friday, March 30, 2007

Gotcha with Ruby "upcase!" and "downcase!"

Ruby String class provides a method called upcase that converts all characters of a string to upper case. Ruby also provides an equivalent (downcase) to convert all the characters of the string to lower case. The return value of upcase or downcase is a copy of the string with all the characters converted to upper or lower case. To convert the string in place, there are upcase! and downcase!. The gotcha comes from these two methods. If a string (say, "HELLO WORLD") is all upper case, then invoking upcase! on that string returns nil. This is different from how upcase and downcase function - they return a copy of the string even if all the characters are upper case. This could be a big gotcha!

Examples -

my_string = "Hello World"
my_string1 = "HELLO WORLD"

ret_val = my_string.upcase
ret_val1 = my_string1.upcase

Both ret_val and ret_val1 are "HELLO WORLD".

Now, consider the following -

gotcha_string = "Hello World"
gotcha_string1 = "HELLO WORLD"

ret_val = gotcha_string.upcase!
ret_val1 = gotcha_string1.upcase!

Here, ret_val is "HELLO WORLD" whereas ret_val1 is "nil".

We would expect ret_val1 to also be "HELLO WORLD". So, if we used the bang versions of upcase and downcase like we would use the non-bang versions, we would be in for a rude surprise.

In my opinion, this violates the Principle of Least Surprise that Ruby supposedly adheres to.

Update
I just want to clarify that the value of gotcha_string1 itself doesn't become nil, just the return value of calling that variable is nil. gotcha_string1 will still be "HELLO WORLD". Its return value which is assigned to ret_val1 will be nil. As the commenter below suggests, do not use the "!" version of upcase or downcase in an assignment or do not depend on their return value.





Monday, March 26, 2007

Capitalizing The First Letter Of Each Word In A String

Say we have a string "This is my String" - we want to capitalize the first letter of each word so that my string becomes "This Is My String". My first attempt was to use the capitalize method -

my_string = "This is a String"
my_string.capitalize --> "This is a string"

Not exactly what we want. Turns out that capitalize converts the *first character* of the string (letter "T" in this case) to upper case and the rest of the letter to lower case. In other words, if

my_string1 = "this is a String",
my_string1.capitalize --> "This is a string"

Notice that "t" in "this" became "T" and "S" in "string" became "s".

In order to capitalize the first letter of each word, we have to split the string into words and then apply capitalize on each word.

my_string.split(” “).each{|word| word.capitalize!}.join(” “) --> "This Is A String"

We used "capitalize!" instead of "capitalize" . The difference is that "capitalize!" capitalizes the word in place whereas "capitalize" returns a copy of the word capitalized.

What if we wanted to capitalize all the letters in the string? Turns out, this is straight-forward:

my_string.upcase! --> "THIS IS A STRING"

First Post

First post...getting started. I will try to post about Ruby, Rails and JRuby as and when I find the time.