一連のコミットが発生した後、バックエンドプロセスの実行に失敗するという問題が最近発生しました。さて、私たちは小さな男の子で、チェックインのたびにrake test
を実行しましたが、Railsのライブラリーのロードに奇妙な点があるため、実稼働モードでMongrelから直接実行した場合にのみ発生しました。
バグを追跡しましたが、それは新しいRails gemがStringクラスのメソッドをランタイムRailsコードでの1つの狭い使用を壊す方法で上書きしたためです。
とにかく、要するに、実行時に、メソッドが定義されている場所をRubyに尋ねる方法はありますか? /path/to/some/file.rb line #45
を返すwhereami( :foo )
のようなものこの場合、クラスStringで定義されていると言っても、ライブラリによってオーバーロードされたため、役に立ちません。
ソースがプロジェクト内に存在することを保証することはできません。したがって、'def foo'
をgrepしても、必要なものが必ずしも得られません。多くdef foo
がある場合はもちろん、どちらを使用するかは実行時までわかりません。
これは本当に遅いですが、メソッドが定義されている場所を見つける方法は次のとおりです。
# 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#owner のような、きちんとした機能もあります。
編集:また、他の答えの__file__
と__line__
とREEのメモを参照してください、それらも便利です。 -wg
実際には、上記のソリューションよりも少し先に進むことができます。 Ruby 1.8 Enterprise Editionの場合、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]
私はこのスレッドに遅れて来ており、誰もMethod#owner
に言及していないことに驚いています。
class A; def hello; puts "hello"; end end
class B < A; end
b = B.new
b.method(:hello).owner
=> A
この問題に新しい情報を追加する新しい 類似の質問 から私の回答をコピーします。
Ruby1.9には source_location というメソッドがあります:
このメソッドを含むRubyソースファイル名と行番号を返します。このメソッドがRuby(つまりネイティブ)で定義されていない場合はnilを返します
これは、このgemによって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は組み込みサポートを提供しませんが、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()コールバックを提供します。これはモジュールクラスの一部であり、すべてのクラスはモジュールです。 method_removed()およびmethod_undefined()と呼ばれる2つの関連するコールバックもあります。
http://scie.nti.st/2008/9/17/making-methods-immutable-in-Ruby
メソッドをクラッシュできる場合は、バックトレースが表示され、正確にどこにあるかがわかります。
残念ながら、クラッシュできない場合は、定義されている場所を見つけることができません。メソッドを上書きまたはオーバーライドすることでメソッドを操作しようとすると、上書きまたはオーバーライドされたメソッドからクラッシュが発生し、使用できなくなります。
メソッドをクラッシュさせる便利な方法:
nil
を禁止する場所に渡します-多くの場合、メソッドはArgumentError
または常に存在しないNoMethodError
をnilクラスで発生させます。#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]
非常に遅い回答:)しかし、以前の回答は私を助けませんでした
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
caller()
を使用することにより、現在地のバックトレースをいつでも取得できます。
次のようなことができるかもしれません:
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を台無しにしているだけなので、正確にはわかりませんが、これを開始する方法があると思います。)
これにより、String#fooのすべての再定義が表示されます。少しのメタプログラミングで、必要な機能に合わせて一般化できます。ただし、実際に再定義を行うファイルの前にロードする必要があります。