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
#-----------------------

--
Posted via http://www.ruby-forum.com/.

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 `<main>'

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]

···

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

Can anyone explain `#respond_to_missing?`.

--
All the best, Sandor Szücs

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.

···

--
Posted via http://www.ruby-forum.com/.

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

  https://bugs.ruby-lang.org/issues/5759

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

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 Saturday, January 5, 2013 4:00:02 PM UTC-5, Jan E. wrote:

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.

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 `<main>'

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 `<main>'
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.

···

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.

--
All the best, Sandor Szücs