How do you modify the scope passed to a block?
I've been working with Ruby for a little under a year, and I still don't fully understand "what makes blocks tick". In particular I'm curious how much control one has over the scope of a block. For example, say I have this code:
class Blob
attr_accessor :viscosity
def configure(&:block)
block.call self
end
end
blob = Blob.new
blob.configure do |b|
b.viscosity 0.5
end
A bit of a contrived example there, obviously.
Now, one thing I've noticed while migrating from Rails 2 to Rails 3 is that a lot of their con开发者_如何学Pythonfiguration methods that take blocks no longer take a non-block argument.
For example, in routes.rb, it used to be ActionController::Routing::Routes.draw do |map| ... end
, and now it's just ActionController::Routing::Routes.draw do ... end
. But the methods that are called inside the block still have the appropriate context, without the need to repeat the name of the block's argument over and over.
In my example above, then, I want to be able to do:
blob.configure do
viscosity 0.5
end
so that I can tell people how easy it is to write a DSL in Ruby. :)
This uses instance_eval
to do the magic. See http://apidock.com/ruby/Object/instance_eval/ for some documentation. instance_eval
evaluates a block (or a string) in the context of it's receiver.
def configure(&block)
self.instance_eval &block
end
You'd still have to use the accessor method viscosity=
in your example block or you'd have to define
def viscosity(value)
@viscosity = value
end
in your class.
精彩评论