2016-06-12 1 views
2

J'utilise Pharo 5.0. Dans quelques cas, j'ai trouvé une limite ou peut-être un bug dans une classe Pharo existante (par exemple, quelque chose dans DBXTalk/Garage, ou Regex-Core). Je voudrais être en mesure de modifier un sélecteur ou un ensemble de sélecteurs existant dans une classe en dehors de mon propre projet et de faire cette partie de mon paquet.Comment remplacer un sélecteur existant dans une classe dans un autre paquet

J'ai trouvé plusieurs instructions sur la façon de créer un nouveau sélecteur dans une classe à l'extérieur et se déplacer que dans mon paquet (par exemple , comme le montre cette tutorial). C'est très cool. Mais dans certains cas, je veux réellement modifier un sélecteur existant dans la classe extérieure et avoir ma copie de ce sélecteur remplacer celle de la classe extérieure quand je l'utilise. Je ne souhaite pas modifier le package pré-fourni par un tiers ou Pharo existant.

Dans GNU Smalltalk, je peux le faire tout comme une partie normale de l'extension d'une classe. Par exemple:

Kernel.MatchingRegexResults extend [ 
    at: anIndex [ 
     "My updated version of the 'official' Kernel.MatchingRegexResults#at: selector" 
     "This is part of my package so overrides the 'official' version" 
     ... 
    ] 

    foo [ 
     "My new foo selector" 
    ] 
] 

Comment puis-je faire cela dans Pharo 5.0? J'ai fait pas mal de recherches mais je n'ai pas trouvé de moyen de le faire. Les mots "extend" ou "override" n'apparaissent pas dans le Pharo par l'exemple et dans les livres de Pharo.

+1

Avez-vous essayé la commande * Move to package ... *? Il est disponible dans le menu contextuel de la liste de sélection. –

+0

@LeandroCaniglia oui je l'ai fait. En fait, je l'ai mentionné dans ma question. Le déplacement fonctionne très bien si je veux créer un nouveau sélecteur pour une classe externe existante et déplacer ce nouveau sélecteur dans mon paquet. Mais cela ne fonctionne pas pour modifier/remplacer un sélecteur existant car il va déplacer l'implémentation de ce sélecteur dans mon paquet et le retirer de l'externe. Je ne veux pas supprimer le sélecteur surchargé du package externe, mais je souhaite simplement le remplacer. – lurker

+1

Override signifie override ... vous réécrire la méthode, elle sera déplacée dans votre paquet, mais elle sera modifiée pour tout le système. Pharo n'a pas de système de modules, donc vous ne pouvez pas avoir différentes méthodes avec le même nom dans la même classe ... – EstebanLM

Répondre

2

Le code dans la syntaxe GNU Smalltalk

Kernel.MatchingRegexResults extend [ 
    at: anIndex [ 
     "method body" 
    ] 
    foo [ 
     "My new foo selector" 
    ] 
] 

ressemblerait à ceci

!MatchingRegexResults methodsFor: 'protocol'! 
at: anIndex 
    "method body" 
! 
foo 
    "My new foo selector" 
! ! 

dans un jeu de changement Pharo qui peut être déposé dans du navigateur de fichiers.

Cependant, veuillez noter que dans les deux cas, GNU Smalltalk et Pharo Smalltalk, vous remplacez la version originale de la méthode dans cette classe. Dans GNU Smalltalk, vous n'êtes peut-être pas habitué à enregistrer l'image. Vous pouvez donc penser que la syntaxe extend ne modifie pas la méthode d'origine dans la classe d'origine.

En fait, c'est ce qu'il fait exactement. Avec GNU Smalltalk, vous commencez généralement avec la même vieille image non modifiée à chaque fois que vous exécutez gst.

Cela est dû au fait que l'emplacement par défaut de l'image dans GNU Smalltalk n'est pas accessible en écriture pour l'utilisateur normal. Donc, gst lit la même image en lecture seule à chaque fois, vous la modifiez en mémoire avec des définitions de classe et des extensions, votre image modifiée ne vit que temporairement pendant que votre programme est en cours d'exécution et est supprimée à la sortie du programme.

+0

Je suppose que du point de vue de la gestion des changements, la meilleure chose à faire est probablement de déplacer le sélecteur modifié dans mon paquet, comme @ LeandroCaniglia dit dans son commentaire, même si cela signifie modifier le paquet existant pour le déplacer. Au moins, il est facile de garder une trace de. Si je voulais partager ce paquet et que quelqu'un d'autre essayait de l'utiliser, celui modifié dans mon paquet remplace celui de leur paquet standard? Ou cela dépend-il seulement du paquet qui a été mis à jour dans son environnement en dernier? – lurker

+1

Il ne peut y avoir qu'une seule version d'une méthode dans une classe. La version de la méthode la plus récemment chargée devient la version actuelle. Le protocole étoilé sert uniquement à regrouper les méthodes d'extension dans un package différent pour le navigateur système et le navigateur Monticello. La méthode reste partie de la même classe quel que soit le paquet. –

+0

À droite, mais s'il est défini dans plusieurs paquets, lequel "gagne"? Est-ce basé sur l'ordre de la charge de l'emballage? Lorsque je redéfinis un paquet X défini par un sélecteur dans mon paquet Y, je comprends que la version Y le remplace. Mais si je charge par la suite une version plus récente du paquet X, est-ce que la version Y si le sélecteur est remplacé par cette version plus récente? Ou est-ce simplement ignoré et ma version du paquet Y reste? – lurker

3

Veuillez noter qu'en plus de ce que Milan Vavra a écrit, toutes les méthodes d'un protocole nommé *YourPackage-(something) appartiendront au paquet YourPackage, quel que soit le paquet auquel la classe appartient. Au moins dans Squeak, il y a la convention de mettre des méthodes surchargées comme ça dans le protocole *YourPackage-override. Pharo a probablement une convention de nommage similaire. La fonction Déplacer vers un package déplace la méthode vers un tel protocole "étoilé".

Toutefois, il est déconseillé d'utiliser de telles substitutions car vous ne pouvez pas avoir deux packages fournissant simultanément une implémentation pour la même méthode.Monticello essayera de conserver à la fois la méthode originale et la méthode prioritaire (voir les expéditeurs de PackageInfo>>isOverrideCategory:), mais il est toujours possible que votre méthode de remplacement soit remplacée par des mises à jour de son package original ou vous manquerez des mises à jour de la méthode originale. . La «bonne manière» est de refactoriser la méthode originale dans l'emballage d'origine pour rendre son comportement plus facilement personnalisable.

+0

Oui, je comprends cela. Malheureusement, il y a quelques cas où un paquet dont j'ai besoin, mais qui n'a pas écrit, a un bug ou manque d'une capacité fondamentale. Dans ces cas, il n'y a pas de petit problème, mais de modifier le paquet. Quand je fais cela, je veux être capable de le suivre facilement. Un exemple est d'avoir une [Chaîne de capture dans le remplacement de regex] (http://stackoverflow.com/questions/37403092/capture-string-in-regex-replacement) (amélioration). Un autre est dans DBXTalk/Garage, il donne une erreur quand un attribut entier est NULL dans la base de données (devrait retourner 'nil'). – lurker

+0

Bien sûr, à court terme, il n'y a généralement pas de solution (si vous ne voulez pas envoyer d'autres messages). Mais je voulais aussi le signaler aux autres lecteurs qui viennent ici. :-) – JayK

+0

En effet! Merci de l'avoir signalé. – lurker