How A Ruby Case Statement Works And What You Can Do With It

CaseI found case statements in Ruby pretty interesting as they are capable of doing a little more than the equivalent constructs in other languages. We all know how a simple case statement works, we test on a condition that we give to a case statement, we then walk through a set of possible matches each of which is contained in a when statement e.g.:

ruby print "Enter your grade: " grade = gets.chomp case grade when "A" puts 'Well done!' when "B" puts 'Try harder!' when "C" puts 'You need help!!!' else puts "You just making it up!" end

So far nothing special, the above works just the way you would expect. But, you can do more with a case statement in Ruby.

Multi-Value When And No-Value Case

Ruby allows you to supply multiple values to a when statement rather than just one e.g.:

ruby print "Enter your grade: " grade = gets.chomp case grade when "A", "B" puts 'You pretty smart!' when "C", "D" puts 'You pretty dumb!!' else puts "You can't even use a computer!" end

Pretty cool, but nothing too revolutionary. It doesn’t end there though you can use a case statement without giving it a value to match against, which allows a case statement to mimic the behavior of an if statement, e.g.:

ruby print "Enter a string: " some_string = gets.chomp case when some_string.match(/\d/) puts 'String has numbers' when some_string.match(/[a-zA-Z]/) puts 'String has letters' else puts 'String has no numbers or letters' end

So, why would you use it instead of an if statement? Well, there is probably no reason, they are equivalent. But, it is good to be aware that you can do this, especially if you run into it in the wild, wouldn’t want to be caught unawares.

It All Evaluates To An Object

You probably keep hearing this over and over, but everything in Ruby works with objects. Things are no different when it comes to case statements. A case statement will always return a single object, just like a method call. So, you can safely wrap a case statement in a method call and Ruby will have no problems with it. For example, the above version of the case statement ca be re-written like this:

ruby print "Enter a string: " some_string = gets.chomp puts case when some_string.match(/\d/) 'String has numbers' when some_string.match(/[a-zA-Z]/) 'String has letters' else 'String has no numbers or letters' end

We are now wrapping the whole case statement in a puts method call, rather than doing it within each individual when statement. This works because no matter which when/else succeeds, the whole case statement returns the result of the last line that was executed (in our case it just always returns a string), and so the puts just writes out whatever string is returned.

How It All Works Under The Hood

You can almost consider case/when statements to be syntactic sugar for a method call. Every object in Ruby inherits a method called the case equality method, also known as the triple equals (===). You can think of it as an operator if it helps (the === operator), but we know that Ruby operators are just syntactic sugar for method calls. So whenever a when is trying to match a value (except when we are using a no-value case) there is a method call behind the scenes to the === method/operator. We can therefore take our very first example and re-write it using if statements to be completely equivalent to a case statement:

ruby print "Enter your grade: " grade = gets.chomp if "A" === grade puts 'Well done!' elsif "B" === grade puts 'Try harder!' elsif "C" === grade puts 'You need help!!!' else puts "You just making it up!" end

The implications of this are as follows. Any class you write can override the === method and therefore define it’s own behavior for usage in a case statement. For built-in objects such as strings, the === operator/method is simply equivalent to the == method/operator. But you don’t have to be restricted to this. If you want your class to have the ability to participate in a case statement in some specialized way all you need to do is something like this:

```ruby class Vehicle attr_accessor :number_of_wheels

def initialize(number_of_wheels) @number_of_wheels = number_of_wheels end

def ===(another_vehicle) self.number_of_wheels == another_vehicle.number_of_wheels end end

four_wheeler = Vehicle.new 4 two_wheeler = Vehicle.new 2

print “Enter number of wheel for vehicle: “ vehicle = Vehicle.new gets.chomp.to_i

puts case vehicle when two_wheeler ‘Vehicle has the same number of wheels as a two-wheeler!’ when four_wheeler ‘Vehicle has the same number of wheels as a four-wheeler!’ else “Don’t know of a vehicle with that wheel arrangement!” end```

In this case even though we are matching directly on the vehicle object in our case/when statement, behind the scenes a method call is made to the === operator and so the real match is made on the number of wheels attribute that the vehicle object has (as per what is defined in the === method).

