web-dev-qa-db-fra.com

Qu'est-ce que 'Monkey Patching' signifie exactement en Ruby?

Selon Wikipedia, un singe patch est:

un moyen d'étendre ou de modifier le runtime code des langages dynamiques [...] sans modifier la source d'origine code.

La déclaration suivante de la même entrée m'a confondu:

En Ruby, le terme patch de singe était incompris comme signifiant toute dynamique modification à une classe et est souvent utilisé comme synonyme de dynamiquement modifier n'importe quelle classe à l'exécution.

Je voudrais savoir la signification exacte de la correction de singe en Ruby. Fait-il quelque chose comme ce qui suit ou est-ce autre chose?

class String
  def foo
    "foo"
  end
end
59
Yaser Sulaiman

La réponse courte est qu'il n'y a pas de signification "exacte", parce que c'est un terme nouveau, et que différents utilisateurs l'utilisent différemment. Cela au moins peut être discerné à partir de l'article de Wikipedia. Certains insistent sur le fait que cela ne s'applique qu'au code "runtime" (les classes intégrées, je suppose), alors que d'autres l'utiliseraient pour faire référence à la modification au moment de l'exécution de n'importe quelle classe.

Personnellement, je préfère la définition plus inclusive. Après tout, si nous utilisions le terme pour modifier uniquement les classes intégrées, comment ferions-nous référence à la modification au moment de l'exécution de toutes les autres classes? L'important pour moi est qu'il existe une différence entre le code source et la classe en cours d'exécution.

En Ruby, le terme patch de singe était incompris comme signifiant toute dynamique modification à une classe et est souvent utilisé comme synonyme de dynamiquement modifier n'importe quelle classe à l'exécution.

La déclaration ci-dessus affirme que l'utilisation de Ruby est incorrecte - mais les termes évoluent et ce n'est pas toujours une mauvaise chose.

43
Joshua Swink

La meilleure explication que j'ai entendue pour Monkey Patch/Duck-punching est de Patrick Ewing dans RailsConf 2007

... s’il marche comme un canard et parle comme un canard, c’est un canard, non? Alors si ce canard ne vous donne pas le bruit que vous voulez, vous devez le faire Il suffit de frapper ce canard jusqu'à ce qu'il retourne à la hauteur de vos attentes.

61
RSK

La correction de singe est quand vous replace méthodes d'une classe à l'exécution (not ajoutant de nouvelles méthodes comme d'autres l'ont décrit). 

En plus d’être un moyen très peu évident et difficile de déboguer pour changer le code, il n’a pas d’échelle; Au fur et à mesure que de plus en plus de modules commencent à appliquer des méthodes de correction de singe, la probabilité que les modifications se mutilent augmente.

18
Paul Betts

L’un des aspects les plus puissants de Ruby est la possibilité de rouvrir n’importe quelle classe et de changer ses méthodes.

Oui, c’est vrai, vous pouvez réellement rouvrir n’importe quelle classe et en changer le fonctionnement. Cela inclut les classes standard Ruby comme 

String, Array or Hash!

Maintenant, c'est évidemment aussi dangereux que cela puisse paraître. Pouvoir modifier le résultat attendu d'une méthode peut entraîner toutes sortes de comportements étranges et rendre difficile la traçabilité des bogues.

Néanmoins, la capacité de «Monkey Patch» n’importe quelle classe est extrêmement puissante. Ruby est comme un couteau tranchant, il peut être extrêmement efficace, mais c’est généralement votre faute si vous vous coupez vous-même.

Pour commencer, nous allons ajouter une méthode pratique pour générer du texte Lorem Ipsum:

class String
  def self.lipsum
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
  end
end

Dans cet exemple, j'ai rouvert la classe de base String et ajouté une méthode de classe lipsum.

String.lipsum
=> "Lorem ipsum dolor sit amet, consectetur adipiscing elit."

Cependant, nous pouvons non seulement ajouter des méthodes à la classe String, mais aussi modifier le comportement des méthodes existantes!

class String
  def upcase
    self.reverse
  end
end

Dans cet exemple, nous détournons la méthode upcase et appelons plutôt la méthode reverse!

"hello".upcase
=> "olleh"

Comme vous pouvez le constater, il est extrêmement facile d’ajouter ou de modifier des méthodes sur une classe existante, même si vous ne possédez pas cette classe ou si elle fait partie du noyau de Ruby.

Quand devriez-vous utiliser Monkey Patching?

Rarement.

Ruby nous fournit une multitude d'outils puissants pour travailler. Cependant, le fait qu'un outil soit puissant ne fait pas de lui l'outil idéal.

Monkey Patching en particulier est un outil extrêmement puissant. Cependant, un puissant outil entre de mauvaises mains provoquera une quantité infinie de douleurs et de souffrances.

Chaque fois que vous soumettez une classe à un singe, vous créez potentiellement un mal de tête à l'avenir, lorsque les choses tournent mal.

Les classes qui ont reçu Monkey Patched sont plus difficiles à comprendre et à déboguer. Si vous ne faites pas attention, le message d'erreur que vous recevrez ne vous donnera probablement que très peu d'indices sur le problème.

Lorsque vous appliquez une méthode au correctif de singe, vous risquez éventuellement de supprimer du code en aval reposant sur ce comportement.

Lorsque vous ajoutez une nouvelle méthode à une classe existante à l'aide de Monkey Patching, vous ouvrez potentiellement des cas Edge étranges qu'il est impossible de prévoir.

Quand est-ce que ça marche avec Monkey Patch?

Cela dit, il ne sert à rien d’avoir des outils puissants comme Monkey Patching si vous ne les utilisez pas réellement.

