Brian's Waste of Time

Mon, 24 Apr 2006

(Ruby) Corrupted by JavaScript

I have been corrupted by JavaScript. Ruby really annoyed me when I could not just add properties and functions totally willy-nilly to instances. Ruby makes it easy to reopen classes, or even instances, but it is not so obvious how to do so without creating a new scope (and hence losing your closure).

The ~standared mechanism is to do something vicious like this:

foo = "hello"
msg = "woot!"
class<<foo; self; end.send(:attr_accessor, :bar)

class<<foo; self; end.send(:define_method, :woot) { puts msg }

foo.bar = 7
foo.woot # => "woot!"

Aside from the fact that this is a vicious hack, it relies on the fact that send lets you invoke private methods (define_method) on the singleton class (more recently going by the alias of eigenclass) of foo. This is pretty much a bug and a violation of the object. It's like object rape, or something.

A nicer way to do it, to my mind, is to use anonymous modules. The really nice part of using anonymous modules is that the Module constructor takes a block which is evaluated in the context of the new module, letting you legally call private methods, like define_method.

moo = "TOOW!"
foo.extend(Module.new { attr_accessor :baz })

foo.extend(Module.new { define_method(:toow) { puts moo }} )

foo.baz = 7
foo.toow # => "TOOW!"

moo = "MOOO!!"

foo.toow # => "MOOO!!"

This has the same effect and no nasty exploitation of the send bug!

Of course, with javascript, it is just...

foo = "woot"
foo.bar = 7
foo.stuff = function(a, b, c) { a * b * c }

I still like ruby more, though ;-)

1 writebacks [/src/ruby] permanent link