Я хотел бы знать, могу ли я получить исходный код методом "на лету", и могу ли я получить, в каком файле этот метод.
like
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Я хотел бы знать, могу ли я получить исходный код методом "на лету", и могу ли я получить, в каком файле этот метод.
like
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Используйте 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"
Это новичок в Ruby 1.9. Для Ruby 1.8 вы можете использовать этот камень, и я скопирую этот код до backports
, когда получу вторую.
Ни один из ответов пока не показывает, как отображать исходный код метода на лету...
На самом деле очень просто, если вы используете потрясающий "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
См. также:
Вот как распечатать исходный код из ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Я создал для этого камень "ri_for"
>> require 'ri_for'
>> A.ri_for :foo
... выводит источник (и местоположение, если вы в 1.9).
GL. -r
Мне пришлось реализовать подобную функцию (захватить источник блока) как часть Wrong, и вы можете увидеть, как (и возможно, даже повторное использование кода) в chunk.rb (в основе которого лежит RubyParser Райана Дэвиса, а также довольно забавный исходный файл glomming code). Вам нужно будет изменить его, чтобы использовать Method#source_location
и, возможно, настроить другие вещи, чтобы он включал или не включал def
.
Кстати. Я думаю, что у Rubinius встроена эта функция. По какой-то причине она осталась вне MRI (стандартная реализация Ruby), отсюда и этот хак.
Ооо, мне нравятся некоторые вещи в method_source! Как используя eval, чтобы определить, действительно ли выражение является действительным (и продолжайте скрывать исходные строки, пока не прекратите получать ошибки синтаксического анализа, например Chunk)...
Внутренние методы не имеют расположения источника или источника (например, Integer#to_s
)
require 'method_source'
User.method(:last).source
User.method(:last).source_location
Без зависимостей
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 doc в 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; }