web-dev-qa-db-fra.com

Comment puis-je obtenir le code source d'une méthode de manière dynamique et aussi dans quel fichier cette méthode est localisée?

Je voudrais savoir si je peux obtenir le code source d’une méthode à la volée et si je peux savoir dans quel fichier se trouve cette méthode.

comme 

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

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"

C'est nouveau pour Ruby 1.9, cependant. Pour Ruby 1.8, vous pouvez utiliser ce bijou , et je recopierai ce code dans backports dès que j'aurai une seconde.

94

Jusqu'à présent, aucune des réponses n'a montré comment afficher le code source d'une méthode à la volée ...

C'est en fait très facile si vous utilisez l'impressionnant bijou 'method_source' de John Mair (le fabricant de Pry): La méthode doit être implémentée dans Ruby (pas C) ).

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:

31
Tilo

Voici comment imprimer le code source de Ruby:

puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
14
Automatico

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 voulez utiliser ceci plus facilement, vous pouvez ouvrir la classe 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

Et ensuite, appelez simplement method.source

Avec Pry, vous pouvez utiliser le show-method pour afficher une source de méthode. Vous pouvez même voir du code source Ruby c avec pry-doc installé, selon la documentation de pry dans codde-browing

Notez que nous pouvons également afficher les méthodes C (à partir de Ruby Core) à l’aide de pry-doc plugin; 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;
}
6
fangxing

J'ai créé le joyau "ri_for" à cet effet

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

... affiche la source (et l'emplacement, si vous êtes sur 1.9).

GL .- r

3
rogerdpack

J'ai dû implémenter une fonctionnalité similaire (saisir la source d'un bloc) dans Wrong et vous pouvez voir comment (et peut-être même réutiliser le code) dans chunk.rb (qui s'appuie sur Ryan Davis 'RubyParser ainsi que des fichiers source assez drôles glomming code ). Vous devrez le modifier pour utiliser Method#source_location et peut-être modifier quelques autres choses afin d’inclure ou non la def.

BTW Je pense que Rubinius a cette fonctionnalité intégrée. Pour une raison quelconque, elle n’a pas été laissée dans l’IRM (implémentation standard de Ruby), d’où ce hack.

Oooh, j'aime certaines choses dans method_source ! Comme utiliser eval pour indiquer si une expression est valide (et garder les lignes sources vantées jusqu'à ce que vous n'ayez plus d'erreur d'erreur d'analyse, comme le fait Chunk) ...

1
AlexChaffee

Les méthodes internes n'ont pas de source ou d'emplacement source (par exemple, Integer#to_s)

require 'method_source'
User.method(:last).source
User.method(:last).source_location
0
Dorian