Me gustaría saber si puedo obtener el código fuente de un método sobre la marcha, y si puedo obtener en qué archivo se encuentra este método.
me gusta
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Respuestas:
Utilizar 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"
Tenga en cuenta que, para los métodos integrados, source_location
devuelve nil
. Si desea consultar el código fuente de C (¡diviértase!), Tendrá que buscar el archivo C correcto (están más o menos organizados por clase) y encontrar rb_define_method
el método (hacia el final del archivo ).
En Ruby 1.8 este método no existe, pero puedes usar esta gema .
Ninguna de las respuestas hasta ahora muestra cómo mostrar el código fuente de un método sobre la marcha ...
En realidad, es muy fácil si usa la increíble gema 'method_source' de John Mair (el creador de Pry): el método debe implementarse en Ruby (no en C) y debe cargarse desde un archivo (no irb).
Aquí hay un ejemplo que muestra el código fuente del método en la consola de Rails con 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
Ver también:
source
. Esto funciona como se esperaba.
[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
aunque funciona bien
A continuación se explica cómo imprimir el código fuente de ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Sin dependencias
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]
Si desea usar esto de manera más conveniente, puede abrir la Method
clase:
# ~/.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
Y luego solo llama method.source
Con palanca , puede usar show-method
para ver la fuente de un método, e incluso puede ver un código fuente de ruby c pry-doc
instalado, según el documento de pry en codde-browing
Tenga en cuenta que también podemos ver los métodos C (de Ruby Core) usando el complemento pry-doc; también mostramos la sintaxis alternativa para 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
método dentro de la Method
clase. Sería incluso mejor si procesara el texto y cuándo dejar de imprimir porque llegó al final del método.
Creé la gema "ri_for" para este propósito
>> require 'ri_for'
>> A.ri_for :foo
... genera la fuente (y la ubicación, si está en 1.9).
GL. -r
Tuve que implementar una función similar (tomar la fuente de un bloque) como parte de Wrong y puedes ver cómo (y tal vez incluso reutilizar el código) en chunk.rb (que se basa en RubyParser de Ryan Davis, así como en algunos bastante divertidos código glomming del archivo fuente ). Tendrías que modificarlo para usarlo Method#source_location
y tal vez ajustar algunas otras cosas para que incluya o no eldef
.
Por cierto, creo que Rubinius tiene esta función incorporada. Por alguna razón, se ha dejado fuera de MRI (la implementación estándar de Ruby), de ahí este truco.
¡Oooh, me gustan algunas de las cosas en method_source ! Como usar eval para saber si una expresión es válida (y seguir glomming líneas fuente hasta que deje de recibir errores de análisis, como lo hace Chunk) ...
String#include?
. Hasta ahoraString.instance_method(:include?).source_location
vuelvenil
.