Respond_to_missing?

Can anyone explain #respond_to_missing?.

Hi,

“respond_to_missing?” makes “respond_to?” fit for dynamic methods
defined by “method_missing”.

Normally, an object wouldn’t know if it can respond to a dynamic method
call:

#-----------------------
class A
def method_missing name, *args
if name == :say_hi
puts ‘Hi there!’
else
raise NoMethodError
end
end
end

a = A.new
a.say_hi # “Hi there!”
puts a.respond_to? :say_hi # => false
#-----------------------

But if you define “respond_to_missing?”, you can work around this
problem:

#-----------------------
class A
def method_missing name, *args
if name == :say_hi
puts ‘Hi there!’
else
raise NoMethodError
end
end
def respond_to_missing? name, include_private
name == :say_hi
end
end

a = A.new
a.say_hi # “Hi there!”
puts a.respond_to? :say_hi # => true
#-----------------------

On 1/4/13 3:14 AM, Intransition wrote:

Can anyone explain #respond_to_missing?.

The answer can be found at [1].

irb:0> class Bar
irb:1> def method_missing name, args
irb:2> p args
irb:2> end
irb:1>
irb:1
def respond_to? name, include_private = false
irb:2> true
irb:2> end
irb:1> end
=> nil
irb:0> Bar.new.respond_to? :does_not_exist
=> true
irb:0> Bar.new.method :does_not_exist
NameError: undefined method does_not_exist' for class Bar’
from (irb):112:in method' from (irb):112 from /Users/sz/.rvm/rubies/ruby-1.9.3-p362/bin/irb:16:in

irb:0> class Foo
irb:1> def respond_to? args; super; end
irb:1>
irb:1
def respond_to_missing? *args
irb:2> true
irb:2> end
irb:1> end
=> nil
irb:0> Foo.new.respond_to? :does_not_exist
=> true
irb:0> Foo.new.method :does_not_exist
=> #<Method: Foo#does_not_exist>

[1]

Thank you Jan and Sandor. That is basically what I thought, but I had
recently become confused b/c of this:

Bug #5759: flatten calls to_ary on everything - Ruby master - Ruby Issue Tracking System

If you read toward the bottom of this thread, there is a case that seems
contradictory. I still don’t get it.

How is that contradictory? Are you sure you got the return values of
respond_to_missing? right? Because I guess you want to return true for
:to_ary?

respond_to? first checks if the method is actually, physically there. If
that’s not the case, it checks for respond_to_missing?

In your case both checks return “false”, so you end up with “false” just
like you should.

On Saturday, January 5, 2013 4:00:02 PM UTC-5, Jan E. wrote:

Yes, that is what it should do. But notice #flatten doesn’t seem to
notice
that it returns false. It still calls #to_ary on it,

class Baz
  def method_missing(s); s; end

  def respond_to_missing?(s, x)
    return false if s == :to_ary
    true
  end
end


[Baz.new].flatten
=> in `flatten': can't convert Baz to Array (Baz#to_ary gives 

Symbol) (TypeError)

Even though it appears to work fine if one overrides #respond_to?
directly.

class Baz

  def method_missing(s); s; end

  def respond_to?(s, x)
    super unless s == :to_ary
  end
end

[Baz.new].flatten => [#<Baz:0x007f8d3115c7d0>]

On 1/5/13 12:42 PM, Intransition wrote:

Thank you Jan and Sandor. That is basically what I thought, but I had
recently become confused b/c of this:

Bug #5759: flatten calls to_ary on everything - Ruby master - Ruby Issue Tracking System

If you read toward the bottom of this thread, there is a case that seems
contradictory. I still don’t get it.

The difference of respond_to? and respond_to_missing? is that you can
get a Method object using Kernel#method(sym) if a method will be
dynamically implemented using method_missing.

Here again the example:
13 class Bar1
14 def respond_to_missing? *args
15 true
16 end
17 def method_missing(*args, &blk)
18 p args
19 end
20 end
21
22 class Baz1
23 def respond_to? *args
24 true
25 end
26
27 def method_missing(*args, &blk)
28 p args
29 end
30 end

get the method:

irb:0> Bar1.new.method :foo
=> #<Method: Bar1#foo>

do not get the method:

irb:0> Baz1.new.method :foo
NameError: undefined method foo' for class Baz1’
from (irb):17:in method' from (irb):17 from /.../.rvm/rubies/ruby-1.9.3-p362/bin/irb:16:in

In your example you define: “#to_ary() is not created dynamically nor
defined static”

class TransBaz1
def method_missing(s)
s
end

def respond_to_missing?(s, x)
return false if s == :to_ary
true
end
end

irb:0> TransBaz1.new.method :to_ary
NameError: undefined method to_ary' for class TransBaz1’
from (irb):45:in method' from (irb):45 from /.../.rvm/rubies/ruby-1.9.3-p362/bin/irb:16:in
irb:0> TransBaz1.new.method :foo
=> #<Method: TransBaz1#foo>

You can not get Method object :to_ary using Kernel#method, but you can
get :foo.