Forum: Ruby #respond_to? not working for dynamically generated methods

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
8749270955fc7c361eac3d6073a8ffcf?d=identicon&s=25 Maurice Gladwell (maurice-gladwell)
on 2007-05-30 10:42
It seems Object#respond_to doesn't work for dynamically generated
methods:

SomeRailsModel.respond_to? 'find_by_name' #=> false

1. Is there some way to *really* check if an object will respond to a
message, even if it will respond by a dynamically generated method?

Right now, Object#respond_to? just doesn't do what it name promises: it
doesn't check if an object responds to a message :foo, only if the
object has a :foo method defined.

Thanks,
Maurice B. Gladwell
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2007-05-30 11:02
(Received via mailing list)
Alle mercoledì 30 maggio 2007, Maurice Gladwell ha scritto:
> object has a :foo method defined.
>
> Thanks,
> Maurice B. Gladwell

Are you sure find_by_name is a class method and not an instance method
(i.e,
do you call SomeRailsModel.find_by_name or something like
SomeRailsModel.new.find_by_name)? I don't know Rails, so I may be wrong,
but
to me it seems that find_by_name is an instance method. If it is so,
then you
can't expect SomeRailsModel.respond_to? to return true. This has nothing
to
do with the method being dynamically generated. For instance,

Array.respond_to?(:select)

gives false, because select is an instance method.

Array.new.respond_to?(:select)

gives true, instead.

If you want to know whether a class has an *instance* method without
first
creating an instance of the class, you can call instance_methods on the
class. It will return an array with the names of the methods instances
of the
class will have. For example:

Array.instance_methods
=>["select", "[]=", "inspect", "<<", ... ]

In your case, if find_by_name is an instance method, you can do this:

SomeRailsModel.instance_methods.include? 'find_by_name'

I hope this helps

Stefano
8749270955fc7c361eac3d6073a8ffcf?d=identicon&s=25 Maurice Gladwell (maurice-gladwell)
on 2007-05-30 11:10
Stefano Crocco wrote:
> Are you sure find_by_name is a class method and not an instance method

Yes, I'm positive:

>> SomeRailsModel.respond_to? 'find_by_name'
=> false

>> SomeRailsModel.find_by_name 'foo'
=> #<SomeRailsModel:@name='foo'>

M.
F1d6cc2b735bfd82c8773172da2aeab9?d=identicon&s=25 Nobuyoshi Nakada (Guest)
on 2007-05-30 11:12
(Received via mailing list)
Hi,

At Wed, 30 May 2007 18:01:59 +0900,
Stefano Crocco wrote in [ruby-talk:253530]:
> In your case, if find_by_name is an instance method, you can do this:
>
> SomeRailsModel.instance_methods.include? 'find_by_name'

method_defined? would be better in almost cases.
D9d7afc2a6bd87c96532f91da29553f1?d=identicon&s=25 Sascha Abel (daemor)
on 2007-05-30 12:03
Maurice Gladwell wrote:
> It seems Object#respond_to doesn't work for dynamically generated
> methods:
>
> SomeRailsModel.respond_to? 'find_by_name' #=> false
>
> 1. Is there some way to *really* check if an object will respond to a
> message, even if it will respond by a dynamically generated method?
>
> Right now, Object#respond_to? just doesn't do what it name promises: it
> doesn't check if an object responds to a message :foo, only if the
> object has a :foo method defined.
>
> Thanks,
> Maurice B. Gladwell

I think 'Object#respond_to?' just looks at a list of previously
*defined* methods, as does 'method_defined?', it doesn't matter if
they're defined dynamically at runtime or not. 'find_by_name' is not
really a method in Rails, it's just the magic of method_missing that you
can call it on SomeRailsModel.

In order to find out which methods SomeRailsModel would respond to you'd
have to write a method that looks at 'method_missing' and works out all
the possibilities there. I'm by no means an expert (neither for Ruby nor
Rails), but SomeRailsModel will respond to every 'find_by_foo' method,
where foo is column of the underlying database, so your task seems way
too big for such like me..

Sascha
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-30 12:39
(Received via mailing list)
Hi --

On Wed, 30 May 2007, Maurice Gladwell wrote:

> object has a :foo method defined.
That's what responding to a method means.  Otherwise, it would be
meaningless, since you can send any message to any object.

Things like find_by_name are made possible by method_missing, which
intercepts uninterpretable messages.  It's possible for method_missing
to generate a new method dynamically, but it doesn't have to (and in
fact "find_by_name" does not get generated as a method; it just gets
examined as a string).  Even if it does, there's no way for respond_to
to figure it out.

