メソッドのソースコードを動的に取得する方法と、このメソッドが配置するファイル


89

オンザフライでソースコードをメソッドで取得できるかどうか、およびこのメソッドが含まれるファイルを取得できるかどうかを知りたいです。

お気に入り

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

回答:


114

使用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でこの機能を見逃してしまいました。Lispはこれを行うことができます:)
Tilo

Clojureのから来ていsourceます。これは期待どおりに機能します。
セバスチャンパルマ

私はこのエラーを受け取ります: [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'
エイブラム

RSpec.method(:to_json).source_location正常に動作します
エイブラム

17

Rubyからソースコードを出力する方法は次のとおりです。

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-doccodde-browingのPryのドキュメントによると、インストール済みのruby 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。-r


これで私がすることはすべて、セグメンテーション違反を引き起こしていることです。:(
パンジ

セグメント障害を再現するには?どのメソッド/クラス?
rogerdpack 2011年

1

Wrongの一部として同様の機能(ブロックのソースを取得)を実装する必要があり、chunk.rb(Ryan DavisのRubyParserに依存しているだけでなく、かなり面白いもの)でその方法(そしておそらくコードを再利用すること)を確認できますソースファイルグロミングコード)。あなたはそれを使用するために修正しMethod#source_location、おそらく他のものを微調整して、それが含まれるか含まれないようにする必要がありますdef

ところで、Rubiniusにはこの機能が組み込まれていると思います。何らかの理由でMRI(標準のRuby実装)から除外されているため、このハックが行われました。

おおmethod_sourceの中のいくつかのものが好きです!以下のような式が有効であるかどうかを伝えるためにevalを使用して(とチャンクがないようにあなたは、パースエラーが発生して停止するまで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.