J'ai fait quelques recherches pour trouver différentes méthodes et publications sur la création d'un opérateur de copie en profondeur.
Existe-t-il un moyen rapide et facile (intégré) de copier en profondeur des objets dans Ruby? Les champs ne sont pas des tableaux ou des hachages.
Travailler dans Ruby 1.9.2.
La copie profonde n'est pas intégrée à Vanilla Ruby, mais vous pouvez la pirater en organisant et en désarchivant l'objet:
Marshal.load(Marshal.dump(@object))
Ce n'est pas parfait cependant, et ne fonctionnera pas pour tous les objets. Une méthode plus robuste:
class Object
def deep_clone
return @deep_cloning_obj if @deep_cloning
@deep_cloning_obj = clone
@deep_cloning_obj.instance_variables.each do |var|
val = @deep_cloning_obj.instance_variable_get(var)
begin
@deep_cloning = true
val = val.deep_clone
rescue TypeError
next
ensure
@deep_cloning = false
end
@deep_cloning_obj.instance_variable_set(var, val)
end
deep_cloning_obj = @deep_cloning_obj
@deep_cloning_obj = nil
deep_cloning_obj
end
end
La source:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/Ruby/ruby-list/43424
J'ai créé une implémentation native pour effectuer des clones profonds d'objets Ruby.
C'est environ 6 à 7 fois plus rapide que l'approche du maréchal.
https://github.com/balmma/Ruby-deepclone
Notez que ce projet n'est plus maintenu (dernière validation en 2017 , il y a un rapport problèmes )
Rails a une méthode récursive nommée deep_dup
qui renverra une copie complète d'un objet et, contrairement à dup
et clone
, fonctionne même sur des objets composites (tableau/hachage de tableaux/hachages). C'est aussi simple que:
def deep_dup
map { |it| it.deep_dup }
end
Il existe une implémentation native pour effectuer des clones profonds d'objets Ruby: Ruby_deep_clone
Installez-le avec gem:
gem install Ruby_deep_clone
Exemple d'utilisation:
require "deep_clone"
object = SomeComplexClass.new()
cloned_object = DeepClone.clone(object)
C'est environ 6 à 7 fois plus rapide que l'approche du maréchal et l'événement fonctionne avec des objets gelés.
Notez que ce projet n'est plus maintenu (dernière validation en 2017 , il y a un rapport problèmes )
Vous pouvez utiliser un bijou en double pour cela.
C'est un petit Ruby gem qui peut dupliquer récursivement un objet. Il dupliquera aussi ses références d'objet à la nouvelle duplication.
require 'duplicate'
duplicate('target object')
Je vous suggère d'utiliser la gemme ActiveSupport qui ajoute beaucoup de sucre à votre noyau Ruby core, pas seulement une méthode clone profond ).
Vous pouvez consulter la documentation pour plus d'informations sur les méthodes qui ont été ajoutées.
Le clone profond automatique n'est pas toujours ce que vous voulez. Souvent, vous devez définir quelques attributs sélectionnés à cloner en profondeur. Une manière flexible de le faire consiste à implémenter le initialize_copy
, initialize_dup
et initialize_clone
méthodes.
Si vous avez un cours:
class Foo
attr_accessor :a, :b
end
et vous ne voulez que cloner en profondeur :b
, vous remplacez le initialize_*
méthode:
class Foo
attr_accessor :a, :b
def initialize_dup(source)
@b = @b.dup
super
end
end
Bien sûr, si vous voulez @b
pour cloner en profondeur certains de ses propres attributs, vous faites de même dans la classe b.
Rails fait cela (voir https://github.com/Rails/rails/blob/0951306ca5edbaec10edf3440d5ba11062a4f2e5/activemodel/lib/active_model/errors.rb#L78 )
Pour une explication plus complète, je l'ai appris ici de ce post https://aaronlasseigne.com/2014/07/20/know-Ruby-clone-and-dup/
Consultez également deep_dive. Cela vous permet de faire des copies approfondies contrôlées de vos graphiques d'objets.
Vous n'avez vraiment pas besoin d'un Gem pour cela. Cela ne pourrait pas être beaucoup plus simple que cela, ce qui ne vaut pas les frais généraux d'un Gem!
def deep_clone(obj)
obj.clone.tap do |new_obj|
new_obj.each do |key, val|
new_obj[key] = deep_clone(val) if val.is_a?(Hash)
end
end
end