Basically, to know what's going to happen dynamically, you have to run
the program and send the messages.


David
E0526a6bf302e77598ef142d91bdd31c?d=identicon&s=25 Daniel DeLorme (Guest)
on 2007-05-30 13:09
(Received via mailing list)
dblack@wobblini.net wrote:
> Basically, to know what's going to happen dynamically, you have to run
> the program and send the messages.

Or you have to patch rails so that respond_to? will take this case into
account. It's open source, what are you waiting for? ;-)

Daniel
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 13:52
(Received via mailing list)
On 5/30/07, dblack@wobblini.net <dblack@wobblini.net> wrote:
> > message, even if it will respond by a dynamically generated method?
> >
> > Right now, Object#respond_to? just doesn't do what it name promises: it
> > doesn't check if an object responds to a message :foo, only if the
> > object has a :foo method defined.
Does not look right though

# vim: sts=2 sw=2 expandtab nu tw=0:


module M
  def m; "m" end
end
class A
  def a; "a" end
end

class B < A
  include M
end

b = B.new
def b.b; "b" end

p B.new.respond_to?(:a)
p B.new.respond_to?(:m)
p B.method_defined?(:a)
p B.method_defined?(:m)
p b.respond_to?(:b)
true
true
true
true
true

looks pretty good to me.
Is Rails fooling around with my beloved Ruby ;) ?
For what concerns intercepted messages for which no methods exist
David has said it all below:...
>
> Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
> A. Ruby Power and Light, LLC (http://www.rubypal.com)
>
>

Cheers
Robert
8749270955fc7c361eac3d6073a8ffcf?d=identicon&s=25 Maurice Gladwell (maurice-gladwell)
on 2007-05-30 13:56
David wrote:
> [...]
> Basically, to know what's going to happen dynamically, you have to run
> the program and send the messages.

It would be possible to define at writing time the entire range of
messages that an object will respond to. Here's how:

There are two kinds of messages to which an object responds by something
that is not a NoMethodError:

1) Those corresponding to defined instance methods.

2) Those that are handled in some way by method_missing.

#1 is already well defined and thus handled by #respond_to?. So if we
could just define the range of messages recognized by method_missing, we
could have an object return the entire range of messages to which it
will respond.

Of course, we don't have standard support for that currently, but we
could (e.g. with some DSL) declare inside the class definition (e.g.
above the `def method_missing`) patterns to which method_missing would
respond.

So for example, in ActiveRecord::Base we would have something like:

responds_to /find_by_.+/

Thus `SomeRailsModel.respond_to? :find_by_name` would have the knowledge
it needs to return the correct answer: true.

--
M.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-30 13:56
(Received via mailing list)
Hi --

On Wed, 30 May 2007, Robert Dober wrote:

>> > 1. Is there some way to *really* check if an object will respond to a
> module M
> b = B.new
> true
> true
>
> looks pretty good to me.
> Is Rails fooling around with my beloved Ruby ;) ?

No, it's just using method_missing, which intercepts the
"find_by_name" message.

> For what concerns intercepted messages for which no methods exist
> David has said it all below:...

I'll go along with that :-)


David
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 14:00
(Received via mailing list)
On 5/30/07, dblack@wobblini.net <dblack@wobblini.net> wrote:

> > Is Rails fooling around with my beloved Ruby ;) ?
>
> No, it's just using method_missing, which intercepts the
> "find_by_name" message.
Ok that is acceptable ;) thx for the clarification.
>
> > For what concerns intercepted messages for which no methods exist
> > David has said it all below:...
>
> I'll go along with that :-)
We are risking recursive mutual agreement causing stack overflow ;)
Cheers
Robert
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-30 14:54
(Received via mailing list)
Hi --

On Wed, 30 May 2007, Maurice Gladwell wrote:

>
> 1) Those corresponding to defined instance methods.
>
> 2) Those that are handled in some way by method_missing.

That's every possible string you can sent to an object.

> So for example, in ActiveRecord::Base we would have something like:
>
> responds_to /find_by_.+/
>
> Thus `SomeRailsModel.respond_to? :find_by_name` would have the knowledge
> it needs to return the correct answer: true.

