Ruby on rails 如何找到在运行时定义方法的位置?
我们最近遇到了一个问题,在一系列提交发生后,后端进程无法运行。现在,我们都是好孩子,每次签入后都会运行Ruby on rails 如何找到在运行时定义方法的位置?,ruby-on-rails,ruby,runtime,methods,definition,Ruby On Rails,Ruby,Runtime,Methods,Definition,我们最近遇到了一个问题,在一系列提交发生后,后端进程无法运行。现在,我们都是好孩子,每次签入后都会运行rake测试,但由于Rails库加载中的一些奇怪之处,只有在生产模式下直接从Mongrel运行时才会发生 我追踪到了这个bug,这是由于一个新的Rails gem覆盖了String类中的一个方法,打破了运行时Rails代码中的一个狭隘用法 总之,长话短说,有没有办法在运行时询问Ruby在哪里定义了方法?类似于wheremi(:foo)的东西,它返回/path/to/some/file.rb行#4
rake测试
,但由于Rails库加载中的一些奇怪之处,只有在生产模式下直接从Mongrel运行时才会发生
我追踪到了这个bug,这是由于一个新的Rails gem覆盖了String类中的一个方法,打破了运行时Rails代码中的一个狭隘用法
总之,长话短说,有没有办法在运行时询问Ruby在哪里定义了方法?类似于wheremi(:foo)
的东西,它返回/path/to/some/file.rb行#45
?在这种情况下,告诉我它是在类字符串中定义的是没有帮助的,因为它被某个库重载了
我不能保证源代码存在于我的项目中,因此搜索
'def foo'
不一定能满足我的需要,更不用说如果我有很多def foo
,有时我直到运行时才知道我可能使用哪一个。这可能会有所帮助,但你必须自己编写代码。从博客中粘贴:
Ruby提供了一个方法
每次调用
方法是在
班级。它是模块类的一部分,
每个类都是一个模块。有
还有两个相关的回调调用
方法_removed()和
方法_undefined()
如果您可以使该方法崩溃,您将得到一个回溯跟踪,它将准确地告诉您它在哪里
不幸的是,如果您不能使它崩溃,那么您就无法找到它的定义位置。如果您试图通过覆盖或重写该方法来蒙骗该方法,那么任何崩溃都将来自被覆盖或重写的方法,并且不会有任何用处 碰撞方法的有用方法:
nil
——很多时候,该方法会在nil类上引发ArgumentError
或始终存在的NoMethodError
您可能可以执行以下操作: 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
(我只是弄乱了rails,所以我不知道确切情况,但我想有一种方法可以像这样启动它。)
这将向您展示字符串#foo的所有重新定义。通过一点元编程,您可以将其概括为您想要的任何函数。但是它确实需要在实际执行重新定义的文件之前加载。使用
caller()
这真是太晚了,但下面是如何找到方法定义的位置:
请注意,这不会在所有情况下都起作用,比如本机编译代码。还有一些简洁的函数,比如返回定义方法的文件
编辑:另一个答案中的\uuuu文件
和\uuu行
以及REE注释也很方便wg非常晚的回答:)但之前的回答对我没有帮助
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
实际上,您可以比上面的解决方案更进一步。对于Ruby 1.8企业版,在
方法
实例上有文件
和行
方法:
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
我在这篇文章上迟到了,我很惊讶没有人提到
方法#所有者
class A; def hello; puts "hello"; end end
class B < A; end
b = B.new
b.method(:hello).owner
=> A
A类;你好;放“你好”;结束
B级A
从更新版本复制我的答案,这会为该问题添加新信息
Ruby1.9的方法名为:
返回包含此方法的Ruby源文件名和行号,如果此方法未在Ruby中定义(即本机),则返回nil
此gem已将其后传至1.8.7:
m = Foo::Bar.method(:create)
然后询问该方法的源位置
:
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不提供内置支持,但有一个很好的要点,即基于source\u 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]
在安装了TextMate的Mac电脑上,这也会在指定位置弹出编辑器。也许#source_location
可以帮助找到方法的来源
例:
返回
[project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/associations.rb", line_number_of_where_method_is]
或
返回
[project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/validations.rb", line_number_of_where_method_is]
我在任何方法
类实例上都得到了文件
和行
的“NoMethodError:undefined method”,例如:方法(:方法)。\uu文件
你有哪个版本的ruby?ruby 1.8.7(2010-06-23补丁级别299)[x86\u 64-linux]在ruby 1.9上,m.uu文件uu
和m.u线uu
已替换为m.source u位置
source u位置
适用于Ruby 1.9及以上版本,包括Ruby 1.8.7中的2.1,专门添加了一个特殊方法来查找此信息(在1.9.3中仍然存在)。。。我在下面的回答中给出了详细的信息。我很惊讶你是第一个明确提到这个问题的人。在1.9中引入了另一个鲜为人知的宝藏:Method#parameters
。source\u位置似乎适用于使用activesupport-2.3.14的1.8.7-p334。找到方法后,请尝试方法的owner
方法2.方法中的第二个是什么(:犯罪)
?类的实例Fixnum
重要注意:这不会从method\u missing
中提取任何动态定义的方法。所以如果你有一个modu
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]
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]