it-source

런타임에 메서드가 정의된 위치를 찾는 방법은 무엇입니까?

criticalcode 2023. 6. 15. 21:54
반응형

런타임에 메서드가 정의된 위치를 찾는 방법은 무엇입니까?

최근 일련의 커밋이 발생한 후 백엔드 프로세스가 실행되지 않는 문제가 발생했습니다.자, 우리는 착한 소년 소녀였고 도망쳤습니다.rake test체크인할 때마다 Rails의 라이브러리 로딩에 이상이 있기 때문에 운영 모드에서 Mongrel에서 직접 실행했을 때만 발생했습니다.

버그를 추적해보니 새로운 Rails 보석이 String 클래스의 메서드를 런타임 Rails 코드에서 좁은 용도로 사용하지 못하게 덮어씌워졌기 때문입니다.

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

제 프로젝트에 소스가 있다고 보장할 수 없습니다. 그래서 그랩핑을 합니다.'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+를 사용하는 경우

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]

이것이 네이티브 컴파일된 코드와 같은 모든 것에서 작동하지는 않습니다.메소드 클래스에는 메소드가 정의된 파일을 반환하는 메소드 #owner와 같은 일부 깔끔한 함수도 있습니다.

편집: 항목 참조하십시오.__file__그리고.__line__ -- wg 리고다에른답변의 RE다대유니용합. -- wg

위의 솔루션보다 조금 더 멀리 갈 수 있습니다. 1에는 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_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

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

Ruby 1.9에는 source_location이라는 메서드가 있습니다.

이 메서드를 포함하는 Ruby 소스 파일 이름과 줄 번호를 반환하거나 이 메서드가 Ruby(즉, native)에 정의되지 않은 경우 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에서는 지정된 위치에 편집기도 표시됩니다.

아마도#source_location방법의 출처를 찾는 데 도움이 될 수 있습니다.

ex:

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]

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

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

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

메소드를 크래시할 수 있으면 위치를 정확히 알려주는 역추적 기능이 제공됩니다.

불행히도 충돌할 수 없으면 정의된 위치를 찾을 수 없습니다.메서드를 덮어쓰거나 재정의하여 메서드를 조작하려고 하면 덮어쓰거나 재정의한 메서드에서 충돌이 발생하므로 아무 소용이 없습니다.

충돌 방법의 유용한 방법:

  1. 통과하다nil그것이 금지하는 곳 - 많은 시간 동안 방법은 그것을 제기할 것입니다.ArgumentError 존재하는 는또항존는하재상▁the.NoMethodError교시에
  2. 메소드에 대한 내부 지식이 있고 메소드가 다른 메소드를 호출한다는 것을 알고 있다면 다른 메소드를 덮어쓰고 그 안에서 올릴 수 있습니다.

매우 늦은 답변 :) 하지만 이전 답변은 나에게 도움이 되지 않았습니다.

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

다음과 같은 작업을 수행할 수 있습니다.

foo_finder.foo:

 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().

언급URL : https://stackoverflow.com/questions/175655/how-to-find-where-a-method-is-defined-at-runtime

반응형