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?
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:
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
.