This idea of hiding method calls behind syntax that doesn’t look like method calls, seems to be rather common in Ruby. Personally I like it, you can do some rather elegant things, but the building blocks are still just a bunch of method calls. When it comes to the case statement though, I hardly ever use it when I program in Java for example, but it looks to me like it can be somewhat more handy in Ruby especially with the ability to define custom case behavior for your own objects.

Image by dahliascakes

The Anatomy Of A Rhyme And What Really Rhymes With Orange

orangeLast year I wrote a humorous post, it was a list of words that rhyme with orange. All the words were completely made-up and I gave all of them funny meanings. To my continued surprise it has become the most consistently popular post on my blog (which is really funny for a software development blog, the internet works in mysterious ways :)). As you might know, orange is one of those words in the English language for which it is really difficult to find a rhyme (there are many others like silver, almond etc.). And yet, the majority of the comments on that blog posts are suggestions for some words that people believe rhyme with orange (all incorrect). Some of the other comments express disappointment that they couldn’t find any real words that rhyme with orange in my post. All this tells me 2 things:

  1. Most people don’t really know what a rhyme is
  2. Many people are really interested in words that rhyme with orange (I don’t know why, but I have learned to accept it :))

I don’t like it when people leave disappointed after reading my blog and this is why I decided to address both of the above points. For those people who believe that door hinge or syringe rhyme with orange, I will give a quick overview of the different types of rhyme. And for the curious few who want to find a real rhyme for orange I will attempt to satisfy your curiosity also.

Perfect Rhymes

When we try to find words that rhyme with each other, we are usually trying to find what’s known as a perfect rhyme (also called a true rhyme). Two words are a perfect rhyme of each other if their final stressed vowel and all sounds following it are identical e.g.:

  • sad, bad, mad
  • follow, swallow
  • ruling, fooling
  • etc.

There are 3 types of perfect rhymes:

  1. masculine – the stress is on the final syllable of the word (e.g. spent and went)
  2. feminine – the stress is on the second last syllable of the word (e.g. passion and fashion)
  3. dactylic – the stress is on the third last syllable (e.g. undemocratically and aristocratically)

That is all there is to it. If you want to find perfect rhymes for words, that’s all you need to know.

Imperfect Rhymes

When we use the word rhyme in a general sense (at least as far as words are concerned) we are usually talking about words that sound phonetically similar in some way, but which are not true rhymes. Phonetically similar words can be classified in a number of ways:

  • half rhyme – two words have a matching final consonant
  • imperfect rhyme – a rhyme between a stressed syllable and an unstressed one
  • oblique rhyme – a rhyme where the match in sound is imperfect
  • consonance – words have matching consonants
  • assonance – words have some matching vowels
  • alliteration – words have a matching initial consonant
  • etc.

The point is there are many different types of imperfect rhyme, and because of this with some types of imperfect rhyme (such as oblique rhymes) almost any word can be considered an imperfect rhyme of almost any other. In short, it becomes extremely subjective.

Imperfect rhymes can be used in verse (and have been since ancient times), but that does not make them true rhymes, which is what most people would refer to when they talk about rhyme (i.e. in general conversation we tend to use the word rhyme in a strict sense – a perfect rhyme). This is why we can’t really say that door hinge or syringe rhyme with orange. They are certainly imperfect rhymes (since pretty much anything can be), but they are not true rhymes unless we decide to use the word rhyme in it’s general sense (which noone does in day-to-day conversation).

I’ve given only a very basic explanation about rhymes and rhyming and only as far as specific words are concerned. If you want to dig deeper into the ‘science’ of poetry, there is a lot more to know about rhyme. How to organize verse, tetrameters, hexameters etc. Feel free to explore if you’re interested (Google is your friend).

What Really Rhymes With Orange

And so we’re back to oranges :). So, are there any real words that perfectly rhyme with orange? Well, it is a little complicated. Technically speaking orange is considered to be a word that doesn’t have any perfect rhymes, however we can always resort to a trick. We can always make up words as long as we make them proper names. You could therefore make up a name that would be a perfect rhyme for orange. Infact such names already exist:

Gorringe – is a family name and if you choose to pronounce it in a particular way it can rhyme with orange.

Blorange – is a mountain in south east Wales. Once again, if you choose to pronounce it in a particular way it will also rhyme with orange. It is however not strictly correct as despite the way it’s spelt, it is not pronounced the same (the correct pronunciation is – Blorins).

