Def de Ruby et EVAL instance vs EVAL classe

Je lis la section de métaprogrammation de programmation Ruby 1.9 et j'ai du mal à comprendre ce qui se passe en interne entre class_eval/class_exec vs. instance_eval/instance_exec.

Donc tout d'abord, ma compréhension est que def ajoute une méthode à la table de méthode de self (l'objet de classe):

class A
  puts self  # => A
  def foo; 42; end  # added to the method table of self, so becomes an instance method
end
A.new.foo  # => 42

Et si nous utilisons class_eval, nous obtenons le même comportement:

A.class_eval do
  puts self  # => A
  def bar; 42; end  # same as above
end
A.new.bar  # => 42

Mais d'une manière ou d'une autre dans le cas instance_eval, les choses sont différentes:

A.instance_eval do
  puts self  # => A
  def baz; 42; end  # added to the method table of an anonymous
                    # singleton class of self, so becomes a class method
end
puts A.baz  # => 42

s = 'string'
s.instance_eval do ... end  # same behavior, so now def creates an instance method

Donc je comprends la différence fonctionnelle entre class_eval et instance_eval.

Mais les contextes à l'intérieur des blocs class_eval et instance_eval regardent exactement la même chose pour moi-en particulier, self pointe vers le même objet, et les local_variables sont les mêmes. Alors, qu'est-ce qui se passe à l'intérieur des blocs (en interne) qui fait que def agit différemment?

Y a-t-il une documentation que je pourrais lire? Le RDoc pour instance_eval et class_eval ne l'aide pas. En regardant la source, instance_eval semble mettre en place un objet de classe singleton alors que class_eval ne le fait pas-mais cette différence est-elle visible en dehors du code C, au niveau Ruby?

26
demandé sur Jo Liss 2010-12-10 15:57:40

2 réponses

Je pense que votre confusion vient du fait que def ne dépend pas du moi actuel, vous pourriez penser que c'est une "classe actuelle" qui a ses propres règles.

Suivant vos exemples:

class A
  # defs here go to A
  puts self  # => A
  class << self
     #defs here go to A's eigenclass
  end
end

A.class_eval do
  #defs here go to A
end

A.instance_eval do
  #defs here go to A's eigenclass     
end

s = "Hello World"

class << s
  #defs here go to s's eigenclass
end

Voici la partie du chapitre qui parle du problème et c'est assez clair sur le comportement

Class_eval et instance_eval ensemble soi-même pour la durée du bloc. Cependant, ils diffèrent dans la façon dont ils configurer l'environnement pour méthode définition. class_eval met les choses en place comme si vous étiez dans le corps d'une classe définition, donc les définitions de méthode définir les méthodes d'instance en contraste, appeler instance_eval sur une classe agit comme si vous travailliez à l'intérieur du classe singleton de soi. Donc, toutes les méthodes que vous définissez deviendra les méthodes de la classe.

La seule chose que je pense valoir la peine d'ajouter est que vous pouvez appeler instance_eval dans n'importe quel objet, pas seulement les classes, et le comportement ne change pas mais a des conséquences différentes.

Quelques lectures pertinentes:

Ruby: instance_eval et class_eval définitions de méthodes

Le Chapitre 4 de cette excellente série

31
répondu krusty.ar 2015-10-23 17:55:54

Juste pour ajouter à @krusty.ar réponse: def et define_method ajouter des méthodes au contexte de définition de méthode actuel (je crois que c'est ce qu'on appelle, Je ne suis pas sûr), pas au courant self.

C'est juste qu'à l'intérieur d'un module, d'une classe ou d'un corps de classe singleton, ces deux-là sont identiques.

Mais, par exemple, dans un corps de script (aka niveau supérieur), self est l'objet main, mais le contexte de définition de méthode actuel est Object.

3
répondu Jörg W Mittag 2010-12-10 14:51:06