Как найти source_location кода, выполняемого супер? - программирование
Подтвердить что ты не робот

Как найти source_location кода, выполняемого супер?

class C1
  def pr
    puts 'C1'
  end
end

class C2 < C1
  def pr
    puts 'C2'
    super
    puts self.method(:pr).source_location
  end
end

c = C2.new
c.pr

В вышеприведенной программе можно получить местоположение кода, выполняемого super (C1::pr в нашем случае), а также получить расположение кода C2::pr с помощью метода source_location?

4b9b3361

Ответ 1

Из ruby ​​2.2 вы можете использовать super_method следующим образом:

Class A
  def pr
    puts "pr"
  end
end

Class B < A
  def pr
    puts "Super method: #{method(:pr).super_method}"
  end
end

Поскольку super_method возвращает метод, вы можете связать их, чтобы найти предка:

def ancestor(m)
  m = method(m) if m.is_a? Symbol
  super_m = m.super_method
  if super_m.nil?
    return m
  else
    return ancestor super_m
  end
end

Ответ 2

Вам просто нужно добраться до суперкласса, а затем использовать instance_method, чтобы получить метод из суперкласса.

class C2 < C1
  def pr
    puts "C2"
    super
    puts "Child: #{self.method(:pr).source_location}"
    puts "Parent: #{self.class.superclass.instance_method(:pr).source_location}"
  end
end

РЕДАКТИРОВАТЬ - принимая во внимание комментарий о проверке цепи родословной, он (на удивление) кажется ненужным.

class C1
  def pr
    puts "C1"
  end
end

class C2 < C1; end

class C3 < C2
  def pr
    puts "C3"
    super
    puts "Child source location: #{self.method(:pr).source_location}"
    puts "Parent source location: #{self.class.superclass.instance_method(:pr).source_location}"
  end
end

c = C3.new
c.pr

печатает

C3
C1
Child source location: ["source_location.rb", 10]
Parent source location: ["source_location.rb", 2]

Ответ 3

Если вы используете pry, вы можете использовать флаг -s, чтобы показать супер метод. Документация об этой функции здесь.

show-source Class#method -s

Ответ 4

Чтобы увидеть всю предков метода...

Определите это в сеансе irb:

class Object
  def method_ancestry(method_name)
    method_ancestors = []
    method = method(method_name)
    while method
      method_ancestors << [method.owner, method.source_location]
      method = method.super_method
    end
    method_ancestors
  end
end

Например, в консоли Rails я могу сделать:

# assuming User is an ActiveRecord class
User.new.method_ancestry(:save)

=> [[ActiveRecord::Suppressor,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/suppressor.rb", 40]],
 [ActiveRecord::Transactions,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/transactions.rb", 317]],
 [ActiveRecord::AttributeMethods::Dirty,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/attribute_methods/dirty.rb",
   21]],
 [ActiveRecord::Validations,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/validations.rb", 43]],
 [ActiveRecord::Persistence,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/persistence.rb", 124]]]

В этом списке не указано, действительно ли какое-либо из приведенных определений методов вызывает super или просто переопределяет их унаследованное определение. Но если вы видите super в одном из них, он переходит к следующему в списке.

Если вы используете это много, вы можете поместить его в свои ~/.irbrc или ~/.pryrc.