我们最近遇到了一个问题,在一系列提交之后,一个后端进程无法运行。现在,我们都很乖,每次签入后都会运行rake测试,但是,由于Rails库加载中的一些奇怪之处,它只在我们直接从Mongrel在生产模式下运行时才会发生。
我追踪了这个bug,它是由于一个新的Rails gem覆盖了String类中的一个方法,这种方法破坏了运行时Rails代码中的一个狭窄使用。
总之,长话短说,有没有一种方法,在运行时,问Ruby在哪里定义了一个方法?类似于whereami(:foo),返回/path/to/some/file。Rb线45号?在这种情况下,告诉我它是在类String中定义的是没有帮助的,因为它被一些库重载了。
我不能保证源生活在我的项目,所以grepping 'def foo'不一定给我我需要的,更不用说,如果我有很多def foo's,有时我不知道,直到运行时,我可能会使用哪一个。
这真的很晚了,但下面是如何找到定义方法的地方:
http://gist.github.com/76951
# 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>
如果你使用的是Ruby 1.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]
注意,这并不适用于所有东西,比如本机编译代码。Method类也有一些简洁的函数,比如Method#owner,它返回定义方法的文件。
编辑:也请参阅另一个答案中的__file__和__line__以及REE的注释,它们也很方便。——工作组
从一个更新的类似问题中复制我的答案,为这个问题添加了新的信息。
Ruby 1.9有一个叫做source_location的方法:
返回Ruby源代码文件名和包含该方法的行号,如果该方法没有在Ruby中定义(即本机),则返回nil。
这已经被这个gem反向移植到1.8.7:
ruby18_source_location
所以你可以请求这个方法:
m = Foo::Bar.method(:create)
然后请求该方法的source_location:
m.source_location
这将返回一个包含文件名和行号的数组。
例如ActiveRecord::Base#验证这个返回:
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]
对于类和模块,Ruby不提供内置支持,但有一个优秀的Gist,它构建在source_location上,为给定的方法返回文件,如果没有指定方法,则为类返回第一个文件:
Ruby where_is模块
在行动:
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]
在安装了TextMate的mac上,这也会在指定位置弹出编辑器。