[ruby-on-rails] 런타임에 메소드가 정의 된 위치를 찾는 방법은 무엇입니까?

최근에 일련의 커밋이 발생한 후 백엔드 프로세스가 실행되지 않는 문제가있었습니다. 이제 우리는 좋은 작은 소년과 소녀 였고 rake test체크인 할 때마다 달렸 지만 Rails의 라이브러리 로딩에 약간의 이상이 있었기 때문에 프로덕션 모드에서 Mongrel에서 직접 실행할 때만 발생했습니다.

버그를 추적했으며 런타임 Rails 코드에서 좁은 사용을 중단하는 방식으로 String 클래스의 메소드를 덮어 쓰는 새로운 Rails gem으로 인한 것입니다.

어쨌든, 간단히 말해서, 런타임에 메소드가 정의 된 위치를 Ruby에 물어볼 수있는 방법이 있습니까? 그런 식으로 뭔가 whereami( :foo )를 반환 /path/to/some/file.rb line #45합니까? 이 경우 String 클래스에 정의되었다고 말하면 일부 라이브러리에 의해 오버로드 되었기 때문에 도움이되지 않습니다.

나는 프로젝트에서 소스의 수명을 보장 할 수 없으므로 grepping을 위해 'def foo'필자가 필요한 것을 줄 필요는 없으며, 많은 것을 가지고 있는지 언급 def foo하지 않고 때로는 런타임 중 어느 것을 사용하고 있는지 알 수 없습니다.



답변

이것은 실제로 늦었지만 메소드가 정의 된 위치를 찾는 방법은 다음과 같습니다.

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) # 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]

네이티브 컴파일 코드와 같은 모든 기능에는 적용되지 않습니다. 방법 클래스 처럼, 너무, 몇 가지 참신한 기능이 방법 # 소유자 메소드가 정의 된 파일을 반환합니다.

편집 : 또한 볼 __file____line__그들도 편리있어, 다른 대답 REE에 대한 메모를. -wg


답변

실제로 위의 솔루션보다 조금 더 나아갈 수 있습니다. Ruby 1.8 Enterprise Edition의 경우 인스턴스에 __file____line__메소드가 있습니다 Method.

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_locationJonathan 이 감사합니다.

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


답변

이 문제에 새로운 정보를 추가 하는 새로운 유사한 질문 에서 내 대답을 복사 합니다.

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]

클래스와 모듈의 경우, 루비는 내장 된 지원을 제공하지 않지만 source_location메소드가 지정되지 않은 경우 주어진 메소드에 대한 파일 또는 클래스에 대한 첫 번째 파일을 리턴 하도록 빌드하는 훌륭한 Gist가 있습니다 .

실제로 :

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에서는 지정된 위치에 편집기가 나타납니다.


답변

도움이 될 수 있지만 직접 코딩해야합니다. 블로그에서 붙여 넣기 :

루비는 메소드가 클래스 내에서 추가되거나 재정의 될 때마다 호출되는 method_added () 콜백을 제공합니다. 모듈 클래스의 일부이며 모든 클래스는 모듈입니다. method_removed () 및 method_undefined ()라는 두 개의 관련 콜백도 있습니다.

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


답변

메소드를 중단시킬 수 있다면 정확한 위치를 알려주는 역 추적을 얻게됩니다.

불행히도 충돌이 없으면 정의 된 위치를 찾을 수 없습니다. 메서드를 덮어 쓰거나 재정 의하여 메서드를 사용하여 원숭이를 시도하면 덮어 쓰거나 재정의 된 메서드에서 충돌이 발생하여 아무 소용이 없습니다.

유용한 충돌 방법 :

  1. nil그것이 금지 된 곳을 통과 하십시오-메소드가 nil 클래스에서 ArgumentError또는 항상 존재 하는 시간을 많이 가질 것 NoMethodError입니다.
  2. 메소드에 대한 내부 지식이 있고 메소드가 다른 메소드를 호출한다는 것을 알고 있다면 다른 메소드를 겹쳐 써서 그 내부에서 발생할 수 있습니다.

답변

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

또는

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]