Tuesday, 18 September 2007

Boy do I Love Ruby...

This fact about Ruby isn't a surprise, I just needed to express how much I love that fact that all numbers are objects:

Come to me sweet DSL's! Massage me expressive and terse code constructs! Relieve my angst and pain and potential RSI!

(Sorry. To much Russell Brand on the plane this morning...)

Even More Ruby Surprises - Blocks and Closures 101

For me, the Ruby learning continues apace. This weekend it was the turn of blocks and closures, however first I'd like to mention a little pecadillo which made me smile.

Surprise C1 - Parallel Assignment

Now those Ruby folks constantly bang on about how expressive Ruby is and generally then go off into very complicated and convoluted discussions as to why, but this, to me is a perfect illustration:

What this says to me is "I have some variables. I want to call them this and this, and I want them to equal this and this." Simple and legible. Nice

Surprise C2 - Blocks Can Have (Multiple) Parameters Passed to Them and Can Return Values Too

Now coming from a Java background, the whole concept of blocks and closures was a bit of a mystery to me. (Now I do get anonymous inner classes, but frankly the whole Closures debate had me a little confused.) No longer. After a single paragraph in the PickAxe (which I won't restate here, suffice to say you should buy the book) I now see what they're all about and how damn useful they can be. I can also see how useful passing a parameter to a block can be:

And if we combine this with the ability to return a value from a block too:

And how about multiple paramaters? Easy:

All in all, blocks seem really controllable and intuitive (to me at least).

Surprise C3 - Ruby Functions Can React According to Whether They Were Called With a Block or Not

It gets even better. Ruby also allows you to simply code functions which can be called with blocks as well as without. If you call with a block, they can react in their own special way:

Surprise C4 - Ruby Blocks Can Be Closures

What we've seen so far haven't strictly speaking been closures. However, Ruby does allow you to use blocks in such a way that they are - blocks can be passed as arguments, and then assigned to variables as Proc objects, and then exceuted using the Proc#call method. To seal the deal, Ruby makes sure that it remembers the context in which a block was defined. That is to say the value of "self", plus the methods, variables and constants in scope. Behold:

Netbeans 6 Note: The grey squiggles under the start_button and pause_button variables indicates that they have been initialised, but not yet used. Handy eh?

Hasta luego!

Friday, 14 September 2007

More Ruby Surprises (and my first Ruby Disappointment)

I'm still going at the PickAxe book. This time it's arrays...

Ruby Surprise B1 - You can use negative indexes

If I use a negative index as the index to your array, it works, but you count from the right hand end, rather than the left:


Ruby Surprise B2 - No ArrayIndexOutOfBoundsException

If I blow the bounds on my array, I just get a nil, rather than an ArrayIndexOutOfBoundsException equivalent:


Ruby Surprise B3 - Addressing Ranges is Easy

There are a number of ways to get a range of values from my array. The first is to pass in two arguments, the start index and the range size:


Then there is the start index and the end index version...:


Or the start index and the one before the end index version...:


And I can even use the negative indexing paradigm as mentioned in Surprise B1...:


Ruby Dissapointment 1 - You can't Count Backwards Through an Array (but Groovy can)

This works in Groovy (which I am learning from a colleague has a very similar syntax to Ruby) but not Ruby:

Saturday, 8 September 2007

Ruby Surprises - Back to the Beginning with the PickAxe

I've recently bought the famous PickAxe book. The plan? To go back over all I know about Ruby from a different perspective to make sure I understand all the subtleties of the language. Here are some of the surprises so far for me, someone coming from Java land.

Surprise 1 - Classes are Always Open

In Ruby, classes are always open. This means that when you want to add a new method to them, you simply open them (with a new "class ... end") and add the code you require:

Here we've defined a new class "Song" and given it an initializer. Later (just below in fact) we've realised we need to add a "to_s" method. This is simple to do, simply by re opening the definition of Song. Ruby now sees the Song class as being a combination of all that we've defined for it. Therefore, when we run our code we get the following result:

NOTE: You can redefine any class you want, not just ones you've created yourself. This scares some hardcore Java programmers.

Surprise 2 - To Redefine a Subclass, No Need to Restate the Extension

Here we're going to do exactly the same as before with the "Song" example, but now we'll use a Subclass of Song; "KaraokeSong". As you'd expect, the first time we define KaraokeSong, we need to tell Ruby that it extends Song. However, when we re define it to add a "to_s" method, we can treat it simply as the class that it is. Ruby already knows it extends Song:

(Netbeans) Surprise 3 - Netbeans can't do Code Completion on Already Defined Variables in a Class Re-Definition

I guess this is probably too much to ask, but as I'm trying to learn how to use the Netbeans Ruby Editor at the same time as I learn Ruby, it is worth nothing that code completion for variables doesn't work if you are in a piece of code which is re defining a class which contains them:

On the positive side, it is very cool that code completion works within String literals. Regex completion is a godsend too.

Surprise 4 - Slimline Ruby Encapsulation

Anyone who has nearly gone insane hand-coding Javabean encapsulation code without the refactoring help of an IDE will have railed against the verbosity of the getXxxx and setXxxx paradigm. I was pleasantly surprised therefore to discover the simplicity and expressivity of the Ruby encapsulation code:

This to me makes it look as if the attribute is not encapsulated (which makes client code simpler and easier to read) when in fact it is (which means you get all the good points of encapsulation). Cool.

Surprise 5 - You can Encapsulate Virtual Attributes

Using this Ruby encapsulation idiom, you can encapsulate virtual attributes (i.e. ones which do not exist as actual instance variables):

(Netbeans) Surprise 6 - Class Attributes Must be Initialised Before You Use Them

It's a rule that a Ruby class attribute must be initialised before you use it. Netbeans reinforces this by not providing it as an option in code completion if you forget to do so (Though it would be cool if there was an associated tool tip to remind you to follow the rules):

That's it for now. More to follow as I progress through the book...

Monday, 30 April 2007

Packaging a Simple JRuby App Plus Gems

I've pretty much finished my first real ruby application. It's dead simple but does make use of two gems - Hpricot and simple-rss. Now, as I've blogged before the plan is to make this deployable as simply as possible to any system with a JVM available.

The big question I still had was how to package it? I was aware there had been some ruby magic going on while I wrote it what with the gems and everything but I did know that if I got a hold of the complete JRuby distribution available as a single jar file (the eponymous jruby-complete.jar which turned out to be a little hard to track down) I would be able to then just poke things into life with a simple "java" command:
java-jar jruby-complete-0.9.9.jar main.rb
I tried this and it worked perfectly. Until we hit one or my 'require' calls to the gems I'd used. How to get round that? I had a look around as usual. Ruby being ruby, the vast majority of information is on blogs, newsgroups and wikis. Unfortunately for me the JRuby wiki was down and all the blog entries were talking about far more complicated stuff to do with Rails. I was on my own...

So I had a look at the gems which I had installed. It's simple to find them (once you know where to look) just go to your ruby installation's home directory (CRuby or JRuby it's all the same) and then ".\lib\ruby\gems\1.8\gems". There you can see a list of all the gems your installation of ruby knows about:

You can see they are just directories. I had a look inside the aptly named "simple-rss" to see if what it contained made sense:


Seems simple enough. I read the README but it didn't tell me what I needed to know but the lib directory looked promising:


Only a single .rb file, excellent. I coped this to my project's lib directory (where all my .rb files live and ran the "java" command again. I was making progress, now the 'require' complaint was related to Hpricot.

Hpricot is a little more complicated. The standard version uses some components written in C. If you choose to download it manually from _why's subversion repo this is the one you will get.

NOTE: You can get most ruby libraries directly in this way without having to use ruby gems. Ruby Forge allows you to download them manually and if you open the archives you will find they have the same structure as when you use "gem -install" to get them.

Luckily, there is also a jruby version of hpricot for jrubyists which you can get via "gem -install". I looked in my jruby gems directory again and found the Hpricot gem:

A little more complicated this time but now I knew where I was going -./lib:

More than a single file this time but still pretty simple. I made an assumption that I could just do as I had before and just copy the complete contents of this folder across to my app. I did, ran the "java" command again and it worked. "Gordon's Alive!"

Loose Ends...
1. There are a few loose ends to tie up. I mentioned that the default Hpricot uses some C elements. These can be seen if you download the library manually and look in the ./lib directory. There, instead of "hpricot_scan.jar" you'll see "hpricot_scan.so". Not good for java...

2. It seems to me that if the jruby guys can package all the jruby bits and pieces inside a single jar, I could use the same method to package my bits and pieces with theirs and make my app a single jar file too. I'll blog about it when I figure out how to do this. In the meantime, I'm happy with a directory containing my ruby files, some html, the jruby jar and some shell scripts to keep me away from the command line.

Sunday, 29 April 2007

Ruby Convention - Return Value Comments on Statements

It is a Ruby convention to provide comments on the return value of a statement. E.g.:

With code colouring this is quite clear but can otherwise be confusing to a learner already confused with the unfamiliar syntax (like me)

Singleton Classes in Ruby

After my last post on my other blog where I'd described trying to get my head around Ruby inheritance and instance variables I got this comment:

To start with it confused me. (The '#' on the last line was missing too which didn't help.) As I'm still a real noob when it comes to Ruby I still have trouble coming to terms with the compact syntax which others use; however I'm in this to learn so I had a fiddle and here is the fruit of my labours.

It turns out (after a fair bit of googling/yahooing - spread the love man) that this is an example of a Ruby Singleton Class. I'll explain below but should first note that this is very much lifted from Ola Bini's post on the topic. I take it slower with some more code and hopefully some Java angles. Just to be clear, this is not original work but represents my thought processes in understanding Ola's illustration.

Ready? Lets go.

1. Ruby has no concept of things being final; unlike in Java. If I want to add a method or attribute to the String class, I just do it (you can even do this to Java classes when using JRuby, but let's not complicate things):

Note: You can see that Netbeans had seen that I've added a method to my String class and offers it as an option in the code completion dialogue. I'll continue to use the info Netbeans gives me as it maps onto how I think about Java.

When I run it I get this:

Cool. I've added a new method to the String class (a "Class Method" no less) and it's available from all my instances of the String class from now on. Ruby sees this as a good thing because you, the developer are free to place code where it makes sense to you and your object model - i.e. if I want my String to be able to say "hello" then this should go on the String class) But this isn't what we need to think about; more of a dipping of our toe in the water. Lets move on...

2. In Ruby, everything is an object, and all objects have a class which they are an instance of. You can get at these classes by calling the method class on any object you like. When you start coding the methods of your class will only be the ones available by defaut to that object's class. We can see these in Netbeans if we press CTRL-SPACE to get code completion:

Then we just saw we can add to this list by redefining the class itself in the standard way. There is however another way. Ruby also allows you to add new methods to any object. How? This is the first (and more intuitive to Java folks) way:

Which gives us this when we run it:

Super. As I'd expect. But there is another way and now we are heading into the land of Singleton classes. We can get an object's class by using "class". We can use "<<" to push this onto the class definition extension which follows. E.g.:

Again we can see that in the line of test code, Nebeans has picked this up and offers "bar" as an optional method on our foo object. We won't run it as I'm sure you can guess what it does. We have added a method to a foo object.

All still aboard? Lets complicate things further. We've added a method to foo which is a n instance of String. Is this method available to other Strings? Code completion will tell us:

Hmmm. Not on the list. If we look at the Navigator pane it's telling us the same thing:


And there's the clue; foo is now listed as a class with our bar method defined on it. What? Remember we said everything in Ruby is an object? Well, it turns out that even classes are objects. Confused? Free yourself from your Java chains! It means we can frig around with them just like anything else we can get our grubby mits on but we need to be aware of what Ruby does for us when we do.

What is happening is that when we define a new method on a specific object an new, anonymous class is inserted between that object and the real class (in this case "String") which defines it. (Remember, Ruby only has single inheritance so this is pretty easy to picture in your head.) When we call a method on foo, the interpreter first looks inside the anonymous class for a definition (if there is one) and then on to the real class.

Now for the final push. You'll have probably guessed that our anonymous class is actually what is called a Singleton class. Seems fair, but why the "Singleton"? As we've seen, all objects can have a Singleton class, even if the original user didn't intend it. You want it, you can add it. Fine. Now know that classes are objects themselves. Following me? I'll say it slowly as it took me a while too; C-l-a-s-s-e-s a-r-e o-b-j-e-c-t-s.

Lets take an example, the class String is actually an instance of the class Class,as are all classes. There is nothing special about these instances. Their names are capitalised simply because they are constants. Now, because every class is an instance of Class, what are called Class Methods in Ruby or Static Methods in Java are actually just a special case of Singleton Methods; ones which are defined on the instance of the class in question. Lets add a Singleton Method to the String class. As I'm coming to learn with Ruby, there's more than one way to do it, but there is a preferred way. First, the non preferred way:

And now the preferred way:


The first way is pretty simple. It's dead like the first example, way up the top of this page but the new hello method is private (It turns out that "private" in Ruby isn't what "private" is in Java but that's another post...) ; a Singleton Method. So why is the second way preferred? It's because it makes explicit the Singleton Class, both to you the developer and also to Ruby.

First, you the developer: In Ruby you need to think about how the code reads to you as a human being, not as a compiler as Java has taught you. This way shows us that the Singleton class is defined inside the class definition, and hello is defined on it. Just read it and you'll see.

Second, Ruby: Look at the Navigator for this way and compare it with the navigator for the first way. There is an extra "self" class in between the String and our function. This is the embodyment of the Singleton class.

We should explain this "self" a little more. Used on it's own in our code, "self" lets us get access to the class instance we are using it on like the first class in the code below. When used in a similar way to the preferred way it now gets us the Singleton class instance. We can see this in the second class. Again, look at the Navigator pane where it is made clear:

We can see that the syntax to get access to the Singleton class is the same we used to get access to foo.bar. We also can see that the navigator shows the clear difference between the two String classes - the latter has a Singleton class.

What about the differences between what these methods return? The former (the so called "regular self") returns the class instance: "String". The latter returns the Singleton class for the String.

So finally, lets return to the comment which started all this in the first place:

Clearly, we are defining a class ("C") and then adding a Singleton method and what I can only assume is called a Singleton attribute called "method". We then create a sub class of this ("D") and the last line of the code demonstrates that this sub class has access to the Singleton class instance. If we look at the Navigator, we can see all this laid out nicely for us as a hierarchy.

So why is this important? Well, as the comment stated, this is a nice and simple way to inherit class instance variables but more importantly this idiom is used in meta-programming, a mainstay or the Ruby world. For more detail on this I'd better leave it to Ola and his blog.