The only non-proper-name word that can rhyme with orange is:

Sporange – a plant that produces spores. This one is also arguable since, technically speaking, it should be sporangium rather than sporange since sporangia is the plural form of the word.

That’s it. There are no other words in the English language that can be considered a perfect rhyme of orange, so if you don’t like the above three and don’t want to make up a proper name of your own, you’re out of luck. Personally I don’t like any of the above three words and while I normally have no problems making up words/names when I need to, anything you’re likely to come up with to rhyme with orange will undoubtedly just sounds stupid (try it if you don’t believe me :)).

Image by mattieb

What Everybody Should Know About Installing And Using Java On Ubuntu

JavaInstalling and switching between versions of Java on Ubuntu is a relatively simple process (with a couple of caveats), you just need to know the right commands. Considering that there was a time when I didn’t know this either I thought I’d share what I know (shouldn’t take long :)).

Anyways, first thing first. When we talk about installing Java on Ubuntu we are of course talking about Sun Java. You can also install Open JDK if you want, but most people will use the Sun version for their Java development. Of course these days there are several versions of Sun Java that are in mainstream use; well basically 2, Java1.5 and Java6 (I am sure things will be even more interesting when Java 7 comes out). Regardless of which version of the JDK you want to install the process to do this on Ubuntu is the same. You need to know what package you want to install and then you need to use our old friend apt-get.

Installing Java

In the case of the Sun JDK you will want to install either (or both) of:

sun-java5-jdk<br /> sun-java6-jdk

The commands for this will be:

sudo apt-get install sun-java5-jdk

or

sudo apt-get install sun-java6-jdk

Once you put in your password apt-get will go ahead and do it’s thing. The only thing to watch out for is that with Java you might get a license screen popping up during the installation (i.e. it won’t just finish by itself, so don’t go away), you will need to accept. That’s it, you now have one or several version of Java installed.

Switching Between Versions

Of course, if you have more than one version installed it is probably for a reason and you will need to switch between them at some point. Ubuntu has a very handy command just for this, update-java-alternatives. Using this command is simple:

update-java-alternatives -l

Which will produce output similar to the following:

java-1.5.0-sun 53 /usr/lib/jvm/java-1.5.0-sun<br /> java-6-sun 63 /usr/lib/jvm/java-6-sun

You can now pick one of the alternatives that were printed out and use the same command, with a different switch, to make Ubuntu use it as it’s default Java installation:

sudo update-java-alternatives -s java-6-sun

This will output a bunch of stuff:

Using '/usr/lib/jvm/java-6-sun/bin/appletviewer' to provide 'appletviewer'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/apt' to provide 'apt'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/extcheck' to provide 'extcheck'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/HtmlConverter' to provide 'HtmlConverter'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/idlj' to provide 'idlj'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jarsigner' to provide 'jarsigner'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jar' to provide 'jar'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/javac' to provide 'javac'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/javadoc' to provide 'javadoc'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/javah' to provide 'javah'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/javap' to provide 'javap'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/java-rmi.cgi' to provide 'java-rmi.cgi'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jconsole' to provide 'jconsole'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jdb' to provide 'jdb'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jhat' to provide 'jhat'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jinfo' to provide 'jinfo'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jmap' to provide 'jmap'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jps' to provide 'jps'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jrunscript' to provide 'jrunscript'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jsadebugd' to provide 'jsadebugd'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jstack' to provide 'jstack'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jstatd' to provide 'jstatd'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/jstat' to provide 'jstat'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/native2ascii' to provide 'native2ascii'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/rmic' to provide 'rmic'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/schemagen' to provide 'schemagen'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/serialver' to provide 'serialver'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/wsgen' to provide 'wsgen'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/wsimport' to provide 'wsimport'.<br /> Using '/usr/lib/jvm/java-6-sun/bin/xjc' to provide 'xjc'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/ControlPanel' to provide 'ControlPanel'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/java' to provide 'java'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/java_vm' to provide 'java_vm'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/javaws' to provide 'javaws'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/jcontrol' to provide 'jcontrol'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/jexec' to provide 'jexec'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/keytool' to provide 'keytool'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/orbd' to provide 'orbd'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/pack200' to provide 'pack200'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/policytool' to provide 'policytool'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/rmid' to provide 'rmid'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/rmiregistry' to provide 'rmiregistry'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/servertool' to provide 'servertool'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/tnameserv' to provide 'tnameserv'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/bin/unpack200' to provide 'unpack200'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so' to provide<br /> 'firefox-javaplugin.so'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so' to provide<br /> 'iceape-javaplugin.so'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so' to provide<br /> 'iceweasel-javaplugin.so'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so' to provide<br /> 'midbrowser-javaplugin.so'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so' to provide<br /> 'mozilla-javaplugin.so'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so' to provide<br /> '<a href="http://xulrunner-1.9-javaplugin.so">xulrunner-1.9-javaplugin.so</a>'.<br /> Using '/usr/lib/jvm/java-6-sun/jre/lib/i386/libnpjp2.so' to provide<br /> 'xulrunner-javaplugin.so'.

