Digging Deep with Instance_eval #
I feel like instance_eval
deserves a friendlier name. Especially when used in tandem with a block to reach down inside an object for a moment.
A great example of this is on the RubyGarden wiki under RubyStyleGuide/InjectComplexTestsIntoObjects. The challenge is to reduce the redundancy of the below.
f = open("myfile") if f.stat.readable? and f.stat.writable? and f.stat.size? and f.stat.owned? # work with file end
My favorite solution involves instance_eval
, but see how long and ugly it looks? Perhaps an answer would be aliasing a name like within
for simple block calls to instance_eval
.
f = open("myfile") if f.stat.instance_eval{ readable? and writable? and size? and owned? } # work with file end
MenTaLguY
Used that way, it’s a bit like a
with
block in Visual Basic, actually.(Horrid comparison, I know, but it’s the first thing that came to mind. And it is a convenient thing sometimes.)
MenTaLguY
Ah, I see someone’s actually gone and done an Object#with, though employing method_missing? to do it.
The disadvantage of instance_eval over the method_missing? is that you can’t easily call private methods from the enclosing scope.
Doesn’t matter for what you’re trying to do here, but it’s limiting in more general usage.
MenTaLguY
Another solution for minimizing redundancy in this particular case might be:
Heh. Horrid, no?
BloodyEll
I think MenTaLguY needs a spanking for that last one.
timsuth
How about
MrCode
f.stat is called for each invocation of the block for MenTaLguY and timsuth’s examples, which could be inefficient. So a separate variable is needed for best efficiency. Or instance_eval could be used, but that gets real ugly:
By the way, here is another version:
Not all that clever, but just obfuscated enough to be interesting ;)
Hey _why, what is wrong with the “is?” method created on the above linked page? That sure looks clean to me…
zem
What would be nice would be a method to do a series of sends to an object and collect the results. (“Collect” would actually be a great name for this, shame it’s a synonym for “map” instead).
why
MrCode: nothing wrong with it. How would you do “or” logic with it, if you wanted? I guess multiple “is?” calls.
murphy
I think Ruby has other ways to mimic a with-like behaviour.
My favorite: Extending classes.
It seems logical that the File::Stat object is responsible for managing that.
bleh
no pls, not yet another reinvention of
I find the one based on method_missing ugly. Not thread-safe, too much code…
MenTaLguY
You could make a threadsafe one actually.
Wouldn’t have immediate access to the object’s instance variables, but if you did you’d be using instance_eval anyway.
Private methods will be dispatched to the object passed as a parameter to with, if it responds to them, else they will be dispatched in the calling context.
Of course this won’t work totally. Object/Kernel methods on DoubleDelegate will take the highest precedence of all.
You can have DoubleDelegate undefine any methods it gets from its ancestors, or you can find some way to make DoubleDelegate a class that doesn’t inherit from Object or Kernel.
MenTaLguY
I imagine this sort of thing is why Matz wants a “bare” superclass for Object, actually.
MenTaLguY
Until then I suppose you can do something like this, if you have Evil Ruby or similar installed to get Object#class=
Untested. If you try it and open a portal to Hell or something, you were warned.
Comments are closed for this entry.