2010-07-03 17 views
1

Je voudrais obtenir ce qui suit en introduisant un nouvel opérateur (par exemple :=)Comment créer un opérateur pour la copie/le clonage profond d'objets dans Ruby?

a := b = {} 
b[1] = 2 
p a # => {} 
p b # => {1=>2} 

Pour autant que je comprends, je dois modifier la Object classe, mais je ne sais pas quoi faire pour pour obtenir ce que je veux.

require 'superators' 
class Object 
    superator ":=" operand # update, must be: superator ":=" do |operand| 
    # self = Marshal.load(Marshal.dump(operand)) # ??? 
    end 
end 

Pourriez-vous m'aider?


Mise à jour

Ok, superators ne sera probablement pas me aider, mais je veux encore tel opérateur. Comment puis-je (ou vous) créer une extension pour Ruby, que je pourrais charger en tant que module?

require 'deep_copy_operator' 
a !?= b = {} # I would prefer ":=" but don't really care how it is spelled 
b[1] = 2 
p a # => {} 
p b # => {1=>2} 

Répondre

2

Tout d'abord, la syntaxe pour superators est

superator ":=" do |operand| 
    #code 
end 

Il est un bloc, parce que superator est une macro métaprogrammation.

Deuxièmement, vous avez quelque chose qui va avec Marshal ... mais c'est un peu magique. N'hésitez pas à l'utiliser tant que vous comprenez exactement ce que vous faites. Troisièmement, ce que vous faites n'est pas tout à fait faisable avec un superateur (je crois), car self ne peut pas être modifié pendant une fonction. (si quelqu'un sait le contraire, s'il vous plaît faites le moi savoir)

Aussi, dans votre exemple, a doit d'abord exister et être défini avant d'être en mesure d'appeler la méthode := dedans.

Votre meilleur pari est probablement:

class Object 
    def deep_clone 
    Marshal::load(Marshal.dump(self)) 
    end 
end 

pour produire un clone profond d'un objet.

a = (b = {}).deep_clone 
b[1] = 2 
p a # => {} 
p b # => {1=>2} 
+2

Sûrement l'opérande va après le faire, non? Parce que c'est un argument de bloc? – Chuck

+0

Ok, merci, ça doit être une méthode de block not. Utiliser 'deep_clone' aiderait, mais cela le rend désordonné, surtout si on n'a pas 2 mais 5 hachages à initialiser. Donc, je suis vraiment curieux de faire un tel opérateur. – Andrei

+0

@chuck - Vous avez raison; J'ai fait une faute de frappe; @Andrei - C'est impossible sans être vraiment en désordre, parce que vous voulez fondamentalement modifier 'self', ainsi qu'appeler une méthode sur un objet qui n'est pas encore défini. –

3

wow, superators look soigné! Mais malheureusement, cela ne fonctionnera pas pour vous, pour deux raisons. D'abord, votre opérateur ne correspond pas à la regex (vous ne pouvez pas utiliser deux-points). Assez facile, trouvez un nouvel opérateur. Mais le second que je ne pense pas pouvoir surmonter, le superateur est essentiellement un nom de méthode défini sur l'objet à gauche. Vous ne pouvez donc pas l'utiliser pour les instructions d'affectation. Si votre variable n'est pas définie, vous ne pouvez pas l'utiliser, cela provoquerait une erreur. Et si elle est définie, alors vous ne pouvez pas changer son type de façon évidente pour moi (peut-être avec un certain niveau de réflexion et de métaprogrammation qui est bien au-delà de tout ce que je sais, mais cela semble honnêtement improbable ... Je n'aurais jamais pensé qu'il serait possible de créer des superateurs, alors qui sait). Donc, je pense que vous êtes de retour à pirater et à reconstruire votre Ruby.

+0

Merci encore, Joshua! J'ai encore un peu d'espoir que l'on puisse créer un tel opérateur sans recompiler Ruby. Sinon, mon code sera plus difficile à utiliser par d'autres personnes. Mon espoir est que l'on peut faire un module/gemme, que d'autres peuvent installer et activer un tel opérateur. – Andrei