There are two things to note about the command.

  1. It needs root privileges, so you will need to execute it with sudo
  2. The name of the java version you pass to the command is one of the things that was printed out when you ran update-java-alternatives –l (i.e. java-6-sun or java-1.5.0-sun)

This is all you need to do to have your whole Ubuntu installation use a different version of Java. That’s all great, but there is one big problem.

The Built-In FAIL And How To Fix It

Many Java applications written these days rely on the existence of the JAVA_HOME environment variable (they use this variable to know which Java they should execute with). Unfortunately none of the commands we ran above set the JAVA_HOME environment variable. Instead you will normally have to wait until the first time you execute a Java application which fails when it tries to find JAVA_HOME before you realize that you will need to set this yourself.

Even then things are not quite that simple. The update-java-alternatives command relies quite heavily on symlinks so it may take a while to even figure out where your current Java is installed. Once you do figure it out and set your JAVA_HOME environment variable, you have to remember to update it if you decide to switch java versions later (by using the update-java-alternatives command).

I will try to save you some pain and tell you where things live and then show you how I set my JAVA_HOME so that it is automatically (almost) updated when you switch Java versions. So, the first thing you would need to do to figure out where things live is to run the following command:

which java

Which tells you that your java executable lives in:

/usr/bin/java

Of course if you go and have a look you will see that it is actually a symlink to:

/etc/alternatives/java

That in turn is also a symlink to something like (depending on your java version):

/usr/lib/jvm/java-6-sun/jre/bin/java

We’re almost there but not quite. You need to go back a few directories from the path above, more specifically you need to go to:

/usr/lib/jvm

This is where all the JVMs that are on your system will be found, you will also notice that java-6-sun in this directory is actually a symlink to the java-6-sun-1.6.0.14 (your actual version may differ) directory. The story for java-1.5.0-sun is similar. So, now you know that if you’re currently using Java 6 then your JAVA_HOME path should be:

/usr/lib/jvm/java-6-sun-1.6.0.14

To make sure this path persists between shutdowns, you will need to put it in your .bashrc file. But, as I mentioned you don’t want to just hard-code it as you would need to come and change it when you switch versions. So instead you can add the following line to the end of your .bashrc file:

export JAVA_HOME=`readlink -f \`which javac\` | awk -Fbin '{print $1}'`

What this does is automatically work out what your JAVA_HOME path should be (and sets it)  depending on what version of Java you’re currently using. It finds where your java interpreter lives and follows all the symlinks if there are any (and we know there are several). It then uses awk to extract the path before any bin folders which will be the path to your JAVA_HOME. The reason all of this works is because:

  • the java compiler javac will always be in the bin folder of your JDK as opposed to the bin folder of your JRE (like the java executable itself could be), so extracting the path before the bin folder using awk, gives is the path to what JAVA_HOME should be
  • using readlink –f, allows us to follow multiple levels of symlinks, which is handy in this case since that’s what we need to do to actually get the real path of where the javac compiler lives

The only thing to remember with this is that once it is in your .bashrc, every time you switch Java versions you will need to close the terminal and open a new one, or source your .bashrc again to make sure the JAVA_HOME path is updated. It is not a perfect solution but it is a decent one and it does the job. However if someone knows of a way to do this without having to start a new terminal or source your profile, do leave a comment and share your knowledge with everyone.

That’s all you need to know to install and work with Java on Ubuntu like a pro :).

Image by Refracted Moments