I’ve been bitten by this way too many times now. And I’m just plain
tired of it.
Today’s case:
def wrap_method( sym, &blk )
raise ArgumentError, “method does not exist – #{sym}” unless
method_defined?( sym )
old = instance_method(sym)
define_method(sym) { |*args| blk.call(old.bind(self), *args) }
end
Seems all well and good until now when it comes out that
#method_defined?, like #instance_methods, does something only a Ruby
hacker without a life would expect. The actual monster code needed
is:
def wrap_method( sym, &blk )
unless public_method_defined?( sym ) || private_method_defined?(
sym ) || protected_method_defined?( sym )
raise ArgumentError, “method does not exist – #{sym}”
end
old = instance_method(sym)
define_method(sym) { |*args| blk.call(old.bind(self), *args) }
end
Now, it just doesn’t stand to any good reason. When we wan’t to
actually grab a method, we don’t use #public_instance_method, do we?
That would be a nightmare! And so it is with the above case and many
others I’ve delt with. Every time I have to go back and fix this “bug”
recalling the terribly inconvenient and anti-literal definition of
these methods-methods.
T.
def wrap_method( sym, &blk )
raise ArgumentError, “method does not exist – #{sym}” unless method_defined?( sym )
old = instance_method(sym)
define_method(sym) { |*args| blk.call(old.bind(self), *args) }
end
Replace “unless method_defined?( sym )” with “unless
(method(sym) rescue nil)”.
But you don’t need this check. instance_method(sym), on the
next line, already performs this check for you.
gegroet,
Erik V. - http://www.erikveen.dds.nl/
I think Mr. Veenstra’s approach is fine–either allow the exception
from instance_method() to percolate up, or rescue it and throw your
own. As far as a comprehensive check goes, wouldn’t ‘unless
method_defined? || private_method_defined?’ suffice? Or you could, I
guess, use
unless Object.new.extend(self).respond_to?(sym, true)
which seems more amusing.
Erik V. wrote:
def wrap_method( sym, &blk )
raise ArgumentError, “method does not exist – #{sym}” unless method_defined?( sym )
old = instance_method(sym)
define_method(sym) { |*args| blk.call(old.bind(self), *args) }
end
Replace “unless method_defined?( sym )” with “unless
(method(sym) rescue nil)”.
Tha won’t work b/c it would be looking at the module or classes
methods, not the instance methods.
But you don’t need this check. instance_method(sym), on the
next line, already performs this check for you.
Oh right, thanks, I’ll change.
Nonetheless if I wanted to do something else with the check, the point
of my post remains. It silly to have to check
public_methods || private_methods || protected_methods
When #instance_methods should just correspond to the behavior to
#instance_method. I mean, isn;t reasonable to think those two methods
would have the same lookup behavior?
T.
Dumaiu wrote:
I think Mr. Veenstra’s approach is fine–either allow the exception
from instance_method() to percolate up, or rescue it and throw your
own. As far as a comprehensive check goes, wouldn’t ‘unless
method_defined? || private_method_defined?’ suffice? Or you could, I
guess, use
unless Object.new.extend(self).respond_to?(sym, true)
which seems more amusing.
I think my point is being missed. Forget my last example, it has
nothing to do with it --it was just a special case --one in which I
didn’t end up needing to check if the method existed b/c it was going
to do what I was telling it do anyway. I could just as easily taken a
different route.
My point is about the semantic meaning of important methods about
methods. Think about it like Dr. Suess. Let’s say I have these methods:
big_fish #=> [ “tuna”, “saw” ]
small_fish #=> [ “trout”, “croaker” ]
tiny_fish #=> [ “beta” ]
So what woud expect from just:
fish #=> ?
T.
Tempting as it is to respond to Dr. Seuss, I think it makes more
sense to ask you to state your point as succinctly as possible so as to
prevent further misunderstanding. I’m guessing you dislike the fact
that method_defined?() doesn’t consider private methods–?
-J
Dumaiu wrote:
Tempting as it is to respond to Dr. Seuss, I think it makes more
sense to ask you to state your point as succinctly as possible so as to
prevent further misunderstanding. I’m guessing you dislike the fact
that method_defined?() doesn’t consider private methods–?
Yes --and protected. method_defined? is one of the culprits, and so
are #methods and #instance_methods. Here’s my Dr. Seuss analogy
de-anaologized:
public_instance_methods #=> [ “tuna”, “saw” ]
private_instance_methods #=> [ “trout”, “croaker” ]
protected_instance_methods #=> [ “beta” ]
So what woud expect from just:
instance_methods #=> ?
T.
A quick test I did in irb suggests that methods(),
instance_methods() and method_defined?() all register protected
members, meaning that only the, uh, privates are omitted. I concede
that it can be confusing, but there’s no point submitting a RCR without
an understanding of the current rationale. I suppose the idea is that
because private methods are implementational, you shouldn’t have to see
them without specifically asking. Of course, prohibiting access would
be out of character for Ruby; hence the optional respond_to?()
parameter.
I might like having an optional switch for instance_methods(), too,
but in all I think the setup is satisfactorily logical and consistent.
My thinking on the matter is a bit clearer now. How about you?
-J