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