Ruby-实际上获取实例的所有方法

xxj*_*jnn 6 ruby

在这个问题上:

如何在Ruby中列出对象的所有方法?

您可以调用foo.methods并获取所有方法。但这并不能获得所有方法。使用ActiveStorage的Rails中的示例:

Image.first.specimens.first.methods.include?(:variant)
# => false
Image.first.specimens.first.respond_to?(:variant)
# => true
Image.first.specimens.first.variant
Traceback (most recent call last):
        1: from (irb):3
ArgumentError (wrong number of arguments (given 0, expected 1))
Image.first.specimens.first.method(:variant)
# => #<Method: ActiveStorage::Attachment(id: integer, name: string, record_type: string, record_id: integer, blob_id: integer, created_at: datetime)#variant>
Run Code Online (Sandbox Code Playgroud)

鉴于正在引发ArgumentError,因此respond_to?可以抓取该方法,它确实具有variant方法。但是没有显示.methods。如何查看方法的完整列表?

knu*_*nut 8

也许您错过了链接文章公认答案中的最后一段。如何在Ruby中列出对象的所有方法?

补充说明::has_many不会直接添加方法。相反,ActiveRecord机制使用Ruby method_missing和responses_to技术来即时处理方法调用。结果,这些方法未在方法方法结果中列出。

为了使代码示例更加清楚:

class Foo
  def hello
    puts 'Hello'
  end

  def method_missing(name, *args, &block)
    case name
      when :unknown_method
        puts "handle unknown method %s" % name # name is a symbol
      else
        super #raises NoMethodError unless there is something else defined
    end
  end
end

foo = Foo.new
p foo.respond_to?(:hello) #-> true
p foo.respond_to?(:unknown_method) #-> false
foo.unknown_method  #-> 'handle unknown method unknown_method'
foo.another_unknown_method  #-> Exception
Run Code Online (Sandbox Code Playgroud)

该方法unknown_method从未定义过,但是有一种方法可以处理未知方法。因此,该类给人的印象是现有方法,但是没有。

也许如何动态获取方法的源代码,以及该方法位于哪个文件中有助于获取有关内容的信息:

Foo.instance_method(:method_missing).source_location
Run Code Online (Sandbox Code Playgroud)

加成

当定义自己的时method_missing,还应该更改respond_to?with 的行为。respond_to_missing?

  def respond_to_missing?(method, *)
    return method == :unknown_method || super
    #or if you have a list of methods:
    #~ return %i{unknown_method}.include?(method) || super
    #or with a regex for 
    #~ method =~ /another_(\w+)/ || super
  end
end
Run Code Online (Sandbox Code Playgroud)

有关详细信息,另请参见`respond_to?`与`respond_to_missing?`

  • 值得一提的是,如果通过`method_missing`公开伪造方法,则应反映`respond_to_missing?`中的更改。 (2认同)
  • 您应该只调用“super”,而不是引发自己的“NoMethodError”。 (2认同)