如何找到一个方法是定义在运行时?
-
05-07-2019 - |
题
我们最近有一个问题,即,经过一系列的承诺已经发生、后台进程失败的运行。现在,我们好一点的男孩和女孩跑了 rake test
之后每一个检查-但是,由于一些奇怪的在轨的图书馆加载,它只发生当我们跑了它直接从杂种生产模式。
我追踪的错误降,这是由于新的轨道宝石复盖的方法在String类中的一种方式,打破了一个狭窄的使用在运行轨道的代码。
无论如何,长话短说,是否有一种方法,在运行时,要问的红宝石在哪一种方法已界定?喜欢的东西 whereami( :foo )
返回 /path/to/some/file.rb line #45
?在这种情况下,告诉我,这是定义中的类串将是无益的,因为它超载的一些图书馆。
我不能保证源的生活在我的项目,因此grepping为 'def foo'
一定不会给我什么,我需要,更不要说如果我有 很多 def foo
's,有时候我不知道直到运行时,哪一个我可以使用。
解决方案
这是真的迟到了,但这里是你如何可以找到一个方法是定义:
# How to find out where a method comes from.
# Learned this from Dave Thomas while teaching Advanced Ruby Studio
# Makes the case for separating method definitions into
# modules, especially when enhancing built-in classes.
module Perpetrator
def crime
end
end
class Fixnum
include Perpetrator
end
p 2.method(:crime) # The "2" here is an instance of Fixnum.
#<Method: Fixnum(Perpetrator)#crime>
如果你在Ruby1.9,你可以使用 source_location
require 'csv'
p CSV.new('string').method(:flock)
# => #<Method: CSV#flock>
CSV.new('string').method(:flock).source_location
# => ["/path/to/ruby/1.9.2-p290/lib/ruby/1.9.1/forwardable.rb", 180]
注意,这不会的工作的一切,就像母编码。的 种类 有一些巧妙的职能,太像 方法#所有人 其回返的文件,其中的方法是限定的。
编辑:还看到的 __file__
和 __line__
和稀土元素,在其他的答案,他们是方便的。-wg
其他提示
实际上,你可以走远一点比的解决方案上。红宝1.8企业版,还有就是 __file__
和 __line__
方法上的 Method
实例:
require 'rubygems'
require 'activesupport'
m = 2.days.method(:ago)
# => #<Method: Fixnum(ActiveSupport::CoreExtensions::Numeric::Time)#ago>
m.__file__
# => "/Users/james/.rvm/gems/ree-1.8.7-2010.01/gems/activesupport-2.3.8/lib/active_support/core_ext/numeric/time.rb"
m.__line__
# => 64
红宝1.9外,还有 source_location
(谢谢你乔纳森!):
require 'active_support/all'
m = 2.days.method(:ago)
# => #<Method: Fixnum(Numeric)#ago> # comes from the Numeric module
m.source_location # show file and line
# => ["/var/lib/gems/1.9.1/gems/activesupport-3.0.6/.../numeric/time.rb", 63]
我来晚了此线,感到惊讶的是,没有人提到 Method#owner
.
class A; def hello; puts "hello"; end end
class B < A; end
b = B.new
b.method(:hello).owner
=> A
抄我的答案,从一个较新的 类似的问题 增加新的信息这一问题。
红宝石 1.9 有的方法称为 source_location:
返回的红宝石的来源的文件和线路数量包含这种方法或零如果这种方法不是限定在红宝石(即司机)
这已经移植到 1.8.7 通过这种宝石:
所以你可以要求该方法:
m = Foo::Bar.method(:create)
然后问问 source_location
这一方法:
m.source_location
这将返回一系列与文件和线路数量。E.g ActiveRecord::Base#validates
这个回报:
ActiveRecord::Base.method(:validates).source_location
# => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]
对课程和模块红宝石不提供建立在支助,但有一个极好的主旨,是建立在 source_location
回文件一定的方法或第一个文件为一类,如果没有一种方法是规定:
在行动:
where_is(ActiveRecord::Base, :validates)
# => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]
Mac有件安装,这也会弹出来的编辑在指定的位置。
这可以帮助,但你必须代码你自己。粘贴从博客:
红宝石提供了一个method_added() 回调援引每次一个 方法是加入或重新定义内 类。它的部分模块,类, 和每一类是一个模块。还有 还有两个相关的回调叫 method_removed()及 method_undefined().
http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby
如果你可以崩溃的方法,你会得到回溯这将确切地告诉你它在哪里。
不幸的是,如果你不能崩溃,那么你不能找出它已被定义。如果你尝试的猴子方法通过复盖了,或者重写,那么任何崩溃将来自你的复盖或复盖的方法,它不会被任何使用。
有用的方式的崩溃方法:
- 通
nil
它禁止它的-很多的时间的方法将提高一个ArgumentError
或永远存在NoMethodError
在一个零类。 - 如果你有的内部知识的方法,你知道,方法又呼吁其他一些方法,然后你可以overrwrite的其他方法,并提高内部。
也许是的 #source_location
可以帮助找到哪里是方法。
例如:
ModelName.method(:has_one).source_location
返回
[project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/associations.rb", line_number_of_where_method_is]
或
ModelName.new.method(:valid?).source_location
返回
[project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/validations.rb", line_number_of_where_method_is]
很晚回答:)但是,先前的答复并没有帮助我
set_trace_func proc{ |event, file, line, id, binding, classname|
printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
}
# call your method
set_trace_func nil
你可能能够这样做:
foo_finder.rb:
class String
def String.method_added(name)
if (name==:foo)
puts "defining #{name} in:\n\t"
puts caller.join("\n\t")
end
end
end
然后确保foo_finder载的第一个喜欢的东西
ruby -r foo_finder.rb railsapp
(我只是搞砸了轨道,所以我不知道,但我想有个方法可以开始就这样。)
这会告诉你所有的重新定义的字符串#foo。有一点超编,可以概括为任何功能你想要的。但它确实需要加载文件之前,实际上做了重新定义。
你总是可以得到一种回溯的你在哪里使用 caller()
.