Ruby - фактически получить ВСЕ методы для экземпляра - PullRequest
6 голосов
/ 14 октября 2019

В этом вопросе:

Как перечислить все методы для объекта в 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. Как я могу увидеть полный список методов?

1 Ответ

8 голосов
/ 14 октября 2019

Может быть, вы пропустили последний абзац в принятом ответе связанного поста Как перечислить все методы для объекта в Ruby? :

Добавлено Обратите внимание: has_many не добавляет методы напрямую. Вместо этого механизм ActiveRecord использует методы Ruby method_missing и responseds_to для обработки вызовов методов на лету. В результате методы не перечислены в результате метода method.

Чтобы было яснее, что происходит, пример кода:

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 никогда не бываетопределено, но есть метод для обработки неизвестных методов. Таким образом, класс создает впечатление существующего метода, но его нет.

Может быть Как я могу получить исходный код метода динамически, а также, какой файл находится в этом методе в , помогаетполучить информацию о содержимом:

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

См. Также `response_to?` Против `response_to_missing?` для подробностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...