Je lis le Module
mais ils ne parviennent pas à comprendre leurs différences et à savoir lequel doit être utilisé à quel endroit.
Comment le eval
différent de exec
?
Je lis le Module
mais ils ne parviennent pas à comprendre leurs différences et à savoir lequel doit être utilisé à quel endroit.
Comment le eval
différent de exec
?
Je vais répondre à un peu plus que votre question en incluant instance_{eval|exec}
dans votre question.
Toutes les variantes de {instance|module|class}_{eval|exec}
changer le contexte actuel c'est-à-dire la valeur de self
:
class Array
p self # prints "Array"
43.instance_eval{ p self } # prints "43"
end
Maintenant, les différences. Le site eval
accepte une chaîne ou un bloc, tandis que la version exec
n'acceptent qu'un bloc mais vous permettent de lui passer des paramètres :
def example(&block)
42.instance_exec("Hello", &block)
end
example{|mess| p mess, self } # Prints "Hello" then "42"
El eval
ne permet pas de passer des paramètres. Elle fournit self
comme premier paramètre, bien que je ne puisse pas penser à une utilisation pour cela.
Enfin, module_{eval|exec}
est le même que celui correspondant class_{eval|exec}
mais ils sont légèrement différents de instance_{eval|exec}
car ils changent ce qui est la classe ouverte actuelle (c'est-à-dire ce qui sera affecté par def
) de différentes manières :
String.instance_eval{ def foo; end }
Integer.class_eval { def bar; end }
String.method_defined?(:foo) # => false
String.singleton_methods.include?(:foo) # => true
Integer.method_defined?(:bar) # => true
Alors obj.instance_{eval|exec}
ouvre la classe singleton de obj
alors que mod.{class|module}_{eval|exec}
ouvre mod
lui-même.
Bien sûr, instance_{eval|exec}
sont disponibles sur n'importe quel objet Ruby (y compris les modules), alors que {class|module}_*
sont uniquement disponibles sur Module
(et donc Classes
)
Pour répondre d'abord à votre dernière question, l'évaluation (dans toutes ses variantes) est complètement différent de l'exécution. exec $command
démarre un nouveau processus pour exécuter la commande que vous avez spécifiée et se termine à la fin de ce processus.
class_eval
y module_eval
ont le pouvoir de redéfinir les classes et les modules - même ceux que vous n'avez pas écrits vous-même. Par exemple, vous pouvez utiliser la classe eval pour ajouter une nouvelle méthode qui n'existait pas.
Fixnum.class_eval { def number; self; end }
7.number # returns '7'
class_eval
peut être utilisé pour ajouter des méthodes d'instance, et instance_eval
peut être utilisé pour ajouter des méthodes de classe (oui, cette partie est très confuse). Une méthode de classe serait quelque chose comme Thing.foo
-- vous appelez littéralement le foo
sur la méthode Thing
classe. Une méthode d'instance est comme l'exemple ci-dessus, utilisant class_eval
J'ai ajouté un number
à chaque instance de Fixnum
.
Ok, donc c'est le *_eval
classe de méthodes. Les méthodes exec sont similaires, mais elles vous permettent de regarder à l'intérieur d'une classe et d'exécuter un bloc de code comme s'il était défini comme une méthode sur cette classe. Vous avez peut-être une classe qui ressemble à ceci :
class Foo
@@secret = 'secret key'
@@protected = 'some secret value'
def protected(key)
if key == @@secret
return @@protected
end
end
end
La classe Foo
est juste une enveloppe autour d'une valeur secrète, si vous connaissez la bonne clé. Toutefois, vous pouvez inciter la classe à vous livrer ses secrets en exécutant un bloc dans le contexte de la classe, comme suit :
Foo.class_exec { @@secret = 'i'm a hacker' }
Foo.protected('i'm a hacker') #returns the value of @@protected because we overwrote @@secret
En général, avec beaucoup d'outils dans Ruby, vous pouvez utiliser n'importe lequel d'entre eux pour résoudre beaucoup de problèmes. La plupart du temps, vous n'en aurez probablement même pas besoin, à moins que vous ne vouliez patcher une classe définie par une bibliothèque que vous utilisez (bien que cela ouvre toute une boîte de vers). Essayez de jouer avec eux dans irb et voyez lequel vous trouvez le plus facile. Personnellement, je n'utilise pas le *_exec
autant que les *_eval
méthodes, mais c'est une préférence personnelle de ma part.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.