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...)
I'm a Java programmer. I'm learning Ruby. This is where I'll think out loud and collate my experiences. Please tell me what you think.
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...)
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!
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:
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: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: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: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):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...
java-jar jruby-complete-0.9.9.jar main.rbI 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...