That's a bit of a conversation-stopper :-)  But I'll just observe that
"responding to a message" is really a kind of high-level, abstract way
of saying that the object has a method it can run whose name
corresponds to the message.  That's not true of "find_by_name" in the
case of an ActiveRecord::Base subclass; there is no such method, and
the only way an object can handle the message is with method_missing,
which is not the same as the message itself being understood by the
object.

You could of course shoehorn find_by_* into respond_to? for AR
objects, if you don't mind, essentially, writing method_missing twice
(once for real, once as a kind of pseudo-static twin).  But in the
general case, method_missing really means it's missing, and it's
handled at the time in ways that cannot be predicted or registered
with the system in advance.  For example:

   class C
     def method_missing(m)
       super unless rand(2).zero?
       puts "I'm handing your message!"
     end
   end

   c = C.new

Does c respond to "blah"?

In sum, the way it's engineered, with objects responding to certain
messages (in the sense of having corresponding methods), and
method_missing available to handle the missing ones, gives you more
latitude and flexibility than you'd be able to encapsulate in a
missing-method registry.


David
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-30 15:05
(Received via mailing list)
On May 30, 2007, at 7:53 AM, dblack@wobblini.net wrote:

> You could of course shoehorn find_by_* into respond_to? for AR
> objects, if you don't mind, essentially, writing method_missing twice
> (once for real, once as a kind of pseudo-static twin).

I don't really understand this stance.  My opinion is that providing
a method_missing() implementation is a convenient way for a
programmer to define a lot of dynamic methods.  This increases the
messages an object responds to.

Following from that logic, I believe you should also override
respond_to?() to reflect those new messages.  It's my opinion
therefore that this thread has exposed a bug in Rails that should be
patched.

As for the double implementation, I would think we would handle that
in the usual way.  You use an Extract Method refactoring to pull out
the matching logic into a separate private method and use that in
both implementations.

Those are just my opinions though.

James Edward Gray II
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 15:34
(Received via mailing list)
On 5/30/07, James Edward Gray II <james@grayproductions.net> wrote:
> On May 30, 2007, at 7:53 AM, dblack@wobblini.net wrote:
>
> > You could of course shoehorn find_by_* into respond_to? for AR
> > objects, if you don't mind, essentially, writing method_missing twice
> > (once for real, once as a kind of pseudo-static twin).
>
> I don't really understand this stance.  My opinion is that providing
> a method_missing() implementation is a convenient way for a
> programmer to define a lot of dynamic methods.  This increases the
> messages an object responds to.

I have always felt that dynamic method creation and dynamic message
interception are not quite the same beast. But I guess you have some
thoughts behind your claim of which I fail to grasp the concept. Would
you mind to elaborate?

To be honest, with my lack of imagination, right now I really do not
like the idea to tweak #respond_to? .

Am I right that in the following case

class A
   def method_missing name, *args, &blk
      return whatever(name, *args, &blk)
   end
end

A.new.respond_to(x) would be true for whatever x - if it were for your
idea.

Is this really a good idea?

Cheers
Robert

<snip>
> Those are just my opinions though.
Same here :)
>
> James Edward Gray II
>
>
>
Robert
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (Guest)
on 2007-05-30 15:42
(Received via mailing list)
On Wed, May 30, 2007 at 08:56:08PM +0900, Maurice Gladwell wrote:
> Of course, we don't have standard support for that currently, but we
> could (e.g. with some DSL) declare inside the class definition (e.g.
> above the `def method_missing`) patterns to which method_missing would
> respond.
>
> So for example, in ActiveRecord::Base we would have something like:
>
> responds_to /find_by_.+/

Hmm, everybody forgets to anchor their regular expressions :-)

Anyway, this doesn't seem right. find_by_foo will fail if there is no
column
called 'foo'. So really you should really check that the column exists.

But that doesn't work either, when you remember that AR also supports
find_by_foo_and_bar(x,y), find_by_foo_and_bar_and_baz(x,y,z) etc.

It would be too expensive to enumerate all these possibilities up-front.
Rather, I think you need to check whether a particular method name is
valid
or not. In which case, what you really want is to define a respond_to?
method in ActiveRecord::Base which has the same logic as 'find'.

class ActiveRecord::Base
  alias :respond_to :real_respond_to
  def respond_to?(m)
    return true if real_respond_to?(m)

    # now also return true if m is of the form find_xxxxxxxx and
    # xxxxxx is a valid finder pattern
  end
end

Regards,

Brian.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-30 15:59
(Received via mailing list)
On May 30, 2007, at 8:34 AM, Robert Dober wrote:

>> programmer to define a lot of dynamic methods.  This increases the
>> messages an object responds to.
>
> I have always felt that dynamic method creation and dynamic message
> interception are not quite the same beast. But I guess you have some
> thoughts behind your claim of which I fail to grasp the concept. Would
> you mind to elaborate?

I'm not really sure what else to say.  I read the documentation for
respond_to?():

$ ri -T Object#respond_to?
----------------------------------------------------- Object#respond_to?
      obj.respond_to?(symbol, include_private=false) => true or false
------------------------------------------------------------------------
      Returns +true+> if _obj_ responds to the given method. Private
      methods are included in the search only if the optional second
      parameter evaluates to +true+.

I know that ActiveRecord model classes will except find_by_*()
methods, so the fact that respond_to?() returns false for them makes
the above documentation lie.  That does not seem good to me and it's
certainly possible to fix it.  Thus, I can only reason that it is a
bug in ActiveRecord.

> Is this really a good idea?

Is it a good idea not to?  What exactly is the use case for
respond_to?()?  I have only ever used it to find out if something I
want is available.  If I can't do that reliably, it doesn't really
help me much.

James Edward Gray II
8749270955fc7c361eac3d6073a8ffcf?d=identicon&s=25 Maurice Gladwell (maurice-gladwell)
on 2007-05-30 16:00
James Gray wrote:
> On May 30, 2007, at 7:53 AM, dblack@wobblini.net wrote:
>
>> You could of course shoehorn find_by_* into respond_to? for AR
>> objects, if you don't mind, essentially, writing method_missing twice
>> (once for real, once as a kind of pseudo-static twin).
>
> I don't really understand this stance.  My opinion is that providing
> a method_missing() implementation is a convenient way for a
> programmer to define a lot of dynamic methods.  This increases the
> messages an object responds to.

I must agree with James Edward Gray here.

David's contrived example is of course possible, but highly unlikely in
practice; a programmer will generally not code his program into a
situation in which he can't be sure whether an object will respond to a
particular message sent to it. That's probably a major reason for having
Object#respond_to?.

In practice, and certainly in the Rails' find_by_* case, you have a
well-defined  range of messages to which an object will respond, known
already at development time. I don't know of a single real-life example
in which a programmer doesn't know at development time the entire range
of messages his objects might respond to. And Rails - with all its magic
- notwithstanding.

--
M.

(Of course, even if there would be an exception to that rule, in which
we really cannot delimit - for reasons unimaginable - the range of
messages to which the object will respond to at runtime - that rare and
probably bizarre case would not obviate the usefulness of the other
99.99% more common cases.)
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (Guest)
on 2007-05-30 16:09
(Received via mailing list)
On Wed, May 30, 2007 at 11:00:14PM +0900, Maurice Gladwell wrote:
> > messages an object responds to.
>
> I must agree with James Edward Gray here.
>
> David's contrived example is of course possible, but highly unlikely in
> practice; a programmer will generally not code his program into a
> situation in which he can't be sure whether an object will respond to a
> particular message sent to it. That's probably a major reason for having
> Object#respond_to?.

As an edge case, consider a DRb client proxy object. Should respond_to?
be
handled locally, or should it be proxied to the server? This involves an
expensive network round trip.

In many cases it may be cheaper to attempt the call and to rescue a
NoMethodError, than to have 'respond_to?' perform almost as much work as
the
call you're testing.

Regards,

Brian.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-30 16:14
(Received via mailing list)
On May 30, 2007, at 9:08 AM, Brian Candler wrote:

>>> a method_missing() implementation is a convenient way for a
>> particular message sent to it. That's probably a major reason for
> NoMethodError, than to have 'respond_to?' perform almost as much
> work as the
> call you're testing.

I agree with everything you just said and it still doesn't convince
me respond_to?() should lie.  ;)  Whether or not we use respond_to?()
in a given situation seems like an entirely different issue to me.

James Edward Gray II
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-30 16:38
(Received via mailing list)
Hi --

On Wed, 30 May 2007, Maurice Gladwell wrote:

>> messages an object responds to.
>
> I must agree with James Edward Gray here.
>
> David's contrived example is of course possible, but highly unlikely in
> practice; a programmer will generally not code his program into a
> situation in which he can't be sure whether an object will respond to a
> particular message sent to it. That's probably a major reason for having
> Object#respond_to?.

But it can happen; hence NoMethodError.

