File Coverage

blib/lib/Data/Walk/Clone.pm
Criterion Covered Total %
statement 34 38 89.4
branch 8 10 80.0
condition 4 6 66.6
subroutine 9 10 90.0
pod 2 2 100.0
total 57 66 86.3


line stmt bran cond sub pod time code
1             package Data::Walk::Clone;
2             our $AUTHORITY = 'cpan:JANDREW';
3 3     3   6083 use version; our $VERSION = version->declare('v0.28.0');
  3         4  
  3         16  
4             ###InternalExtracteDClonE warn "You uncovered internal logging statements for Data::Walk::Clone-$VERSION";
5             ###InternalExtracteDClonE use Data::Dumper;
6 3     3   285 use 5.010;
  3         8  
7 3     3   9 use utf8;
  3         3  
  3         48  
8 3     3   54 use Moose::Role;
  3         18  
  3         19  
9             requires qw(
10             _process_the_data _dispatch_method _get_had_secondary
11             );
12 3     3   10703 use MooseX::Types::Moose qw( HashRef Bool );
  3         5  
  3         29  
13              
14             #########1 Package Variables 3#########4#########5#########6#########7#########8#########9
15              
16             $| = 1;
17             my $clone_keys = {
18             donor_ref => 'primary_ref',
19             };
20              
21             #########1 Dispatch Tables 3#########4#########5#########6#########7#########8#########9
22              
23             my $seed_clone_dispatch ={######<------------------------------------ ADD New types here
24             ARRAY => sub{
25             unless( exists $_[1]->{secondary_ref} ){
26             $_[1]->{secondary_ref} = [];
27             }
28             return $_[1];
29             },
30             HASH => sub{
31             unless( exists $_[1]->{secondary_ref} ){
32             $_[1]->{secondary_ref} = {};
33             }
34             return $_[1];
35             },
36             OBJECT => sub{
37             unless( exists $_[1]->{secondary_ref} ){
38             $_[1]->{secondary_ref} = bless( {}, ref $_[1]->{primary_ref} );
39             }
40             return $_[1];
41             },
42             SCALAR => sub{
43             $_[1]->{secondary_ref} = $_[1]->{primary_ref};
44             return $_[1];
45             },
46             name => 'seed_clone_dispatch',#Meta data
47             };
48              
49             #########1 Public Attributes 3#########4#########5#########6#########7#########8#########9
50              
51             has 'should_clone' =>(
52             isa => Bool,
53             writer => 'set_should_clone',
54             reader => 'get_should_clone',
55             predicate => 'has_should_clone',
56             default => 1,
57             );
58              
59             #########1 Public Methods 3#########4#########5#########6#########7#########8#########9
60              
61             sub deep_clone{#Used to convert names for Data::Walk:Extracted
62             ###InternalExtracteDClonE warn "Made it to deep_clone with input:" . Dumper( @_ );
63 23     23 1 4007 my $self = $_[0];
64             my $passed_ref =
65             ( @_ == 2 ) ?
66 23 50 66     80 ( ( is_HashRef( $_[1] ) and exists $_[1]->{donor_ref} ) ?
    100          
67             $_[1] : { donor_ref => $_[1] } ) :
68             { @_[1 .. $#_] } ;
69             ###InternalExtracteDClonE warn "transformed hashref:" . Dumper( $passed_ref );
70             @$passed_ref{
71 23         2142 'before_method', 'after_method',
72             } = (
73             '_clone_before_method', '_clone_after_method',
74             );
75             ###InternalExtracteDClonE warn "Start recursive parsing with:" . Dumper( $passed_ref );
76 23         60 $passed_ref = $self->_process_the_data( $passed_ref, $clone_keys );
77 23         579 $self->_set_first_pass( 1 );# Re-set
78             ###InternalExtracteDClonE warn "End recursive parsing with:" . Dumper( $passed_ref );
79 23         91 return $passed_ref->{secondary_ref};
80             }
81              
82             sub clear_should_clone{
83             ###InternalExtracteDClonE warn "turn cloning back on at clear_should_clone ...";
84 0     0 1 0 my ( $self, ) = @_;
85 0         0 $self->set_should_clone( 1 );
86 0         0 return 1;
87             }
88              
89             #########1 Private Attributes 3#########4#########5#########6#########7#########8#########9
90              
91             has '_first_pass' =>(
92             isa => Bool,
93             writer => '_set_first_pass',
94             reader => '_get_first_pass',
95             default => 1,
96             );
97              
98             #########1 Private Methods 3#########4#########5#########6#########7#########8#########9
99              
100             sub _clone_before_method{
101 103     103   79 my ( $self, $passed_ref ) = @_;
102             ###InternalExtracteDClonE warn "reached _clone_before_method with input:" . Dumper( $passed_ref );
103 103 100       2617 if( $self->_get_first_pass ){
104             ###InternalExtracteDClonE warn "perform a one time test for should_clone ...";
105 23 50       563 if( !$self->get_should_clone ){
106             ###InternalExtracteDClonE warn "skipping level now ...";
107 0         0 $passed_ref->{skip} = 'YES';
108             }else{
109             ###InternalExtracteDClonE warn "turn on one element of cloning ...";
110 23         617 $self->_set_had_secondary( 1 );
111             }
112 23         575 $self->_set_first_pass( 0 );
113             }
114 103         178 return $passed_ref;
115             }
116              
117             sub _clone_after_method{
118 103     103   75 my ( $self, $passed_ref ) = @_;
119             ###InternalExtracteDClonE warn "reached _clone_after_method with input:" . Dumper( $passed_ref );
120             ###InternalExtracteDClonE warn "should clone?:" . $self->get_should_clone;
121 103 100 66     2570 if( $self->get_should_clone and
122             $passed_ref->{skip} eq 'NO' ){
123             ###InternalExtracteDClonE warn "seeding the clone as needed for: $passed_ref->{primary_type}";
124             $passed_ref = $self->_dispatch_method(
125             $seed_clone_dispatch,
126             $passed_ref->{primary_type},
127 94         197 $passed_ref,
128             );
129             }else{
130             # Eliminating the clone at this level
131 9         14 $passed_ref->{secondary_ref} = $passed_ref->{primary_ref};
132             }
133             ###InternalExtracteDClonE warn "the new passed_ref is:" . Dumper( $passed_ref );
134 103         170 return $passed_ref;
135             }
136              
137             #########1 Phinish Strong 3#########4#########5#########6#########7#########8#########9
138              
139 3     3   10948 no Moose::Role;
  3         5  
  3         12  
140              
141             1;
142             # The preceding line will help the module return a true value
143              
144             #########1 Main POD starts 3#########4#########5#########6#########7#########8#########9
145              
146             __END__
147              
148             =head1 NAME
149              
150             Data::Walk::Clone - deep data cloning with boundaries
151              
152             =head1 SYNOPSIS
153              
154             #!perl
155             use Moose::Util qw( with_traits );
156             use lib '../lib';
157             use Data::Walk::Extracted;
158             use Data::Walk::Clone;
159             use MooseX::ShortCut::BuildInstance qw( build_instance );
160              
161             my $dr_nisar_ahmad_wani = build_instance(
162             package => 'Clone::Camels',
163             superclasses =>['Data::Walk::Extracted'],
164             roles =>[ 'Data::Walk::Clone' ],
165             skip_node_tests =>[ [ 'HASH', 'LowerKey2', 'ALL', 'ALL' ] ],
166             );
167             my $donor_ref = {
168             Someotherkey => 'value',
169             Parsing =>{
170             HashRef =>{
171             LOGGER =>{
172             run => 'INFO',
173             },
174             },
175             },
176             Helping =>[
177             'Somelevel',
178             {
179             MyKey =>{
180             MiddleKey =>{
181             LowerKey1 => 'lvalue1',
182             LowerKey2 => {
183             BottomKey1 => 'bvalue1',
184             BottomKey2 => 'bvalue2',
185             },
186             },
187             },
188             },
189             ],
190             };
191             my $injaz_ref = $dr_nisar_ahmad_wani->deep_clone(
192             donor_ref => $donor_ref,
193             );
194             if(
195             $injaz_ref->{Helping}->[1]->{MyKey}->{MiddleKey}->{LowerKey2} eq
196             $donor_ref->{Helping}->[1]->{MyKey}->{MiddleKey}->{LowerKey2} ){
197             print "The data is not cloned at the skip point\n";
198             }
199            
200             if(
201             $injaz_ref->{Helping}->[1]->{MyKey}->{MiddleKey} ne
202             $donor_ref->{Helping}->[1]->{MyKey}->{MiddleKey} ){
203             print "The data is cloned above the skip point\n";
204             }
205              
206             #####################################################################################
207             # Output of SYNOPSIS
208             # 01 The data is not cloned at the skip point
209             # 02 The data is cloned above the skip point
210             #####################################################################################
211              
212             =head1 DESCRIPTION
213              
214             This L<Moose::Role> contains methods for implementing the method L<deep_clone
215             |/deep_clone( $arg_ref|%args|$data_ref )> using L<Data::Walk::Extracted>. This method is
216             used to deep clone (clone many/all) levels of a data ref. Deep cloning is accomplished by
217             sending a 'donor_ref' that has data nodes that you want copied into a different memory
218             location. In general Data::Walk::Extracted already deep clones any output as part of its
219             data walking so the primary value of this role is to manage deep cloning boundaries. It may
220             be that some portion of the data should maintain common memory references to the original
221             memory references and so all of the Data::Walk::Extracted skip methods will be recognized
222             and supported. Meaning that if a node is skipped the data reference will be copied directly
223             rather than cloned. The deep clone boundaries are managed using the L<skip attributes
224             |https://metacpan.org/module/Data::Walk::Extracted#skipped_nodes> in Data::Walk::Extracted.
225              
226             =head2 USE
227              
228             This is a L<Moose::Role> specifically designed to be used with L<Data::Walk::Extracted
229             |https://metacpan.org/module/Data::Walk::Extracted#Extending-Data::Walk::Extracted>.
230             It can be combined at run time with L<Moose::Util> or L<MooseX::ShortCut::BuildInstance>.
231              
232             =head1 Attributes
233              
234             Data passed to -E<gt>new when creating an instance. For modification of these attributes
235             see L<Methods|/Methods>. The -E<gt>new function will either accept fat comma lists or a
236             complete hash ref that has the possible attributes as the top keys. Additionally
237             some attributes that have all the following methods; get_$attribute, set_$attribute,
238             has_$attribute, and clear_$attribute, can be passed to L<deep_clone
239             |/deep_clone( $arg_ref|%args|$data_ref )> and will be adjusted for just the run of that
240             method call. These are called 'one shot' attributes. The class and each role (where
241             applicable) in this package have a list of 'supported one shot attributes'.
242              
243             =head2 should_clone
244              
245             =over
246              
247             B<Definition:> There are times when the cloning needs to be turned off. This
248             is the switch. If this is set to 0 then deep_clone just passes the doner ref back.
249              
250             B<Default> undefined = everything is cloned
251              
252             B<Range> Boolean values (0|1)
253              
254             =back
255              
256             =head2 (see also)
257              
258             L<Data::Walk::Extracted|https://metacpan.org/module/Data::Walk::Extracted#Attributes>
259             Attributes
260              
261             =head1 Methods
262              
263             =head2 deep_clone( $arg_ref|%args|$data_ref )
264              
265             =over
266              
267             B<Definition:> This takes a 'donor_ref' and deep clones it.
268              
269             B<Accepts:> either a single data reference or named arguments
270             in a fat comma list or hashref
271              
272             =over
273              
274             B<Hash option> - if data comes in a fat comma list or as a hash ref
275             and the keys include a 'donor_ref' key then the list is processed as such.
276              
277             =over
278              
279             B<donor_ref> - this is the data reference that should be deep cloned - required
280              
281             B<[attribute name]> - attribute names are accepted with temporary attribute
282             settings. These settings are temporarily set for a single "deep_clone" call and
283             then the original attribute values are restored. For this to work the the attribute
284             must meet the L<necessary criteria|/Attributes>.
285              
286             =back
287              
288             B<single data reference option> - if only one data_ref is sent and it fails
289             the test;
290              
291             exists $data_ref->{donor_ref}
292              
293             then the program will attempt to name it as donor_ref => $data_ref and then clone
294             the whole thing.
295              
296             =back
297              
298             B<Returns:> The deep cloned data reference
299              
300             =back
301              
302             =head2 get_should_clone
303              
304             =over
305              
306             B<Definition:> This will get the current value of the attribute
307             L<should_clone|/should_clone>
308              
309             B<Accepts:> nothing
310              
311             B<Returns:> a boolean value
312              
313             =back
314              
315             =head2 set_should_clone( $Bool )
316              
317             =over
318              
319             B<Definition:> This will set the attribute L<should_clone|/should_clone>
320              
321             B<Accepts:> a boolean value
322              
323             B<Returns:> nothing
324              
325             =back
326              
327             =head2 has_should_clone
328              
329             =over
330              
331             B<Definition:> This will return true if the attribute L<should_clone|/should_clone>
332             is active
333              
334             B<Accepts:> nothing
335              
336             B<Returns:> a boolean value
337              
338             =back
339              
340             =head2 clear_should_clone
341              
342             =over
343              
344             B<Definition:> This will set the attribute L<should_clone|/should_clone>
345             to one ( 1 ). I<The name is awkward to accomodate one shot attribute changes.>
346              
347             B<Accepts:> nothing
348              
349             B<Returns:> nothing
350              
351             =back
352              
353             =head1 Caveat utilitor
354              
355             =head2 Supported Node types
356              
357             =over
358              
359             =item ARRAY
360              
361             =item HASH
362              
363             =item SCALAR
364              
365             =back
366              
367             =head1 SUPPORT
368              
369             =over
370              
371             L<github Data-Walk-Extracted/issues|https://github.com/jandrew/Data-Walk-Extracted/issues>
372              
373             =back
374              
375             =head1 TODO
376              
377             =over
378              
379             B<1.> Support cloning through class instance nodes (can should you even do this?)
380              
381             B<2.> Support cloning through CodeRef nodes
382              
383             B<3.> Support cloning through REF nodes
384              
385             =back
386              
387             =head1 AUTHOR
388              
389             =over
390              
391             =item Jed Lund
392              
393             =item jandrew@cpan.org
394              
395             =back
396              
397             =head1 COPYRIGHT
398              
399             This program is free software; you can redistribute
400             it and/or modify it under the same terms as Perl itself.
401              
402             The full text of the license can be found in the
403             LICENSE file included with this module.
404              
405             This software is copyrighted (c) 2012, 2016 by Jed Lund.
406              
407             =head1 Dependencies
408              
409             =over
410              
411             L<version> - 0.77
412              
413             L<utf8>
414              
415             L<MooseX::Types>
416              
417             L<Moose::Role>
418              
419             =over
420              
421             B<requires>
422              
423             =over
424              
425             =item _process_the_data
426              
427             =item _dispatch_method
428              
429             =item _get_had_secondary
430              
431             =back
432              
433             L<Data::Walk::Extracted>
434              
435             L<Data::Walk::Extracted::Dispatch>
436              
437             =back
438              
439             =back
440              
441             =head1 SEE ALSO
442              
443             =over
444              
445             L<Clone> - clone
446              
447             L<Log::Shiras::Unhide> - Can use to unhide '###InternalExtracteDClonE' tags
448              
449             L<Log::Shiras::TapWarn> - to manage the output of exposed '###InternalExtracteDClonE' lines
450              
451             L<Data::Dumper> - used in the '###InternalExtracteDGrafT' lines
452              
453             =back
454              
455             =cut
456              
457             #########1 Main POD ends 3#########4#########5#########6#########7#########8#########9