Как найти 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
?
Ответы
Ответ 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
.