如何动态获取方法的源代码以及此方法所在的文件

时间:2010-08-03 01:52:32

标签: ruby

我想知道我是否可以动态获取源代码,以及我是否可以获取此方法的文件。

喜欢

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

7 个答案:

答案 0 :(得分:101)

使用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中,此方法不存在,但您可以使用this gem

答案 1 :(得分:34)

到目前为止,答案都没有显示如何动态显示方法的源代码

如果您使用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 

另见:

答案 2 :(得分:15)

以下是如何从ruby打印出源代码:

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

答案 3 :(得分:9)

没有依赖

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的一些ruby c源代码,根据pry' codde-browing

中的文档
  

请注意,我们也可以使用。来查看C方法(来自Ruby Core)   pry-doc插件;我们还展示了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;
}

答案 4 :(得分:4)

我为此创建了“ri_for”gem

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

...输出源(和位置,如果你在1.9上)。

GL。 -r

答案 5 :(得分:1)

我必须在Wrong中实现一个类似的功能(获取块的来源),你可以看到chunk.rb(依赖于Ryan)如何(甚至可能重用代码)戴维斯的RubyParser以及一些非常有趣的源文件glomming code)。您必须修改它以使用Method#source_location,并可能调整其他一些内容,以便它包括def

BTW我认为Rubinius内置了这个功能。出于某种原因,它被排除在MRI之外(标准的Ruby实现),因此这个黑客。

哦,我喜欢method_source中的一些内容!就像using eval to tell if an expression is valid一样(并且在你停止得到解析错误之前保持glomming源代码行,就像Chunk那样)......

答案 6 :(得分:1)

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

require 'method_source'
User.method(:last).source
User.method(:last).source_location