为什么Object.instance_methods(false)不能在Ruby中返回预期的方法?

 2021-04-27 

Why doesn't Object.instance_methods(false) return expected methods in Ruby?

执行Object.instance_methods(true)时,我会获得http://ruby-doc.org/core-2.5.0/Object.html上列出的所有实例方法(以及在BasicObject中定义的大多数实例方法;我将我不太确定为什么我没有得到BasicObject的所有实例方法,但这是另一个问题。但是,当我执行Object.instance_methods(false)时,我只会得到

1
[:__binding__, :pry, :to_yaml]

我希望它返回我之前获得的所有方法,减去BasicObject方法。我想念什么?


大多数方法不是在对象本身上定义的,而是在内核(包含在对象中的模块)上定义的。您可以看到以下内容:

Object.instance_methods(true).map(&method(:method)).map(&:owner)

=> [Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, #>, Kernel, Kernel, Kernel, #>, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, Kernel, BasicObject, BasicObject, BasicObject, BasicObject, BasicObject, BasicObject, BasicObject, BasicObject]

如果我打开一个新的irb窗口并运行

1
Object.instance_methods(true).select { |sym| method(sym).owner == Object }

我没有结果。但是,如果我要求"撬",那么我只会得到[:pry, :__binding__]


这是因为这些实例方法来自其他祖先。下面的第7行说明了Object(在我的Ruby运行时中)没有自己的实例方法:

1
2
3
4
5
6
7
8
9
10
11
12
2.5.0 :001 > Object.ancestors
 => [Object, Kernel, BasicObject]
2.5.0 :002 > Object.instance_methods(true)
 => [:instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_get, :public_methods, :instance_variables, :method, :public_method, :define_singleton_method, :singleton_method, :public_send, :extend, :pp, :to_enum, :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?, :freeze, :inspect, :object_id, :send, :to_s, :display, :nil?, :hash, :class, :clone, :singleton_class, :itself, :dup, :taint, :yield_self, :untaint, :tainted?, :untrusted?, :untrust, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :!, :equal?, :instance_eval, :instance_exec, :==, :!=, :__id__, :__send__]
2.5.0 :003 > o = Object.instance_methods(false)
 => []
2.5.0 :004 > k = Kernel.instance_methods(false)
 => [:instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_get, :public_methods, :instance_variables, :method, :public_method, :define_singleton_method, :singleton_method, :public_send, :extend, :pp, :to_enum, :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?, :freeze, :inspect, :object_id, :send, :to_s, :display, :nil?, :hash, :class, :clone, :singleton_class, :itself, :dup, :taint, :yield_self, :untaint, :tainted?, :untrusted?, :untrust, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods]
2.5.0 :005 > bo = BasicObject.instance_methods(false)
 => [:!, :equal?, :instance_eval, :instance_exec, :==, :!=, :__id__, :__send__]
2.5.0 :006 > Object.instance_methods(true) - (k + bo)
 => []