> In practice, and certainly in the Rails' find_by_* case, you have a
> well-defined  range of messages to which an object will respond, known
> already at development time. I don't know of a single real-life example
> in which a programmer doesn't know at development time the entire range
> of messages his objects might respond to. And Rails - with all its magic
> - notwithstanding.

If it's absolutely known what messages every object will respond to,
then we don't need #respond_to? :-)  I don't know... it's obviously
just a slightly different way of looking at it.  I'm uneasy with
having to rewrite respond_to? every time I implement method_missing;
it seems like a lot of work and an awfully tight coupling.


David
8749270955fc7c361eac3d6073a8ffcf?d=identicon&s=25 Maurice Gladwell (maurice-gladwell)
on 2007-05-30 16:40
Brian Candler wrote:
> In many cases it may be cheaper to attempt the call and to rescue a
> NoMethodError, than to have 'respond_to?' perform almost as much work as
> the
> call you're testing.

That's certinly true, but the rescue technique you describe is not a
substitute for a working #respond_to?. You're actually sending the
message, not asking the object whether it will respond to it.

These are two completely different operations. The only relevant
solution here would be if you aspired to emulate Object#respond_to? by
checking if the call raises NoMethodError, but that's infeasible because
method call commonly have side effects and/or are destructive.

--
M.
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (Guest)
on 2007-05-30 16:47
(Received via mailing list)
On Wed, May 30, 2007 at 11:40:57PM +0900, Maurice Gladwell wrote:
> These are two completely different operations. The only relevant
> solution here would be if you aspired to emulate Object#respond_to? by
> checking if the call raises NoMethodError, but that's infeasible because
> method call commonly have side effects and/or are destructive.

I'm saying that if you're doing

    object.foo if object.respond_to? :foo

then you may as well do

    object.foo rescue nil

(or a more specific rescue for NoMethodError)

I guess there are other uses for respond_to?, but I very rarely use it -
especially with ActiveRecord, which was the example given. Why do you
want
to check that an ActiveRecord class responds usefully to
find_by_foo_and_bar, but not actually call find_by_foo_and_bar?

Regards,

Brian.
B33ea5c12d767bfd1253940a960274f5?d=identicon&s=25 Tim Hunter (timhunter)
on 2007-05-30 16:53
James Gray wrote:
>
> I don't really understand this stance.  My opinion is that providing
> a method_missing() implementation is a convenient way for a
> programmer to define a lot of dynamic methods.  This increases the
> messages an object responds to.
>
> Following from that logic, I believe you should also override
> respond_to?() to reflect those new messages.  It's my opinion
> therefore that this thread has exposed a bug in Rails that should be
> patched.
>

FWIW, there's an entry about this in the Ruby Style Guide on
rubygarden.org:
http://wiki.rubygarden.org/Ruby/page/show/RubyStyl...
8749270955fc7c361eac3d6073a8ffcf?d=identicon&s=25 Maurice Gladwell (maurice-gladwell)
on 2007-05-30 16:57
David wrote:
> If it's absolutely known what messages every object will respond to,
> then we don't need #respond_to? :-)

