Как я могу получить исходный код метода динамически, а также, какой файл находится этот метод в - PullRequest
74 голосов
/ 03 августа 2010

Я хотел бы знать, могу ли я получить исходный код методом на лету, и могу ли я узнать, в каком файле находится этот метод.

как

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

Ответы [ 7 ]

104 голосов
/ 03 августа 2010

Использование 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 этот метод не существует, но вы можете использовать этот драгоценный камень .

35 голосов
/ 18 июля 2012

Ни один из ответов пока не показывает, как отобразить исходный код метода на лету ...

На самом деле это очень легко, если вы используете потрясающий драгоценный камень 'method_source' Джона Мэйра (создатель Pry) Метод должен быть реализован в Ruby (не C) и должен быть загружен из файла (не irb).

Вот пример отображения исходного кода метода в консоли Rails с method_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 

Смотри также:

15 голосов
/ 05 марта 2014

Вот как распечатать исходный код из ruby:

puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
9 голосов
/ 27 октября 2017

Без зависимостей

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 для просмотра источника метода, и вы даже можете увидеть некоторый исходный код ruby ​​c с установленным pry-doc, согласно документу pry в codde-browing

Обратите внимание, что мы также можем просматривать методы C (из Ruby Core) с помощью плагина pry-doc;мы также демонстрируем альтернативный синтаксис для метода 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;
}
4 голосов
/ 03 августа 2010

Я создал камень "ri_for" для этой цели

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

... выводит источник (и местоположение, если вы находитесь на 1.9).

GL.-r

1 голос
/ 06 июля 2017

Внутренние методы не имеют источника или местоположения источника (например, Integer#to_s)

require 'method_source'
User.method(:last).source
User.method(:last).source_location
1 голос
/ 07 февраля 2013

Мне пришлось реализовать аналогичную функцию (захват источника блока) как часть Неправильно , и вы можете увидеть, как (и, возможно, даже повторно использовать код) в chunk.rb (который использует RubyParser Райана Дэвиса, а также довольно забавный исходный файл блестящий код ). Вы должны изменить его, чтобы использовать Method#source_location и, возможно, настроить некоторые другие вещи, чтобы он включал или не включал def.

Кстати, я думаю, что в Rubinius эта функция встроена. По какой-то причине она была исключена из MRI (стандартная реализация Ruby), отсюда и этот взлом.

Ооо, мне нравится кое-что из method_source ! Подобно , использующему eval, чтобы определить, является ли выражение действительным (и продолжать отображать исходные строки, пока вы не перестанете получать ошибки синтаксического анализа, как это делает Chunk) ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...