2008-10-06 29 views
290

我們最近出現了一個問題,在發生一系列提交後,後端進程無法運行。現在,我們是優秀的小男孩和女孩,每次辦理登機手續後都會跑rake test,但由於Rails圖書館加載中存在一些問題,只能在生產模式下直接從Mongrel運行它時纔會發生。如何查找在運行時定義方法的位置?

我跟蹤了這​​個bug,這是由於新的Rails gem覆蓋了String類中的一個方法,這種方式打破了運行時Rails代碼中的一個狹窄用法。

無論如何,長話短說,在運行時,有沒有辦法在Ruby中定義一個方法?像whereami(:foo)那樣返回/path/to/some/file.rb line #45?在這種情況下,告訴我它是在String類中定義的,將無濟於事,因爲它被某個庫重載。

我不能保證源生活在我的項目,所以對於grepping將'def foo'不一定給我我需要什麼,更何況,如果我有很多def foo的,有時我不知道,直到運行時其我可能會使用一個。

+1

在Ruby 1.8.7,特殊方法被特別添加來找到這些信息(並且它仍然存在於1.9.3中)...下面我的答案中有詳細信息。 – 2012-02-20 04:11:43

回答

373

這確實是晚了,但這裏是你如何能找到其中定義的方法:

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) 
#<Method: Fixnum(Perpetrator)#crime> 

如果你上紅寶石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 class也有一些簡潔的功能,如Method#owner,它返回定義方法的文件。

編輯:另請參閱__file____line__以及其他答案中的REE註釋,它們也很方便。 - WG

+1

查找方法後,source_location顯示爲1.8.7-p334使用activesupport-2.3.14 – MaasSql 2012-07-17 18:03:33

+0

,請嘗試Method的「所有者」方法 – Juguang 2013-12-03 11:20:27

+0

「2.method(:crime)」中的數字2是什麼? – stack1 2015-03-02 21:24:47

6

這可能有幫助,但你必須自己編寫代碼。從博客粘貼:

Ruby provides a method_added() callback that is invoked every time a method is added or redefined within a class. It’s part of the Module class, and every Class is a Module. There are also two related callbacks called method_removed() and method_undefined().

http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby

4

如果你會崩潰的方法,你會得到一個回溯它會告訴你它的確切位置。

不幸的是,如果你不能崩潰,那麼你不能找出它的定義。如果您試圖通過覆蓋或覆蓋該方法來使用該方法,那麼任何崩潰都會來自您的覆蓋或重寫方法,並且不會有任何用處。轟然方法

有用的方法:

  1. nil它禁止它 - 很多的時間的方法將提高在無類的ArgumentError或永遠存在NoMethodError
  2. 如果您對方法有深入的瞭解,並且您知道該方法反過來調用其他方法,那麼您可以覆蓋其他方法,並在其中引發其他方法。
+0

如果您有權訪問代碼,您可以輕鬆地插入'require'ruby-debug';調試器「在你想要放入的代碼中。 – 2012-10-22 15:23:52

2

您也許能夠做這樣的事情:

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 

(I」我只是搞不清軌道,所以我不確切,但我想有一種方法可以啓動它,就像這樣。)

這將向您展示String#foo的所有重新定義。有了一些元編程,你可以將它推廣到任何你想要的功能。但它確實需要在實際重新定義的文件之前加載。

2

通過使用caller(),您始終可以回溯到您所在的位置。

+0

這對於找到稱爲你的東西非常有用,但當你試圖找到定義的東西的時候並不好。 – 2012-10-22 15:21:16

3

很晚了答案:)但是前面的回答對我沒有幫助

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 
78

實際上,你可以走得更遠一點比上面的解決方案。對Ruby 1.8企業版,對Method實例__file____line__方法:

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 

爲Ruby 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] 
34

我來了遲到這個帖子,並且很驚訝,沒有人提到Method#owner

class A; def hello; puts "hello"; end end 
class B < A; end 
b = B.new 
b.method(:hello).owner 
=> A 
10

從較新的similar question複製我的答案,爲此問題添加新信息。

紅寶石1.9已方法稱爲source_location

Returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby (i.e. native)

這已經通過這種寶石回遷到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/[email protected]/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81] 

類和模塊,Ruby沒有提供內置支持,但有一個很好的要點,在那裏,建立在source_location返回文件爲一個給定的方法或第一檔類,如果沒有指定方法:

在動作:

where_is(ActiveRecord::Base, :validates) 

# => ["/Users/laas/.rvm/gems/[email protected]/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81] 

在安裝了TextMate的Mac上,這也會彈出編輯器在指定位置。

3

也許#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] 

OR

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] 
相關問題