#respond_to? is usually used when we don't know exactly which object is
referenced by a particular name, and especially what it can do ("duck
typing"). So we check if `foo.respond_to? :to_s` to see if we can tell
it to convert itself to a String.

But if we do know that foo is, say, an Array, we should - as the system
programmers - know which messages it will respond_to and how. It's
generally never the case that we know which object we have, yet are not
sure which messages it will respond to.

> I don't know... it's obviously
> just a slightly different way of looking at it.  I'm uneasy with
> having to rewrite respond_to? every time I implement method_missing;
> it seems like a lot of work and an awfully tight coupling.

Yes, that is true. Everyone would be happy (some much happier, others a
tiny bit happier :-) if we had a really working #respond_to? that would
cover all cases. But implementing such a thing elegantly seems
non-trivial.

It would be interesting to see an implementation of James Edward Gray's
suggestion above. ("You use an Extract Method refactoring to pull out
the matching logic into a separate private method and use that in
both implementations.")

--
M.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-30 17:02
(Received via mailing list)
Hi --

On Wed, 30 May 2007, Tim Hunter wrote:

>> patched.
>>
>
> FWIW, there's an entry about this in the Ruby Style Guide on
> rubygarden.org:
> http://wiki.rubygarden.org/Ruby/page/show/RubyStyl...

Hmmm... perhaps there needs to be a second entry explaining why it's
better not to put oneself in the position of having to maintain two
almost identical methods in parallel instead of one :-)


David
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-30 17:14
(Received via mailing list)
Hi --

On Wed, 30 May 2007, Maurice Gladwell wrote:

> David wrote:
>> If it's absolutely known what messages every object will respond to,
>> then we don't need #respond_to? :-)
>
> #respond_to? is usually used when we don't know exactly which object is
> referenced by a particular name, and especially what it can do ("duck
> typing"). So we check if `foo.respond_to? :to_s` to see if we can tell
> it to convert itself to a String.

#respond_to? != duck typing, though.  At least "hard" duck typing is
just:

   foo.to_s

> But if we do know that foo is, say, an Array, we should - as the system
> programmers - know which messages it will respond_to and how. It's
> generally never the case that we know which object we have, yet are not
> sure which messages it will respond to.

Well... there you get into the issue of class vs. type.  If you have a
spare six months, you can read the archives of this list on that topic
:-)  But certainly in ActiveRecord you get objects (association
collections) that will tell you that they are Arrays but which have
many methods beyond the vanilla Array.new object.

While you're right that my rand(2) example is contrived, I'm not ready
to say that it's so clear that method_missing can never be used to
handle cases that we couldn't anticipate and enumerate.  That seems
like a kind of retro-constraint, just so that it will interoperate
with respond_to?.

>> I don't know... it's obviously
>> just a slightly different way of looking at it.  I'm uneasy with
>> having to rewrite respond_to? every time I implement method_missing;
>> it seems like a lot of work and an awfully tight coupling.
>
> Yes, that is true. Everyone would be happy (some much happier, others a
> tiny bit happier :-) if we had a really working #respond_to? that would
> cover all cases. But implementing such a thing elegantly seems
> non-trivial.

I consider #respond_to? to be working, but I know what you mean :-)


David
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-30 17:32
(Received via mailing list)
On May 30, 2007, at 9:57 AM, Maurice Gladwell wrote:

> It would be interesting to see an implementation of James Edward
> Gray's
> suggestion above. ("You use an Extract Method refactoring to pull out
> the matching logic into a separate private method and use that in
> both implementations.")

#!/usr/bin/env ruby -wKU

class Test
   def initialize(*fields)
     @fields = fields.map { |f| f.to_s }
   end

   def find(*args)
     "Performing query with args:\n#{args.inspect}"
   end

   def method_missing(meth, *args, &block)
     if find_args = dynamic_finder?(meth)
       find( find_args.first,
             :conditions => find_args[1..-1].zip(args).
                                             map { |n, v| "#{n} = '#
{v}'"}.
                                             join(" AND ") )
     else
       super
     end
   end

   def respond_to?(*args)
     super || dynamic_finder?(args.first)
   end

   private

   def dynamic_finder?(method_call)
     if method_call.to_s =~ /\Afind(_all)?_by_(\w+)\Z/
       args =  [$1 ? :all : :first]
       args += $2.split("_and_")
       args if args[1..-1].all? { |f| @fields.include? f }
     end
   end
end

if __FILE__ == $PROGRAM_NAME
   model = Test.new(:name, :age, :height, :weight)

   p !!model.respond_to?(:find_by_name_and_height)
   p !!model.respond_to?(:find_all_by_age)
   p !!model.respond_to?(:find_all_by_race)

   puts

   puts model.find_by_name_and_height("James", "61 in.")
   puts model.find_all_by_name_and_height
end

James Edward Gray II
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 22:32
(Received via mailing list)
On 5/30/07, James Edward Gray II <james@grayproductions.net> wrote:
> class Test
>        find( find_args.first,
>      super || dynamic_finder?(args.first)
>    end
>
>    puts model.find_by_name_and_height("James", "61 in.")
>    puts model.find_all_by_name_and_height
> end
>
> James Edward Gray II
>
>
>

This is very interesting, I just imagine that dynamic_finder does not
give consistent results depending on events outside the Ruby
program(*). Are you still happy with the semantics, instead of
respond_to? giving false negatives it gives false positives now.
A second issue was brought up by David,( I have no idea why he put a
smiley ;)
You have created a dependency between method_missing and respond_to? I
really feel bad about this.

Robert

(*) or maybe by threading
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 22:33
(Received via mailing list)
On 5/30/07, James Edward Gray II <james@grayproductions.net> wrote:
> >> I don't really understand this stance.  My opinion is that providing
> respond_to?():
> methods, so the fact that respond_to?() returns false for them makes
> the above documentation lie.
James the documentation is not correct anyway, look at the wording,
nothing ever can reply to methods, only to messages. I liked a lot
what David has said about this.  >That does not seem good to me and
it's
> certainly possible to fix it.  Thus, I can only reason that it is a
> bug in ActiveRecord.
That is kind of a thing I have not considered in my reply, I
misunderstood that you were dreaming about a magical
Object#respond_to? which would interpret the semantics of
#method_missing generally, hence my surprise.
>
> > Is this really a good idea?
>
> Is it a good idea not to?  What exactly is the use case for
> respond_to?()?  I have only ever used it to find out if something I
> want is available.  If I can't do that reliably, it doesn't really
> help me much.
Hmm sure but I feel its need more in MetaProgramming, if you want to
fix ActiveRecord I cannot argue with you at all I do not know that
stuff, so I just bail out of the discussion.

However if you would like to spend some time in philosophy about
respond_to? I see a clearcut dilemma between the ideal behavior of
respond_to? and method_missing. See my example above but it is easy to
imagine that #method_missing is dispatching depending on an external
datasource.
How would you want #respond_to? to handle this?

I just feel that for practical reasons #respond_to? does a good job
already. This might
Robert
A131b672fdbd2a58dce12031ad78b121?d=identicon&s=25 Wolfgang Nádasi-Donner (wonado)
on 2007-05-30 23:05
(Received via mailing list)
James Edward Gray II schrieb:
> What exactly is the use case for respond_to?()?

Only as a remark for a special usage, which is not easy (impossible?)
without
"respond_to?()".

I have some Libraries for textual analysis, which are usually used via
"irb".
The application works on large Arrays of String objects. Based on
regular
expressions I define sometimes methods for some of these object, during
one
textual analysis often several methods.

Then I can categorize the String objects in the Array by using
"respond_to?()".

It is very easy and helpful (may be it sounds complex an strange, but
this is
only my bad English).

Wolfgang Nádasi-Donner
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-30 23:09
(Received via mailing list)
On May 30, 2007, at 3:31 PM, Robert Dober wrote:

> This is very interesting, I just imagine that dynamic_finder does not
> give consistent results depending on events outside the Ruby
> program(*). Are you still happy with the semantics, instead of
> respond_to? giving false negatives it gives false positives now.

Well, if it can't be made accurate, that's a different thing.  First,
we would probably need to document that it can't be trusted in such a
case.

> You have created a dependency between method_missing and respond_to? I
> really feel bad about this.

I guess that means that I made it so that respond_to?() needs to be
updated if method_missing() is?  Yes, I guess that's right.

David says that's bad.  OK.  I thought respond_to?() lying to me was
bad.  So I guess we just chose to care about different things.

I guess each person needs to decide what is more important to them.

James Edward Gray II
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 23:22
(Received via mailing list)
On 5/30/07, James Edward Gray II <james@grayproductions.net> wrote:
>
> > You have created a dependency between method_missing and respond_to? I
> > really feel bad about this.
>
> I guess that means that I made it so that respond_to?() needs to be
> updated if method_missing() is?  Yes, I guess that's right.
>
> David says that's bad.  OK.
And so do I, well that sounds quite prepotent, I know.
>I thought respond_to?() lying to me was
> bad.  So I guess we just chose to care about different things.
>
> I guess each person needs to decide what is more important to them.
Well I was hoping to convince you, sure I was, but I see now that
after having discussed things we just have different opinions and that
is that of course.

The most important point I wanted to make - and I probably failed - is
that I am not sure if it really lies for me, but this is a tricky
issue and I can understand what you dislike about it.

Cheers
Robert
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-30 23:26
(Received via mailing list)
On 5/30/07, Wolfgang Nádasi-Donner <wonado@donnerweb.de> wrote:
>
> Then I can categorize the String objects in the Array by using "respond_to?()".
>
> It is very easy and helpful (may be it sounds complex an strange, but this is
> only my bad English).
Hmm as fellow native German Speaker I think your English is perfect.
Could you give an example?
I somehow feel that you might use a different approach than
hitchhiking methods, or are the used for different purposes too.

Sounds interesting.

Cheers
Robert
A131b672fdbd2a58dce12031ad78b121?d=identicon&s=25 Wolfgang Nádasi-Donner (wonado)
on 2007-05-31 14:56
(Received via mailing list)
Robert Dober schrieb:
> Sounds interesting.

I don't know, because it is a special situatuation, and it is very
experimental.
During usage i build something like a hybride human-software process. At
start
some helper libraries are required in "irb", and then I worked with
several data
in different buffers, writing helpful code for analysis and changes and
throw
the code away after the work is done (usually there is no future use for
the
code). If one wants to use this in a "real program" s/he must find out
how to
generate (=create) useful Ruby code based on some events - I mean code,
that is
not predictable when the program starts.

Robert Dober schrieb:
> Could you give an example?

This is difficult, because there is no fixed code, but I can decribe a
typical
process.

Someone comes to me with a CD (or ZIP file via mail) with several
textual files,
and says "...something is wrong there..", or "...can you help me by
producing a
short overview...". Especially in the first situation I have nearly no
addition
information. So I load one File into a line oriented buffer structure
(based on
an Array of Strings) an start analysing the data by using helper methods
and
regular expressions.

Sometimes (=often) the files have explicit relationships via textual
remarks.
This is one case, where the usage of singleton methods for lines
(=String
objects in an Array) comes up, because it is simple and easy to use. It
follows
usually the same pattern:

buffer.each do |line|
   if (md = line.match(/a pattern that is of some interest/)
     # define a special method for the line
   end
end

The definition will take place on the assumption, that the method may be
useful
later on, which is not clear in the moment. It is possible, that the
method
opens a new buffer, loads another file and does some action on it.

This can happen several times. Later it is possible that I want, that a
buffer
applyies such a method for each line the method is defined. I can use
the
following short pattern for this:

buffer.each{|line|line.my_method if line.respond_to?(:my_method)}

Remarks:

1) Performance isn't a interesting thing in this situation. When I think
about
an output and plan what to do next, I am the bottle-neck in the system.

2) This kind of using singleton methods is attractive, because it isn't
complicated and simple to use (=not much to write), what is very
interesting in
an interactive session.

3) Readability of the code isn't relevant, because it will be thrown
away after
usage. This can be done, because the problems differ very much. Reusable
things
will be build in the libraries, that I require in the very beginning.

4) Readability isn't a big problem, because I wrote some large TECO
programs
long time ago... ;-)

