Я хотел бы знать, могу ли я получить исходный код метода на лету и могу ли я узнать, в каком файле находится этот метод.
нравиться
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"
Обратите внимание, что для встроенных методов source_location
возвращает nil
. Если вы хотите проверить исходный код C (получайте удовольствие!), Вам нужно будет найти правильный файл C (они более или менее организованы по классам) и найти rb_define_method
метод (ближе к концу файла ).
В Ruby 1.8 этого метода не существует, но вы можете использовать этот гем .
Ни один из ответов пока не показывает, как отображать исходный код метода на лету ...
На самом деле это очень просто, если вы используете замечательный гем 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
Смотрите также:
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
хотя работает нормально
Вот как распечатать исходный код из ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Без зависимостей
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-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
класса. Было бы даже лучше, если бы он обработал текст и новый, когда прекратить печать, потому что он достиг конца метода.
Я создал для этого гем "ri_for"
>> require 'ri_for'
>> A.ri_for :foo
... выводит источник (и местоположение, если вы используете 1.9).
GL. -р
Мне пришлось реализовать аналогичную функцию (захватить источник блока) как часть Wrong, и вы можете увидеть, как (и, возможно, даже повторно использовать код) в chunk.rb (который опирается на RubyParser Райана Дэвиса, а также на довольно забавные исходный файл glomming code ). Вам придется изменить его, чтобы использовать Method#source_location
и, возможно, настроить некоторые другие вещи, чтобы он включал или не включал def
.
Кстати, я думаю, что в Rubinius встроена эта функция. По какой-то причине она была исключена из MRI (стандартной реализации Ruby), отсюда и этот взлом.
Ооо, мне нравятся некоторые вещи в method_source ! Это похоже на использование eval, чтобы определить, допустимо ли выражение (и продолжайте показывать исходные строки, пока вы не перестанете получать ошибки синтаксического анализа, как это делает Chunk) ...
String#include?
. ПокаString.instance_method(:include?).source_location
возвращаетсяnil
.