What I love most about Ruby
June 29, 2010 § 1 Comment
I have some friends (Hi Dustin) that are serious language geeks, whom I often get into debates with. One of my common refrains is “to do it the Ruby way”, because (while Ruby has its warts) it does so many little things beautifully well. So, as future ammunition, I figured I should try to collect links to my favorite Ruby features (much as many others have already done before me).
I. Language Features
These are intrinsic features of Ruby the language that allow some really elegant API design and programming solutions. Many syntactic elements are stolen from Perl, but generally employed with much better taste. 🙂
1. Implicit trailing block arguments (yield).
In Ruby, any method (function) can always take a block as an optional argument at the end. It doesn’t need to be declared, and it doesn’t even need to be inside the parentheses. It can be accessed implicitly by calling “yield”, or “reified” into an actual argument by declaring a “&block” argument. This is particularly nice for iterators, callbacks, and HTML templates. I used this heavily in my Dispatch library for MacRuby.
2. Literals
Ruby provides convenient, built-in literal syntax for all sorts of things. In addition, Ruby provides an alternate “%” notation (which can use any open/close character) to avoid the need for escaping the enclosing character.
- blocks { block literal }
- strings “foo” %q{foo}
- symbols (unique strings) :foo %s’foo’
- arrays [“foo”, “bar”] %w|foo bar|
- dictionaries {:foo => “bar”} or {foo: bar}
- ranges 0..5 1…3
- regular expressions /reg.*/ %r(reg.*)
- shell invocation `do this` %x!do this!
- characters ?a
- numbers (including binary, and allow “_” for readability) 0b1111_0000
- Primitives: nil, true, false,
This dramatically reduces the syntactic noise when working with all kinds of constructs.
3. String interpolation
In addition, String, Symbol, Regexp, and Shell all support interpolation, where you can ‘inline’ a variable inside a string or other literal “these are #{count} reasons I love Ruby”
4. Array (de)composition, aka “Splat”
The Ruby splat operator (“*”) converts between arrays and discrete objects. Thus, you can easily “explode” an array into an argument list for a function, or assign a returned array to a list of variables.
- The splat operator in Ruby « 4 Lines of Code
- Ruby idioms : The splat operator. « The Plan A
- nick – Ruby Pearls vol. 1 – The Splat
5. Namespaces as objects
In Ruby, (nearly) everything is an object. This includes Modules, which (among other things) serve as namespaces. Classes defined within a module are just constants within that namespace. This also means one can create convenience methods directly on that module, which reduces the need for global variables and can veil the complexity of the underlying classes.
6. “Compile-time” class methods
The Ruby Class class is actually a subclass of Module, and thus also a first-class objects. What this means is that building classes is simply a matter of executing code within the context of a “class” scope. As such — apart from the primitive “def” object for creating functions — all other directives (e.g., attribute properties, public/private) are really just class methods.
This means you can effectively extend or change the semantics of class construction just by extending the “Class” class. Ruby also makes it very clean and easy to define new class methods to use as factories, which avoids the “designated initializer” confusion of Objective-C.
- Ruby Class Tutorial
- Ruby Classes and Objects
- Class and Instance Variables In Ruby // RailsTips by John Nunemaker
- Class: Class
II. Standard Library
The following functions aren’t part of the core language per se, but are baked into the standard library.
1. Transparent URL handling
There’s a Ruby module called “open-uri” that transparently extends the “open” method to work with URLs as well as files. It makes network access brain-dead simple.
2. Smart Casting
As a strongly typed language, Ruby doesn’t automatically convert between different data types; but as a dynamic language, it doesn’t let you explicitly specify cast. So what does it do instead?
It defines a conventional set of “to_*” methods to handle conversions, many of which are implemented by Object and thus inherited by all other Ruby objects. Cleverly, there are both “permissive” and “exact” versions, with the latter giving an error if no exact conversion is available.
- to_a, to_ary, to_enum
- to_f
- to_hash
- to_i, to_int
- to_io
- to_json
- to_proc
- to_s, to_str, to_sym
- to_xml
- to_yaml
The permissive versions are extremely short, which makes “casting” feel very lightweight, but unambiguous.
3. XML/HTML manipulation
Partly as a result of the above, Ruby provides some very elegant libraries for both generating and parsing XML and HTML. Importantly, the recent ones use CSS and/or XPath queries, which are much easier to use than explicit DOM or SAX parsing for common tasks.
[…] Filed under: Uncategorized — Dr. Ernie @ 2:21 pm Following up on my (subjective) list of what I like about Ruby, here’s a (relatively objective) list based on articles about what makes programming […]