Je voudrais savoir si je peux obtenir le code source d'une méthode à la volée, et si je peux obtenir dans quel fichier se trouve cette méthode.
comme
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Réponses:
Utilisez 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"
Notez que pour les méthodes intégrées, source_location
renvoie nil
. Si vous voulez vérifier le code source C (amusez-vous!), Vous devrez chercher le bon fichier C (ils sont plus ou moins organisés par classe) et trouver le rb_define_method
pour la méthode (vers la fin du fichier ).
Dans Ruby 1.8, cette méthode n'existe pas, mais vous pouvez utiliser cette gemme .
Aucune des réponses à ce jour ne montre comment afficher le code source d'une méthode à la volée ...
C'est en fait très facile si vous utilisez l'impressionnant joyau 'method_source' de John Mair (le créateur de Pry): La méthode doit être implémentée en Ruby (et non en C), et doit être chargée à partir d'un fichier (pas d'irb).
Voici un exemple affichant le code source de la méthode dans la console Rails avec 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
Voir également:
source
. Cela fonctionne comme prévu.
[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
fonctionne bien cependant
Voici comment imprimer le code source de ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Sans dépendances
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 vous souhaitez l'utiliser plus facilement, vous pouvez ouvrir la Method
classe:
# ~/.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
Et puis appelle method.source
Avec Pry, vous pouvez utiliser show-method
pour afficher une source de méthode, et vous pouvez même voir du code source ruby c avec pry-doc
installé, selon la doc de pry dans pry codde-browing
Notez que nous pouvons également afficher les méthodes C (depuis Ruby Core) en utilisant le plugin pry-doc; nous montrons également la syntaxe alternative pour 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éthode à l'intérieur de la Method
classe. Ce serait encore mieux s'il traitait le texte et de nouveau quand arrêter l'impression car il atteignait la fin de la méthode.
J'ai créé la gemme "ri_for" à cet effet
>> require 'ri_for'
>> A.ri_for :foo
... renvoie la source (et l'emplacement, si vous êtes sur 1.9).
GL. -r
J'ai dû implémenter une fonctionnalité similaire (récupérer la source d'un bloc) dans le cadre de Wrong et vous pouvez voir comment (et peut-être même réutiliser le code) dans chunk.rb (qui repose sur RubyParser de Ryan Davis ainsi que sur certains assez drôles code glomming du fichier source ). Vous devrez le modifier pour l'utiliser Method#source_location
et peut-être ajuster d'autres choses pour qu'il inclue ou non le fichier def
.
BTW Je pense que Rubinius a cette fonctionnalité intégrée. Pour une raison quelconque, elle a été laissée en dehors de l'IRM (l'implémentation standard de Ruby), d'où ce hack.
Oooh, j'aime certaines choses dans method_source ! Comme utiliser eval pour dire si une expression est valide (et continuer à glommer les lignes source jusqu'à ce que vous arrêtiez d'obtenir des erreurs d'analyse, comme le fait Chunk) ...
String#include?
. Jusqu'à présentString.instance_method(:include?).source_location
revientnil
.