代码之家  ›  专栏  ›  技术社区  ›  allenwei

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

  •  69
  • allenwei  · 技术社区  · 15 年前

    我想知道我是否可以动态地获取源代码一个方法,以及我是否可以获取这个方法在哪个文件中。

    喜欢

    A.new.method(:a).SOURCE_CODE
    A.new.method(:a).FILE
    
    7 回复  |  直到 6 年前
        1
  •  97
  •   Marc-André Lafortune    6 年前

    使用 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"
    

    注意,对于内置方法, 源定位 收益率 nil . 如果想查看C源代码(玩得开心!),您必须查找正确的C文件(它们或多或少是按类组织的)并找到 rb_define_method 对于方法(接近文件末尾)。

    在Ruby1.8中,此方法不存在,但可以使用 this gem .

        2
  •  33
  •   Tilo    13 年前

    到目前为止,没有一个答案显示了如何显示方法的源代码。 在飞翔…

    如果你使用约翰·迈尔(Pry的制造者)的“方法来源”宝石,其实很容易: 方法必须在Ruby(而不是C)中实现,并且必须从文件(而不是IRB)中加载。

    下面是一个在Rails控制台中显示方法源代码的示例,方法为“source:

      $ 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 
    

    参见:

        3
  •  14
  •   Automatico    11 年前

    下面是如何从Ruby中打印出源代码:

    puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
    
        4
  •  6
  •   Fangxing    7 年前

    没有依赖关系

    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

    随撬 你可以使用 show-method 查看方法源代码,甚至可以看到一些RubyC源代码 pry-doc 已安装,根据Pry的文件 codde-browing

    注意,我们也可以使用 pry doc plugin;我们还展示了show方法的替代语法:

    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;
    }
    
        5
  •  3
  •   rogerdpack    15 年前

    我为这个目的创造了宝石

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

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

    GL。 -R

        6
  •  1
  •   AlexChaffee    12 年前

    我必须实现类似的特性(获取块的源代码)作为 Wrong 您可以看到如何(甚至可以重用代码) chunk.rb (这依赖于Ryan Davis的RubyParser以及一些相当有趣的源文件 glomming code )你必须修改它才能使用 Method#source_location 可能会调整一些其他的东西,这样它会或不包括 def .

    顺便说一句,我认为Rubinius内置了这个特性。出于某种原因,它被排除在MRI(标准Ruby实现)之外,因此出现了这种黑客行为。

    噢,我喜欢里面的东西 method_source !喜欢 using eval to tell if an expression is valid (并像chunk一样,不断地获取源代码行,直到您停止解析错误为止)…

        7
  •  1
  •   Dorian    8 年前

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

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