[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

when I say method_defined? I mean it!

Trans

7/22/2006 2:26:00 PM

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.


7 Answers

Erik Veenstra

7/22/2006 4:44:00 PM

0

> 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.erikve...


Trans

7/22/2006 5:00:00 PM

0


Erik Veenstra 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

7/23/2006 12:51:00 AM

0

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.

Trans

7/23/2006 2:03:00 AM

0


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.

Dumaiu

7/23/2006 7:15:00 AM

0

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

Trans

7/23/2006 12:01:00 PM

0


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.

Dumaiu

7/24/2006 2:24:00 AM

0

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