咱們最近遇到了一個問題,即在發生一系列提交後,後端進程沒法運行。 如今,咱們是優秀的小男孩和女孩,並在每次辦理登機手續後都進行了rake test
,可是因爲Rails庫加載中的一些奇怪現象,它只發生在咱們直接從Mongrel生產模式中運行時。 git
我追蹤了這個錯誤,這是由於一個新的Rails gem以一種破壞運行時Rails代碼中一個狹隘用法的方式覆蓋了String類中的一個方法。 github
不管如何,長話短說,有沒有辦法在運行時詢問Ruby在哪裏定義了一個方法? 像whereami( :foo )
那樣返回/path/to/some/file.rb line #45
? 在這種狀況下,告訴我它是在類String中定義的將是無益的,由於它被某些庫重載。 編程
我不能保證源代碼存在於個人項目中,因此對'def foo'
追求並不必定會給我我須要的東西,更不用說我有多少 def foo
,有時候直到運行時我都不知道哪個我可能正在使用。 後端
從一個更新的相似問題中複製個人答案,該問題爲此問題添加了新信息。 數組
Ruby 1.9有一個名爲source_location的方法: ruby
返回包含此方法的Ruby源文件名和行號,若是未在Ruby中定義此方法,則返回nil(即本機) app
這個寶石被反向移植到1.8.7 : 編輯器
因此你能夠請求方法: spa
m = Foo::Bar.method(:create)
而後詢問該方法的source_location
: code
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上,這也會彈出指定位置的編輯器。
這可能會有所幫助,但您必須本身編寫代碼。 粘貼在博客上:
Ruby提供了一個method_added()回調,每次在類中添加或從新定義方法時都會調用該回調。 它是Module類的一部分,每一個Class都是一個Module。 還有兩個相關的回調叫作method_removed()和method_undefined()。
http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby
若是你能夠崩潰這個方法,你會獲得一個回溯,它會告訴你確切的位置。
不幸的是,若是你不能崩潰它,那麼你沒法找到它的定義。 若是您嘗試經過覆蓋或覆蓋它來使用該方法,那麼任何崩潰都未來自您的覆蓋或重寫方法,而且它將沒有任何用處。
崩潰方法的有用方法:
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
(我只是搞砸了軌道,因此我不確切知道,但我想有一種方法能夠像這樣開始。)
這將顯示String#foo的全部從新定義。 經過一些元編程,您能夠將其歸納爲您想要的任何功能。 但它確實須要在實際進行從新定義的文件以前加載。
您能夠使用caller()
始終回溯您所在的位置。