如何动态获取方法的源代码以及该方法位于哪个文件中


89

我想知道是否可以即时获取源代码方法,以及是否可以获取该方法位于哪个文件中。

喜欢

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

Answers:


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'宝石,则实际上非常容易:该方法必须在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 2012年

来自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

根据Prycodde-browing中的文档,使用Pry,您可以使用show-method来查看方法源,甚至可以看到pry-doc已安装的一些ruby c源代码。

注意,我们也可以使用pry-doc插件查看C方法(从Ruby Core);我们还展示了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。如果它处理了文本,并且在停止打印时输入了new,则更好,因为它已到达方法的结尾。
Toby 1 Kenobi

4

为此,我创建了“ ri_for” gem

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

...输出源(以及位置,如果您使用的是1.9)。

GL。-r


这一切对我来说都是产生分段错误。:(
panzi 2011年

如何重现段错误?哪个方法/类?
rogerdpack 2011年

1

作为Wrong的一部分,我必须实现类似的功能(获取块的源代码),您可以看到chunk.rb(依赖于Ryan Davis的RubyParser以及如何做的一些有趣的事情)(甚至可以重用代码)源文件含糊代码)。您必须对其进行修改才能使用,Method#source_location并且可能还要进行一些其他调整,以使其包含或不包含def

顺便说一句,我认为Rubinius内置了此功能。出于某种原因,它被排除在MRI(标准的Ruby实现)之外,因此被称为hack。

噢,我喜欢method_source中的一些东西!就像使用eval来判断一个表达式是否有效(并保持含糊不清的源代码行,直到像块一样停止获取解析错误为止)...


1

内部方法没有源或源位置(例如Integer#to_s

require 'method_source'
User.method(:last).source
User.method(:last).source_location
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.