[RAD stands for
Ruby Ape Diaries, of which
this is part V.]
If you look at Ruby code, you keep seeing this little two-character motif
<<
, and maybe everyone else already knew about this, but
it sure feels like magic to this farm boy from the Prairies.
Bonus: Lisp speculation.
<<
is the name of a method, and you can define it to
mean anything you want, but normally it means “append-to-self”. For a File it
means “Write this on the end”, for an array or list or whatever (and Ruby
doesn’t seem to think there needs to be a difference) it means “add this as a
new element”, and for a string it means “concatenate in place”.
This last operation is particularly useful because, to use Java
terminology, it makes every String
into a
StringWriter
.
For example, suppose you’re writing a protocol using Net::HTTP
and you want to get a trace of the dialog. You say:
session.set_debug_output whatever
Then Net::HTTP
uses <<
on “whatever” to
store the trace. So if “whatever” were a file, you’d get a
logfile. But the simplest way to use this is to say:
trace = ""
session.set_debug_output trace
Then you get your session built up in the string “trace”.
For the Ape’s trace function, I needed to keep track of who said what, so I did something along the lines of:
trace = []
session.set_debug_output trace
Which gave me the dialog in a nice handy list. In practice, I wrapped the
array in a little class and redefined <<
so that I could
timestamp the entries and discard some of the housekeeping like “Connecting
to...”.
The Moral of the Story ·
Of course, every Rubyist knows this by heart, but it bears repeating: If
you’re writing any kind of logging or data-collection framework, do your
output with <<
. And if you’re building any kind of a data
structure that can grow, don’t forget to implement <<
.
Another Example ·
I got a bug report from Hugo Duncan
complaining that the Ape wasn’t doing a good job with relative URIs in general
and xml:base
in particular. He was right, the Ape was wrong.
The Ruby libraries have a URI fixer
but don’t seem to grok xml:base, so I had to write an absolutize
function to take a URI,
the node in the XML tree where it was found, and walk down the tree to the
node building up the appropriate base URI.
First I needed to compute the path from the root to the node:
def path_to node
if node.class == REXML::Element
path_to(node.parent) << node
else
[ ]
end
end
(It’s a pity I’m not preserving Emacs’ nice syntax coloring, but that would
be real work.) This is a straightforward recursive tree-climb that uses
<<
to build up the path.
There’s one more little bit of Ruby magic here; the way REXML builds trees,
you’d normally find that the root element has a parent, an instance of
REXML::Document
. But maybe not; you can get a situation where
that’s not there and the topmost element’s parent is nil
. But
hey, in Ruby everything’s an object, and so is nil
, and
nil.class
is NilClass
, so everything just works.
I’ve noticed that this idiom of referring to whatever.class
irritates real Rubyists. In this case, they’d be right. Because assuming I
eventually switch back to JRuby, those nodes won’t be instances of
REXML::Element
any more, but they will still have element-ish
methods like attributes
or children
or whatever.
Lisp · You notice that phrase “... to build up the path”? In a perverse mood, I might have written “... to cons up the path” because, as I would have been informed by numerous emailers if I didn’t pre-empt it here, every MIT undergrad was doing this kind of thing in Lisp by 1970, isn’t it quaint that the world is catching up, etc etc.
And they’d have a point; but Python and Ruby seem to have oozed further into the mainstream than Lisp ever has.
“Why?” is an interesting question, and I think the biggest single piece of the answer is inheritance from Perl’s culture of ruthless practicality. In other words, not afraid to use syntax to make the point; things are generally lists, except when they’re not; attention to typographic values; building hashes and regexes into the language; not requiring you to ever say “lambda”. Any more?
If Lisp’s audience had been harried sysadmins rather than AI researchers, it’d rule the world by now.