I was recently asked what I like about Ruby. The succinct reason is that I can more easily and quickly apply it to more problems than other languages that I know. The rest of the explanation follows.
Ruby blocks are chunks of code that can take parameters. They can be passed to methods which yield to them, or they can be called directly. When my core language was Java I found myself repeatedly implementing the factory and template patterns together. A superclass would declare a method which does something and then calls what it defines as an abstract method. Then a subclass would define the contents of the abstract method. An instance of the subclass would call its superclass method, which would in turn call it's implementation. An instance of a different subclass would get the similar template behavior while being able to vary part of the implementation. This requires a superclass, 2+ subclasses, and usually a factory to implement. In Ruby, the variable implementation part of the method can just be injected through a block to a method that yields to it. It can be accomplished in a single class.
Methods are called with messages
Ruby invokes methods by sending messages. Calling send with a symbol that matches the method name will invoke the method. Accessibility constraints (public, protected, private) are ignored when sending messages. In Java, accessibilty is a big problem for testing. How can a unit test test a private method if only the target object can call the method? Usually the answer is to move accessibility up to default or protected. In Ruby, rather than calling the method after an accessibility change, you can leave accessibity alone and just send a message to it. Thus, best practices for object oriented accessibility rules can be followed while testing is still easy to accomplish.
Updated 7/22/12: typo - thank you Florian for the correction.
1 class A 2 def hi 3 puts 'hi' 4 end 5 end 6 7 a = A.new 8 a.hi => 'hi' 9 a.send :hi => 'hi'
Ruby only supports instance methods. Ruby classes are objects of class Class bound to the constant that is used as their name. All class methods are implemented as instance methods on the singleton class of the class in question.
1 class Foo 2 3 def foo () 'foo' end 4 5 def self.bar () 'bar' end 6 7 class << self 8 def baz () 'baz' end 9 end 10 11 self # => Foo 12 self.class # => Class 13 self.singleton_methods # => ["bar", "baz"] 14 end
This language feature makes mocking a breeze, which means that test driven development can actually happen. It also makes monkey patching third party libraries easy.
Pure object orientation
In Java there are primitive types and objects. For example, 1 is of type int, which is a primitive data type. It can be converted to an Integer, which is a newer object oriented representation of an int. Collections can only hold objects. Autoboxing allows the easy conversion from int to Integer, but what happens when an Integer of value null is autounboxed? It raises an exception. Furthermore I remember when autoboxing didn't exist in Java. It wasn't fun. There's no need to think of any of this in Ruby as everything is an object. This entire class of problems just never existed in the first place.
A rich API and busy community
Any language that is going to be useful across a multitude of problems needs a large API. Ruby not only has a large API, but it has quick and easy access to a very large set of community created external libraries called Ruby Gems.
What is it good for?
Ruby is a great choice for the following types of projects (among other things):
- web applications
- shell scripting
- client/server applications
- rule engines
More than enough rope to hang yourself
All of this expressive power is great; however, anything is subject to change. Change isn't always good...
1 1+1=2 2 3 class Fixnum 4 def +(other) 5 self - other 6 end 7 end 8 9 1+1=0