Il y a des cas où la réouverture d'une classe a du sens.

Par exemple, vous voyez souvent des patchs de singe qui ajoutent simplement une méthode pratique sans effet secondaire. Ruby a une très belle syntaxe et il peut donc être tentant de redonner à une classe de modifier des sonneries pour transformer un appel de méthode moche en quelque chose de plus lisible.

Ou peut-être avez-vous besoin que Monkey Patche une classe que vous possédez.

Monkey Patch convient dans de nombreux cas, mais ce ne devrait certainement pas être votre première arme de choix.

Monkey Patching sera souvent la préférence du développeur fainéant par rapport à la refactorisation ou à la mise en œuvre d’un modèle de conception connu pour un problème particulier.

Ce n’est pas parce que Monkey Patching vous offre une solution simple que vous devez toujours suivre cette voie.

http://culttt.com/2015/06/17/what-is-monkey-patching-in-Ruby/

6
Subhash Chandra

Vous avez raison; c'est lorsque vous modifiez ou étendez une classe existante plutôt que de la sous-classer.

4
davetron5000

Ceci est un patch de singe:

class Float
  def self.times(&block)
    self.to_i.times { |i| yield(i) }
    remainder = self - self.to_i
    yield(remainder) if remainder > 0.0
  end
end

Maintenant, j'imagine que cela pourrait être utile parfois, mais imaginez si vous voyiez la routine.

def my_method(my_special_number)
  sum = 0
  my_special_number.times { |num| sum << some_val ** num }
  sum
end

Et ça casse seulement de temps en temps quand on l’appelle. Pour ceux qui font attention, vous savez déjà pourquoi, mais imaginez que vous ne sachiez pas que le type float possède une méthode de classe .times et que vous supposez automatiquement que my_special_number est un entier. Chaque fois que le paramètre est un nombre entier, un entier ou un flottant, cela fonctionne correctement (les entiers entiers sont renvoyés sauf s'il existe un reste en virgule flottante). Mais passez un nombre avec n'importe quoi dans la zone décimale et ça va casser à coup sûr!

Imaginez combien de fois cela peut arriver avec vos gemmes, vos plugins Rails et même vos propres collègues dans vos projets. S'il y a une ou deux petites méthodes comme celle-ci et que cela pourrait prendre un certain temps à trouver et à corriger.


Si vous vous demandez pourquoi il se rompt, notez que sum est un entier et qu'un reste en virgule flottante peut être renvoyé; De plus, le signe exponentiel ne fonctionne que lorsque les types sont identiques. Vous pouvez donc penser que c'est réglé, parce que vous avez converti des nombres dérangeants en nombres flottants ... seulement pour constater que la somme ne peut pas prendre le résultat en virgule flottante.

3
Robert K

En Python, monkeypatching est souvent considéré comme un signe d'embarras: "Je devais monkeypatch cette classe parce que ..." (je l'ai rencontré en premier lorsque j'ai parlé à Zope, que l'article mentionne). On avait l'habitude de dire qu'il était nécessaire de prendre le contrôle d'une classe en amont et de le réparer au moment de l'exécution au lieu de faire du lobbying pour corriger les comportements indésirables dans la classe réelle ou pour les corriger dans une sous-classe. D'après mon expérience, les gens de Ruby ne parlent pas beaucoup de monkeypatching, parce que ce n'est pas considéré comme particulièrement mauvais ni même remarquable (d'où le "poinçon de canard"). Évidemment, vous devez faire attention à ne pas modifier les valeurs de retour d'une méthode qui sera utilisée dans d'autres dépendances, mais l'ajout de méthodes à une classe comme le font active_support et les facettes est parfaitement sécurisé. 

Mise à jour 10 ans plus tard : Je modifierais la dernière phrase pour dire "est relativement sûr". L'extension d'une classe de bibliothèque principale avec de nouvelles méthodes peut poser des problèmes si quelqu'un d'autre a la même idée et ajoute la même méthode avec une implémentation ou une signature de méthode différente, ou si les gens confondent les méthodes étendues pour les fonctionnalités du langage principal. Les deux cas se produisent souvent dans Ruby (en particulier en ce qui concerne les méthodes active_support).

2
method

Habituellement, il est question de modifications ad-hoc, en utilisant les classes ouvertes Ruby, souvent avec un code de qualité médiocre.

Bon suivi sur le sujet:

http://www.infoq.com/articles/Ruby-open-classes-monkeypatching

1
maurycy

Explication du concept sans code:

Discussion du concept exact est waaaay trop académique et nuancé qu'il a besoin. Restons simples avec l'exemple suivant:

Le fonctionnement normal d'une voiture

Comment démarrez-vous normalement une voiture? C’est simple: vous mettez le contact, la voiture démarre et le tour est joué!

Singe patcher une voiture

Mais que se passe-t-il si quelqu'un d'autre a fabriqué la voiture et si vous voulez changer son fonctionnement? 

Vous n’avez pas besoin de vous rendre à l’usine de fabrication de voitures pour effectuer ces modifications: vous pouvez simplement le corriger, en passant sous le capot et en réinstallant clandestinement et discrètement des objets et en ajoutant quelques incideniaries ici et là. Vous devez vraiment savoir ce que vous faites lorsque vous faites cela, sinon les résultats pourraient être assez explosifs - et c’est peut-être exactement ce que vous voulez? 

Fabrizzio, où vas-tu?

Boom!

 Monday, Tuesday, Wed-nes-day, Thursday, Friday, Sat-a-day. Image is free and open source from unsplash - https://unsplash.com/photos/dyrehVIidQk

"Gardez votre code source proche, mais vos correctifs de singe plus proches."

0
BKSpurgeon