I Think this is a very special usage of Ruby.

Wolfgang Nádasi-Donner
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-31 15:15
(Received via mailing list)
On 5/31/07, Wolfgang Nádasi-Donner <wonado@donnerweb.de> wrote:
> Robert Dober schrieb:
> > Sounds interesting.
>
> I don't know, because it is a special situatuation, and it is very experimental.
<snip>
Well it still sounds very interesting to me, I remember when I was
writing Emacs Macros for jumping between events in very very long log
files. If I guess correctly what you are doing here is very intersting
and quite complicated.
But to come back to respond_to?
Am I guessing correctly that you use respond_to? in order to manage
the abilities you have already created for your singletons, as these
abilities are methods?

Cheers
Robert
A131b672fdbd2a58dce12031ad78b121?d=identicon&s=25 Wolfgang Nádasi-Donner (wonado)
on 2007-05-31 19:11
(Received via mailing list)
Robert Dober schrieb:
> Am I guessing correctly that you use respond_to? in order to manage
> the abilities you have already created for your singletons, as these
> abilities are methods?

Yes, these methods are something like "executable attributes" - but - I
would
prefer in the moment to say: "don't use it in a real program!".

The usage background is as already named:
1) Execution speed does not matter (even one minute is not a problem),
2) readability does not matter (there are no comments at all),
3) size of code to write does matter (less is better).

I will not recommend to write software (=real programs with a life
cycle) based
on this principles.

Wolfgang Nádasi-Donner
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-06-09 13:10
(Received via mailing list)
Hi --

On Thu, 31 May 2007, James Edward Gray II wrote:

>> You have created a dependency between method_missing and respond_to? I
>> really feel bad about this.
>
> I guess that means that I made it so that respond_to?() needs to be updated
> if method_missing() is?  Yes, I guess that's right.
>
> David says that's bad.  OK.  I thought respond_to?() lying to me was bad.  So
> I guess we just chose to care about different things.

I just raise an eyebrow at that much repeated/parallel code.

> I guess each person needs to decide what is more important to them.

I think it's just a matter of how you define respond_to? conceptually
-- as a handle on the methods in the object's method lookup path, or
as a registry of everything the object can do without raising an
error.  It's interesting in this connection that delegation adds the
delegated methods to the respond_to? roster.  I guess that summarizes
the difference for me: a method that's delegated is known to be taken
care of, whereas a method that's missing is missing (even if the
potential error can be averted).


David
This topic is locked and can not be replied to.