Любой способ определить, какой объект вызвал метод? - PullRequest
19 голосов
/ 24 апреля 2010

Я надеюсь, что инфраструктура передачи сообщений в Ruby означает, что для этого может быть какой-то умный прием.

Как определить вызывающий объект - какой объект вызвал метод, в котором я сейчас нахожусь?

Ответы [ 5 ]

13 голосов
/ 24 апреля 2010

Вы можете легко посмотреть на строку кода, которая вызвала интересующую функцию через

caller.first

, который сообщит вам имя файла и номер строки, вызвавшей соответствующую функцию. Затем вы можете вычислить, какой это был объект.

Однако, похоже, что вы больше похожи на какой-то объект, вызвавший определенную функцию, возможно, в методе экземпляра. Я не знаю метода для выяснения этого - но я бы не стал его использовать, так как он, похоже, сильно нарушает инкапсуляцию.

6 голосов
/ 07 ноября 2014

Как вариант, существует binding_of_caller gem , который позволяет вам выполнять код в контексте любого вызывающего абонента в стеке вызовов (вызывающего абонента, вызывающего абонента и т. Д.). Это полезно для проверки (читай делать что-либо в любой позиции в стеке вызовов ) стека вызовов в разработке, как используется в better_errors.

Объекты класса Binding инкапсулируют контекст выполнения в каком-то конкретном месте в коде и сохраняют этот контекст для будущего использования.

& Ndash; http://www.ruby -doc.org / ядро-2.1.4 / Binding.html

Стоит упомянуть, эта техника должна использоваться только для отладки, для развлечения или в образовательных целях , потому что она очень сильно нарушает принципы ООП.
В основном из-за eval.

Давайте подготовим материал:

require 'binding_of_caller' # I assume, you installed this gem already?

Получить немедленный (ближайший по стеку, следовательно, 0) экземпляр вызывающего абонента:

binding.of_caller(0).eval('self')

... или даже метод непосредственного вызова:

binding.of_caller(0).eval('__method__')

Если вам нужно подняться выше стека вызовов, используйте номера, отличные от 0, для получения привязки звонящего.

Ужасно хаки. Но если вам это действительно нужно, & mdash; вот, пожалуйста.

2 голосов
/ 24 апреля 2010

Технология во всей красе:

 1  # phone.rb
 2  class Phone
 3    def caller_id
 4      caller
 5    end
 6  end
 7  
 8  class RecklessDriver
 9    def initialize
10      @phone = Phone.new
11    end
12    def dial
13      @phone.caller_id
14    end
15  end
16  
17  p = Phone.new
18  p.caller_id.inspect   # => ["phone.rb:18:in `<main>'"]
19  
20  macek = RecklessDriver.new
22  macek.dial.inspect    # => ["phone.rb:13:in `dial'", "phone.rb:22:in `<main>'"]

Примечание: Номер строки в демонстрационных целях. phone.rb:X относится к строке X скрипта.

Посмотрите на phone.rb:13! Этот dial метод - то, что послало вызов! И phone.rb:22 относится к безрассудному драйверу, который использовал метод dial!

1 голос
/ 21 октября 2016

Peter's answer используемый в примере производственного кода

В моей компании мы осуждали флаг deleted во вкусе колонки Paranoia gem deleted_at. Приведенный ниже код показывает, как мы следили за тем, чтобы все прошло хорошо, прежде чем мы удалим столбец (при развертывании этого кода, а затем через 2 или 3 дня после запуска мы развернем миграцию remoove_column :lessons, :deleted

class Lesson < ActiveRecord::Base

  def deleted
    if caller.select { |c| c.match /serialization\.rb/ }.any?
      # this is Rails object mapping
      !!deleted_at
    else
      raise 'deplicated - deleted was replaced by  deleted_at'
    end
  end
end
1 голос
/ 24 апреля 2010

Вы имеете в виду, как self?

irb> class Object
  ..   def test
  ..     self
  ..   end
  .. end
  => nil
irb> o = Object.new
  => #<Object:0xb76c5b6c>
irb> o.test
  => #<Object:0xb76c5b6c>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...