Bug #11465
closed`Array#flatten` calls `to_ary` on objects with `method_missing` even if `respond_to_missing?(:to_ary)` returns `false`.
Description
I noticed this behavior while working on an issue reported on the Rails tracker: https://github.com/rails/rails/issues/21296
I put up a reproduction along with some details about the issue in a Gist: https://gist.github.com/senny/02ee933cc75e7ac8093f
The problem is that Array#flatten
calls to_ary
on objects with method_missing
even if respond_to_missing(:to_ary)
returns false.
class RespondToMissing
def respond_to_missing?(method, stuff)
return false if method == :to_ary
super
end
def method_missing(*args)
super
end
end
trace = TracePoint.new(:raise) do |tp|
p tp.raised_exception
puts tp.raised_exception.backtrace.join("\n")
puts
end
trace.enable
RespondToMissing.new.respond_to? :to_ary # => false
[RespondToMissing.new].flatten
# OUTPUT:
# false
# #<NoMethodError: undefined method `to_ary' for #<RespondToMissing:0x007fd57322ce78>>
# script.rb:10:in `method_missing'
# script.rb:38:in `flatten'
# script.rb:38:in `<main>'
If the objects with method_missing
also define their own respond_to?
it works as expected:
class RespondTo
def respond_to?(method)
super
end
def method_missing(*args)
super
end
end
trace = TracePoint.new(:raise) do |tp|
p tp.raised_exception
puts tp.raised_exception.backtrace.join("\n")
puts
end
trace.enable
p RespondTo.new.respond_to? :to_ary # => false
[RespondTo.new].flatten # no internal exceptions are raised
# OUTPUT:
# false
Expected Behavior¶
I expect respond_to_missing?
to be considered (same as respond_to?
) before Array#flatten
calls #to_ary
.
Workaround¶
As described above it's possible to work around this issue by also defining a respond_to?
method. Another workaround is to define to_ary
and return nil
.
Updated by nobu (Nobuyoshi Nakada) about 9 years ago
- Status changed from Open to Closed
Applied in changeset r51646.
vm_eval.c: share with rb_obj_respond_to
- vm_eval.c (check_funcall_respond_to): share the behavior with
rb_obj_respond_to. [ruby-core:70460] [Bug #11465] - vm_method.c (vm_respond_to): extract from rb_obj_respond_to and
merge r39881.