我们最近遇到了一个问题,即在发生一系列提交后,后端进程无法运行。 现在,我们是优秀的小男孩和女孩,并在每次办理登机手续后都进行了rake test
,但是由于Rails库加载中的一些奇怪现象,它只发生在我们直接从Mongrel生产模式中运行时。
我追踪了这个错误,这是因为一个新的Rails gem以一种破坏运行时Rails代码中一个狭隘用法的方式覆盖了String类中的一个方法。
无论如何,长话短说,有没有办法在运行时询问Ruby在哪里定义了一个方法? 像whereami( :foo )
那样返回/path/to/some/file.rb line #45
? 在这种情况下,告诉我它是在类String中定义的将是无益的,因为它被某些库重载。
我不能保证源代码存在于我的项目中,所以对'def foo'
追求并不一定会给我我需要的东西,更不用说我有多少 def foo
,有时候直到运行时我都不知道哪一个我可能正在使用。
#1楼
从一个更新的类似问题中复制我的答案,该问题为此问题添加了新信息。
Ruby 1.9有一个名为source_location的方法:
返回包含此方法的Ruby源文件名和行号,如果未在Ruby中定义此方法,则返回nil(即本机)
这个宝石被反向移植到1.8.7 :
所以你可以请求方法:
m = Foo::Bar.method(:create)
然后询问该方法的source_location
:
m.source_location
这将返回一个包含文件名和行号的数组。 例如,对于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]
对于类和模块,Ruby不提供内置支持,但是如果没有指定方法,那么有一个优秀的Gist构建在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]
在安装了TextMate的Mac上,这也会弹出指定位置的编辑器。
#2楼
这可能会有所帮助,但您必须自己编写代码。 粘贴在博客上:
Ruby提供了一个method_added()回调,每次在类中添加或重新定义方法时都会调用该回调。 它是Module类的一部分,每个Class都是一个Module。 还有两个相关的回调叫做method_removed()和method_undefined()。
http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby
#3楼
如果你可以崩溃这个方法,你会得到一个回溯,它会告诉你确切的位置。
不幸的是,如果你不能崩溃它,那么你无法找到它的定义。 如果您尝试通过覆盖或覆盖它来使用该方法,那么任何崩溃都将来自您的覆盖或重写方法,并且它将没有任何用处。
崩溃方法的有用方法:
- 传递
nil
禁止它 - 很多时候该方法会在nil类上引发ArgumentError
或者永远存在的NoMethodError
。 - 如果你对方法有内在的了解,并且你知道该方法又调用了其他方法,那么你可以覆盖另一个方法,然后在其中加注。
#4楼
你可以做这样的事情:
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
(我只是搞砸了轨道,所以我不确切知道,但我想有一种方法可以像这样开始。)
这将显示String#foo的所有重新定义。 通过一些元编程,您可以将其概括为您想要的任何功能。 但它确实需要在实际进行重新定义的文件之前加载。
#5楼
您可以使用caller()
始终回溯您所在的位置。
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3192772