Mixing Our Way Out Of Instance Eval?
The lynchpin of Ruby’s pidgins and so-called DSLs (Douchebaggery as a Second Language) is the method known as instance_eval.
From an article titled Ruby DSL Blocks:
def self.order(&block)
order = Order.new
order.instance_eval(&block)
return order.drinks
end
And another one Implementing an internal DSL in Ruby:
def Expectations(&block)
Expectations::Suite.instance.instance_eval(&block)
end
From Creating DSLs with Ruby:
class MyDSL
def define_parameters
yield self
end
def self.load(filename)
dsl = new
dsl.instance_eval(File.read(filename), filename)
dsl
end
end#class MyDSL
So far, so good? Most often instance_eval is used, but you’ll see module_eval, too.
Now, the reason for this.
Jim Weirich: Within the builder code blocks, any method call with an implicit object target needs to be sent to our builder. To achieve this, the code blocks are evaluated with instance_eval which changes the value of self to be the builder.
He goes on to say why this could be troubling.
This is OK until you want to call a method in the calling object. Since self is no longer the calling object, you have to explicitly provide the caller.
In Weirich’s Builder, he prefers to use plain blocks and hand you the variable.
builder { |xm|
xm.em("emphasized")
xm.em { xm.b("emp & bold") }
xm.a("A Link", "href" => "http://onestepback.org")
xm.div { xm.br }
xm.target("name" => "compile", "option" => "fast")
xm.instruct!
xm.html {
xm.head {
xm.title("History")
}
xm.body {
xm.comment! "HI"
xm.h1("Header")
xm.p("paragraph")
}
}
}
With instance_eval, you’d end up with:
builder {
em("emphasized")
em { b("emp & bold") }
a("A Link", "href" => "http://onestepback.org")
div { br }
target("name" => "compile", "option" => "fast")
instruct!
html {
head {
title("History")
}
body {
comment! "HI"
h1("Header")
p("paragraph")
}
}
}
Builder once did use instance_eval, but now offers this explanation in the docs:
The instance_eval implementation which forces self to refer to the message receiver as self is now obsolete. We now use normal block calls to execute the markup block. This means that all markup methods must now be explicitly send to the xml builder.
Rails’ routing stuff also prefers to go without instance_eval:
ActionController::Routing::Routes.draw do |map|
map.with_options :controller => 'blog' do |blog|
blog.show '', :action => 'list'
end
map.connect ':controller/:action/:view'
end
By now, it probably seems like instance_eval has been driven out of play by the mature libs and now only lingers in the dabbling blog posts.
I don’t care about the best way to do this. The fact is: even “normal blocks” are prone to bugs. I had to fix up the Builder example above because it’s wrong in the docs.
xm.em("emphasized") # => emphasized
xm.em { xmm.b("emp & bold") } # => emph & bold
xm.a("A Link", "href"=>"http://onestepback.org")
# => A Link
xm.div { br } # =>
There are two errors in the above example. The date on the RDoc is Sun Feb 05 23:49:01 EST 2006.
Recently I discovered another option to all of this, thanks to the work of Guy Decoux.
While investigating a library Guy never released (called prop,) I realized that perhaps he was on to something while fooling with mixins and the inheritance chain.
Think about it: instance_eval changes self, intercepts method calls and alters instance variables. Really, all we really want to do is dispatch method calls. As Jim Weirich says, changing self is the troubling side effect here.
This is a pertinent topic. Even today, ruby-core discusses a with operator and Paul Brannan chimes in:
Instance_eval for initialization has surprising behavior for instance variables (e.g. as in Ruby/Tk).
A method that affects only method calls and not instance variables would make this idiom more viable.
I don’t know whether that is a good thing or a bad thing.
Again with the good and bad.
What if there was a way to temporarily add methods for the duration of a block?
def to_html
Builder.capture do
html do
head do
title self.friendly_title
end
body do
comment! "HI"
h1("Header")
p("paragraph")
end
end
end
end
The essence of Builder.capture is to mixin a bunch of Builder methods, inject them into the block’s binding. This adds the html, head, comment! methods into the calling self.
Using a very small extension called mixico:
def Builder.capture &blk
mix_eval(self, &blk)
end
This extension enables and disables mixins atomically. It is a single, quick operation to add and remove a module from the inheritance chain. (See the mixico README for more on this technique.)
The mix_eval method code looks like this:
class Module
def mix_eval mod, &blk
blk.mixin mod
blk.call
blk.mixout mod
end
end
The mixin and mixout methods enable and disable the Module in the block’s binding.
While you might be inclined to dismiss this on the grounds of it being mixin magic, I’m starting to believe that this is a notable omission from Ruby. It’s very quick and efficient to disable and enable mixins and could prove to be a very handy technique.
Like open classes, however, I’m afraid the timidity of the business community might label it as taboo, despite it offering great flexibility to you — all of my fine, able-minded friends out there.



























