메서드의 소스 코드를 동적으로 가져오고이 메서드가 어떤 파일에 있는지 어떻게 확인할 수 있습니까?


89

소스 코드를 즉시 메서드로 가져올 수 있는지, 그리고이 메서드가 어떤 파일에 있는지 알 수 있는지 알고 싶습니다.

처럼

A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE

답변:


116

사용 source_location:

class A
  def foo
  end
end

file, line = A.instance_method(:foo).source_location
# or
file, line = A.new.method(:foo).source_location
puts "Method foo is defined in #{file}, line #{line}"
# => "Method foo is defined in temp.rb, line 2"

참고 내장 방법에 대한, 그 source_location반환 nil. C 소스 코드를 확인하려면 (재미있게) 올바른 C 파일 (클래스별로 구성되어 있음)을 찾아서 rb_define_method메서드 (파일 끝쪽 )를 찾아야 합니다. ).

Ruby 1.8에서는이 방법이 존재하지 않지만 이 gem을 사용할 수 있습니다 .


2
안녕하세요, 저는 Ruby 2.6.1을 사용하는 미래에서 왔습니다! 의 소스 코드를 원합니다 String#include?. 지금까지 String.instance_method(:include?).source_location돌아갑니다 nil.
S.Goswami

39

지금까지의 답변 중에는 메서드의 소스 코드를 즉시 표시하는 방법이 나와 있지 않습니다 .

John Mair (Pry 제작자)의 멋진 'method_source'gem을 사용하면 실제로 매우 쉽습니다.이 메서드는 Ruby (C가 아님)로 구현되어야하고 파일 (irb가 아님)에서로드되어야합니다.

다음은 method_source를 사용하여 Rails 콘솔에 메소드 소스 코드를 표시하는 예입니다.

  $ rails console
  > require 'method_source'
  > I18n::Backend::Simple.instance_method(:lookup).source.display
    def lookup(locale, key, scope = [], options = {})
      init_translations unless initialized?
      keys = I18n.normalize_keys(locale, key, scope, options[:separator])

      keys.inject(translations) do |result, _key|
        _key = _key.to_sym
        return nil unless result.is_a?(Hash) && result.has_key?(_key)
        result = result[_key]
        result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
        result
      end
    end
    => nil 

또한보십시오:


1
저는 항상 Ruby에서이 기능을 놓쳤습니다. 리스프는이 :) 할 수있다
는 Tila

Clojure의 source. 이것은 예상대로 작동합니다.
Sebastian Palma

이 오류가 발생합니다. [1] pry(main)> RSpec.method(:class_exec).source MethodSource::SourceNotFoundError: Could not locate source for class_exec! from /home/vagrant/.bundle/foo/ruby/2.5.0/gems/method_source-0.9.2/lib/method_source.rb:24:in `source_helper'
Abram

RSpec.method(:to_json).source_location그래도 잘 작동합니다
Abram

17

루비에서 소스 코드를 출력하는 방법은 다음과 같습니다.

puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])

10

의존성없이

method = SomeConstant.method(:some_method_name)
file_path, line = method.source_location
# puts 10 lines start from the method define 
IO.readlines(file_path)[line-1, 10]

이것을 더 편리하게 사용하려면 Method클래스를 열 수 있습니다 .

# ~/.irbrc
class Method
  def source(limit=10)
    file, line = source_location
    if file && line
      IO.readlines(file)[line-1,limit]
    else
      nil
    end
  end
end

그리고 그냥 전화 method.source

Pry사용하면를 사용하여 show-method메소드 소스를 볼 수 pry-doc있으며 코드 브라우징 의 pry의 문서에 따라 설치된 일부 루비 C 소스 코드도 볼 수 있습니다.

pry-doc 플러그인을 사용하여 Ruby Core에서 C 메소드를 볼 수도 있습니다. 또한 show-method에 대한 대체 구문을 보여줍니다.

pry(main)> show-method Array#select

From: array.c in Ruby Core (C Method):
Number of lines: 15

static VALUE
rb_ary_select(VALUE ary)
{
    VALUE result;
    long i;

    RETURN_ENUMERATOR(ary, 0, 0);
    result = rb_ary_new2(RARRAY_LEN(ary));
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
            rb_ary_push(result, rb_ary_elt(ary, i));
        }
    }
    return result;
}

이것은 클래스 source내부의 메서드에 대한 좋은 아이디어입니다 Method. 방법의 끝에 도달했기 때문에 텍스트를 처리하고 인쇄를 중지해야 할 때를 새로 작성하면 더 좋을 것입니다.
Toby 1 Kenobi

4

이 목적을 위해 "ri_for"gem을 만들었습니다.

 >> require 'ri_for'
 >> A.ri_for :foo

... 소스 (및 1.9 인 경우 위치)를 출력합니다.

GL. -아르 자형


이 모든 것이 분할 오류를 생성하는 것입니다. :(
panzi 2011 년

세그 결함을 재현하는 방법? 어떤 방법 / 클래스?
rogerdpack 2011 년

1

나는 Wrong의 일부로 유사한 기능을 구현해야했고 (블록의 소스를 잡아 ) chunk.rb (Ryan Davis의 RubyParser에 의존 하는 코드와 코드를 재사용하는 방법)를 볼 수 있습니다. 소스 파일 glomming 코드 ). 당신은 그것을 사용하기 위해 그것을 수정해야 할 Method#source_location것이고 아마도 다른 것들을 조정하여 def.

BTW 저는 Rubinius에이 기능이 내장되어 있다고 생각합니다. 어떤 이유로 MRI (표준 Ruby 구현)에서 제외되었으므로이 해킹입니다.

아, method_source 의 내용이 마음에 듭니다 ! 마찬가지로 표현식이 유효한지 말할 평가를 사용하여 (그리고 덩어리가하는 것처럼 당신이, 구문 분석 오류를 받고 중지 할 때까지 glomming 소스 라인을 유지) ...


1

내부 방법 (예를 들어, 소스 또는 소스 위치가 없습니다 Integer#to_s)

require 'method_source'
User.method(:last).source
User.method(:last).source_location
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.