【问题标题】:Ruby - actually get ALL methods for an instanceRuby - 实际上获取实例的所有方法
【发布时间】:2020-02-10 23:56:03
【问题描述】:

在这个问题中:

How to list all methods for an object in Ruby?

您可以调用foo.methods 并获取所有方法。但这并没有得到所有的方法。 Rails 中的示例,带有 ActiveStorage:

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>

鉴于正在引发 ArgumentError,它 respond_to?s,我可以获取该方法,它确实具有变体方法。但它没有与.methods 一起显示。如何查看完整的方法列表?

【问题讨论】:

  • “鉴于 [....] 它确实有变体方法” – 你的结论是错误的。消息和方法密切相关,但通常彼此独立。对象可以响应消息而无需实现具有相同名称的方法。一个对象也可以实现某种方法而不响应相应的消息。
  • 这能回答你的问题吗? How to list all methods for an object in Ruby?

标签: ruby


【解决方案1】:

也许您错过了链接帖子How to list all methods for an object in Ruby?的接受答案中的最后一段:

添加请注意 :has_many 不直接添加方法。相反,ActiveRecord 机器使用 Ruby method_missing 和 responds_to 技术来动态处理方法调用。因此,methods方法结果中没有列出方法。

为了更清楚地说明发生了什么代码示例:

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

方法unknown_method 从未定义,但有一种方法可以处理未知方法。所以这个类给人的印象是一个现有的方法,但是没有。

也许How can I get source code of a method dynamically and also which file is this method locate in 有助于获取有关内容的信息:

Foo.instance_method(:method_missing).source_location

加法

当您定义自己的method_missing 时,您还应该将respond_to? 的行为更改为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

详情请参阅`respond_to?` vs. `respond_to_missing?`

【讨论】:

  • 值得一提的是,如果你通过method_missing暴露虚假方法,你应该镜像respond_to_missing?中的变化
  • 而不是提高自己的NoMethodError,你应该打电话给super
  • @Stefan:感谢您的提示。我调整了我的答案
  • @SergioTulentsev 我扩展了我的答案。感谢您的提示。
  • 好答案。不需要“加法”。就像您在回复根据文章或书籍草稿制作的 cmets 一样进行编辑。
猜你喜欢
  • 2015-02-24
  • 2011-01-06
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 2012-12-25
  • 2013-01-13
  • 2020-02-10
  • 1970-01-01
相关资源
最近更新 更多