|
NAMEClone::More - Natively copying Perl data structuresSYNOPSISuse Clone::More qw( clone ); my $structure = [ { 'key' => 'value' } ]; for my $set ( @$structure ) { my $clone = clone( $set ); for ( keys %$clone ) { print "Everything matches" if ( exists( $set->{$_} ) && $set->{$_} eq $clone->{$_} ); } } DESCRIPTIONThis is intended to act as a utility in order to natively clone data structures via a simple Perl interface. Will ensure that all references will be separated from the parent data strure, yet kept relative to the new structure (if need be).Please take a look at the WARNINGS, GOTCHAS and FUTURE DEVELOPMENT sections, as resources to see if this module is fully capable of doing everything that you want it to do (and it will do most everything). HISTORY"Clone::More" originally began as a patch for the "Clone" module. It was found, with a group I was working with at the time, that there was a pretty noticiable memory leak in the module while cloning massively complex Perl data structures. In an attempt to find the source of the leak and subit the path to the Clone author, Ray Finch, it took a complete overhaul in order for me to stop the leak. Since then, I have been working with Ray Finch to see what we can work out in getting "Clone" up to date with the patches I have applied. Unfortunately, we have fallen out of contact and arrose the counterpart to this module, Clone::Fast. From there, I added more programatic functionality, deviating from the simplicity of Clone::Fast and Clone alike. Thus, "Clone::More" was born!EXPORTcloneClone is the primary function from within the provided module. By passing a scalar reference to this routine, you will expect to get a returned scalar reference that will no longer have any reference to the originating reference. However, references deeper into the structure will still uphold the references within the structure. Example being: use Clone::More qw( clone ); my $foo = { 'a' => 'b' }; my $bar = { 'a' => $foo, 'b' => $foo }; my $baz = clone( $bar ); print "\$foo and \$bar are different references\n" if ( $foo ne $bar ); print "\$foo->{'a'} and \$bar->{'a'} are different references\n" if ( $foo->{'a'} ne $bar->{'a'} ); print "\$foo->{'a'} and \$foo->{'b'} are the same, however\n" if ( $foo->{'a'} eq $bar->{'b'} ); This makes sense, although this can be modified as well. By using the internal variable, BREAK_REFS, you are also allowed to break internal references (may break up circular references, although won't fix the circular reference in the originating reference). circular Given a single data structure, will return a boolean value indicating wether or not there is a circular reference embedded within the structure. use Clone::More qw( circular ); my @a; $a[0] = \@a; my @b; $b[0] = { 'key' => 'value' }; # Will print '@a has a circular reference' print ( ( circular( \@a ) ) ? "\@a has a circular reference\n" : "\@a has NO circular reference\n" ); # Will print '@b has NO circular reference' print ( ( circular( \@b ) ) ? "\@b has a circular reference\n" : "\@b has NO circular reference\n" ) NOTE (Same will apply for "is_circular"): Circular references are a little tricky. "Clone::More", currently, has an embedded ability to find some in most cases. However, there still remains the fact that it is quite tricky to seperate a circular reference from a normal reference set. Therefore, the difference between: my $circular = [ qw( one two ) ]; $circular->[2] = \$r; $circular->[3] = \$r; $circular->[4] = \$r; and: my $not_circ = [ qw( one two ) ]; my $wth_circ = [ qw( one two ) ]; $r->[2] = \$wth_circ; $r->[3] = \$wth_circ; $r->[4] = \$wth_circ; Are very subtile, yet very profound. One will cause a very fast circular memory leak, due to the circular reference, while the other will not; being there is no circular reference. Therefore, the reliability of these tests may still leave something yet to be desired. I will continue development on these exported functions until I am more confident about their behavior. is_circular Is an alias for "Clone::More::circular". Makes for more aesthetically pleasing programming. More 'self documenting' then "Clone::More::circular". Therefore: use Clone::More qw( circular is_circular ); my @a; $a[0] = \@a; my @b; $b[0] = { 'key' => 'value' }; print "1" if ( circular( \@a ) == is_circular( \@a ) ); print "1" if ( circular( \@b ) == is_circular( \@b ) ); print "0" if ( circular( \@a ) == is_circular( \@b ) ); print "\n"; # You will see the following printed to STDOUT: # '110' PROGRAMATIC HOOKSMuch like the Perl Storable module (available in all current Perl distributions), "Clone::More" allows for hooks that will be accessed when cloning any object that has a hook defined. This can be very handy where Inside Out objects would not normally be cloned. WHHAAATT???? What I mean is, only the reference of an object will be cloned, not the internal stash of the object. Therefore, accessors that are defined within an inside out object will not be cloned. There is no real safe way to do this, with the exception of cloning the entire class stash, breaking more things than it will fix. Again, the reference of the object will be fully cloned, and the object it's self will be a new reference, although it will be an empty object. Subsiquently, such as most inside out objects, the blessed reference is of a scalar type; an integer indicating the object id. When cloning this, you would end up with two objects of the same type with the same object id. The hooks have been added in an attempt to prevent this from happening.CLONEMORE_cloneAgain, much like Storable (though a little better, I hope), the function will be called *AFTER* the clone operation has completed on the object being cloned. The routine will have two scalar references passed via the stack, representing both the cloned object as well as the source of the clone. This *should* allow for the programatic manipulation of the object before it gets returned to the caller, or placed into the refering structure.As an example, I will use the following object to define a 'hooked' object: package Hookable; use strict; use warnings; use Clone::More qw( clone ); sub new { bless {}, shift } sub CLONEMORE_clone { # Where clone is the cloned object from the source, where source # was the originating reference my ( $clone, $source ) = @_; # I am going to pretend the source has a list of defined methods, # of which I want to clone and transfer to the clone; outside # of the blessed hash-refrence that is the source of the object $clone->$_( clone( $source->$_() ) ) for ( qw( get_method_1 get_method_2 get_method_3 ) ); # At this point, the cloned object will also have a set of cloned # fields from the source. If, by chance, any of the values of the # defined attribtes are other 'Hookable' objects, the same routine # will be called on that object as well. # The API requires me to return the new $clone, this will be returned to # the caller return $clone; } Using the package from above, I will now use an example of a script where I will demonstrate how the whole thing comes together: #!/usr/bin/perl -w use strict; use Clone::More qw( clone ); my $hookable = Hookable->new(); $hookable->{'hash_stuff'} = 'some value'; my $structure = { 'hookable' => $hookable, 'new' => Hookable->new(), 'deeply' => { 'hookable' => $hookable, 'new' => Hookable->new(); }, }; my $cloned = clone( $sturcture ); This script will demonstrate a number of things. 1.) "Clone::More::clone" will, automagically call the hook on all instances of the Hookable. Though the hash_stuff key will automatically be cloned before the hook is ever called. Subsiquently, the hashes in both values of hookable in the hash will be references of one another, though not references to the originating object. The Hookable->new() object, on the other hand, will not be referenced to anything of the similar like. As a secondary note, it was originally thought to allow for hooks to show up before and after the cloning of the object. Though, that would allow for the full change of the cloning type; this would be very bad. Also, given that it is somewhat reasonable to believe hooks will only be used with inside out objects, we can also assume the cloning of a simple referent will be so lightweight that there will still be the benifit of having clone hook into the object. If anyone has beef with this paradigm, let me know and I'll change it. CONFIGURATION VARIABLES
EXAMPLES
GOTCHAS/WARNINGS
OPTIMIZATION HACKSI have, and will contiue to, wrap all the new features into easily optimized "#ifdef" conditions. Where each new feature will have it's own definition, where commenting out of the definition will allow for much less processing. Using this is the pure basis of Clone (more details within the Clone docs), whereas all of the new functionality found in "Clone::More" is optimized out for a much faster Clone.I'm not going to explain much more, though if you are relitively tuned up in your C, you can take a gander at the XS implementation and play around with it if you'd like! SEE ALSO
AUTHORTrevor Hall, <wazzuteke@cpan.org>COPYRIGHT AND LICENSECopyright (C) 2006 by Trevor HallThis library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Visit the GSP FreeBSD Man Page Interface. |