File Coverage

blib/lib/Data/Walk/Prune.pm
Criterion Covered Total %
statement 49 59 83.0
branch 10 16 62.5
condition 3 6 50.0
subroutine 12 14 85.7
pod 1 1 100.0
total 75 96 78.1


line stmt bran cond sub pod time code
1             package Data::Walk::Prune;
2             our $AUTHORITY = 'cpan:JANDREW';
3 2     2   995 use version; our $VERSION = version->declare('v0.28.0');
  2         2  
  2         9  
4             ###InternalExtracteDPrunE warn "You uncovered internal logging statements for Data::Walk::Prune-$VERSION";
5             ###InternalExtracteDPrunE use Data::Dumper;
6 2     2   170 use 5.010;
  2         4  
7 2     2   6 use utf8;
  2         2  
  2         43  
8 2     2   36 use Moose::Role;
  2         1  
  2         14  
9             requires qw(
10             _get_had_secondary _process_the_data _dispatch_method
11             );
12 2     2   6520 use MooseX::Types::Moose qw( ArrayRef Bool Item HashRef );
  2         3  
  2         14  
13              
14             #########1 Package Variables 3#########4#########5#########6#########7#########8#########9
15              
16             $| = 1;
17             my $prune_keys = {
18             slice_ref => 'primary_ref',
19             tree_ref => 'secondary_ref',
20             };
21              
22             #########1 Dispatch Tables 3#########4#########5#########6#########7#########8#########9
23              
24             my $prune_dispatch = {######<----------------------------------------- ADD New types here
25             HASH => \&_remove_hash_key,
26             ARRAY => \&_clear_array_position,
27             };
28              
29             my $remember_dispatch = {######<-------------------------------------- ADD New types here
30             HASH => \&_build_hash_cut,
31             ARRAY => \&_build_array_cut,
32             };
33              
34             my $prune_decision_dispatch = {######<------------------------------- ADD New types here
35             HASH => sub{ scalar( keys %{$_[1]->{primary_ref}} ) == 0 },
36             ARRAY => sub{ scalar( @{$_[1]->{primary_ref}} ) == 0 },
37             SCALAR => sub { return 0 },#No cut signal for SCALARS
38             UNDEF => sub { return 0 },#No cut signal for UNDEF refs
39             name => '- Prune - prune_decision_dispatch',
40             ###### Receives: the current $passed_ref
41             ###### Returns: pass | fail (Boolean style)
42             };
43              
44             #########1 Public Attributes 3#########4#########5#########6#########7#########8#########9
45              
46             has 'prune_memory' =>(
47             isa => Bool,
48             writer => 'set_prune_memory',
49             reader => 'get_prune_memory',
50             predicate => 'has_prune_memory',
51             clearer => 'clear_prune_memory',
52             );
53              
54             #########1 Public Methods 3#########4#########5#########6#########7#########8#########9
55              
56             sub prune_data{#Used to convert names
57             ##### <where> - Passed input : @_
58 3     3 1 4555 my( $self, @args ) = @_;
59             ###InternalExtracteDPrunE warn "Made it to prune_data with input:" . Dumper( @args );
60 3 50 33     15 my $passed_ref = ( @args == 1 and is_HashRef( $args[0] ) ) ? $args[0] : { @args } ;
61             ###InternalExtracteDPrunE warn "Resolved hashref:" . Dumper( $passed_ref );
62 3         8 @$passed_ref{ 'before_method', 'after_method' } = # Hash slice
63             ( '_prune_before_method', '_prune_after_method' );
64 3         100 $self->_clear_pruned_positions;
65             ###InternalExtracteDPrunE warn "Start recursive parsing with:" . Dumper( $passed_ref );
66 3         11 $passed_ref = $self->_process_the_data( $passed_ref, $prune_keys );
67             ###InternalExtracteDPrunE warn "End recursive parsing with:" . Dumper( $passed_ref );
68 3         16 return $passed_ref->{tree_ref};
69             }
70              
71             #########1 Private Attributes 3#########4#########5#########6#########7#########8#########9
72              
73             has '_prune_list' =>(
74             traits => ['Array'],
75             isa => ArrayRef[ArrayRef[Item]],
76             handles => {
77             _add_prune_item => 'push',
78             _next_prune_item => 'shift',
79             },
80             clearer => '_clear_prune_list',
81             predicate => '_has_prune_list',
82             );
83              
84             has '_pruned_positions' =>(
85             traits => ['Array'],
86             isa => ArrayRef[HashRef],
87             handles => {
88             _remember_prune_item => 'push',
89             number_of_cuts => 'count',
90             },
91             clearer => '_clear_pruned_positions',
92             predicate => 'has_pruned_positions',
93             reader => 'get_pruned_positions',
94             );
95              
96             #########1 Private Methods 3#########4#########5#########6#########7#########8#########9
97              
98             sub _prune_before_method{
99 16     16   14 my ( $self, $passed_ref ) = @_;
100             ###InternalExtracteDPrunE warn "reached _prune_before_method with input" . Dumper( $passed_ref );
101 16 50       24 if( !exists $passed_ref->{secondary_ref} ){
102             ###InternalExtracteDPrunE warn "no matching tree_ref element so 'skip'ing the slice node ...";
103 0         0 $passed_ref->{skip} = 'YES';
104             }
105             ###InternalExtracteDPrunE warn "skip state: $passed_ref->{skip}";
106 16         27 return $passed_ref;
107             }
108              
109             sub _prune_after_method{
110 16     16   8 my ( $self, $passed_ref ) = @_;
111             ###InternalExtracteDPrunE warn "reached _prune_after_method with input" . Dumper( $passed_ref );
112             ###InternalExtracteDPrunE warn "Running the cut test with slice state: $self->_has_prune_list";
113 16 50       28 if( $passed_ref->{skip} eq 'NO') {
114             ###InternalExtracteDPrunE warn "The node was not skipped ...";
115 16 100       31 if( $self->_dispatch_method(
    100          
116             $prune_decision_dispatch,
117             $passed_ref->{primary_type},
118             $passed_ref, ) ){
119             ###InternalExtracteDPrunE warn "adding prune item:" . Dumper( $passed_ref->{branch_ref}->[-1] );
120 3         85 $self->_add_prune_item( $passed_ref->{branch_ref}->[-1] );
121             ###InternalExtracteDPrunE warn "go back up and prune ...";
122             }elsif( $self->_has_prune_list ){
123             my $tree_ref =
124             ( exists $passed_ref->{secondary_ref} ) ?
125 3 50       7 $passed_ref->{secondary_ref} : undef ;
126             ###InternalExtracteDPrunE warn "tree_ref:" . Dumper( $tree_ref );
127 3         80 while( my $item_ref = $self->_next_prune_item ){
128             ###InternalExtracteDPrunE warn "item ref:" . Dumper( $item_ref );
129 3         11 $tree_ref = $self->_prune_the_item( $item_ref, $tree_ref );
130             ###InternalExtracteDPrunE warn "tree ref:" . Dumper( $tree_ref );
131 3 100 66     76 if( $self->has_prune_memory and
132             $self->get_prune_memory ){
133             ###InternalExtracteDPrunE warn "building the rememberance ref ...";
134 1         3 my $rememberance_ref = $self->_dispatch_method(
135             $remember_dispatch,
136             $item_ref->[0],
137             $item_ref,
138             );
139             ###InternalExtracteDPrunE warn "current branch ref is:" . Dumper( $passed_ref->{branch_ref} );
140             $rememberance_ref = $self->_build_branch(
141             $rememberance_ref,
142 1         2 @{ $passed_ref->{branch_ref}},
  1         6  
143             );
144             ###InternalExtracteDPrunE warn "rememberance ref:" . Dumper( $rememberance_ref );
145 1         34 $self->_remember_prune_item( $rememberance_ref );
146             ###InternalExtracteDPrunE warn "prune memory:" . Dumper( $self->get_pruned_positions );
147             }
148             }
149 3         4 $passed_ref->{secondary_ref} = $tree_ref;
150             ###InternalExtracteDPrunE warn "finished pruning at this node - clear the prune list ...";
151 3         75 $self->_clear_prune_list;
152             }
153             }
154 16         27 return $passed_ref;
155             }
156              
157             sub _prune_the_item{
158 3     3   2 my ( $self, $item_ref, $tree_ref ) = @_;
159             ###InternalExtracteDPrunE warn "reached _prune_the_item with item:" . Dumper( $item_ref );
160             ###InternalExtracteDPrunE warn ".. and tree ref:" . Dumper( $tree_ref );
161 3         7 $tree_ref = $self->_dispatch_method(
162             $prune_dispatch,
163             $item_ref->[0],
164             $item_ref,
165             $tree_ref,
166             );
167             ###InternalExtracteDPrunE warn "cut completed succesfully";
168 3         3 return $tree_ref;
169             }
170              
171             sub _remove_hash_key{
172 3     3   3 my ( $self, $item_ref, $tree_ref ) = @_;
173             ###InternalExtracteDPrunE warn "reached _remove_hash_key with item:" . Dumper( $item_ref );
174             ###InternalExtracteDPrunE warn ".. and tree ref:" . Dumper( $tree_ref );
175 3         7 delete $tree_ref->{$item_ref->[1]};
176             ###InternalExtracteDPrunE warn "New tree ref:" . Dumper( $tree_ref );
177 3         4 return $tree_ref;
178             }
179              
180             sub _clear_array_position{
181 0     0   0 my ( $self, $item_ref, $tree_ref ) = @_;
182             ###InternalExtracteDPrunE warn "reached _clear_array_position with item:" . Dumper( $item_ref );
183             ###InternalExtracteDPrunE warn ".. and tree ref:" . Dumper( $tree_ref );
184 0 0       0 if( $self->change_array_size ){
185             ###InternalExtracteDPrunE warn "splicing out position:" . Dumper( $item_ref->[2] );
186 0         0 splice( @$tree_ref, $item_ref->[2]);
187             }else{
188             ###InternalExtracteDPrunE warn "Setting undef at position:" . Dumper( $item_ref->[2] );
189 0         0 $tree_ref->[$item_ref->[2]] = undef;
190             }
191             ###InternalExtracteDPrunE warn "New tree ref:" . Dumper( $tree_ref );
192 0         0 return $tree_ref;
193             }
194              
195             sub _build_hash_cut{
196 1     1   2 my ( $self, $item_ref ) = @_;
197             ###InternalExtracteDPrunE warn "reached _build_hash_cut with item:" . Dumper( $item_ref );
198 1         3 return { $item_ref->[1] => {} };
199             }
200              
201             sub _build_array_cut{
202 0     0     my ( $self, $item_ref ) = @_;
203             ###InternalExtracteDPrunE warn "reached _build_array_cut with item:" . Dumper( $item_ref );
204 0           my $array_ref;
205 0           $array_ref->[$item_ref->[2]] = [];
206             ###InternalExtracteDPrunE warn "New item ref:" . Dumper( $item_ref );
207 0           return $item_ref;
208             }
209              
210             #########1 Phinish Strong 3#########4#########5#########6#########7#########8#########9
211              
212 2     2   8188 no Moose::Role;
  2         2  
  2         8  
213              
214             1;
215             # The preceding line will help the module return a true value
216              
217             #########1 Main POD starts 3#########4#########5#########6#########7#########8#########9
218              
219              
220             __END__
221              
222             =head1 NAME
223              
224             Data::Walk::Prune - A way to say what should be removed
225              
226             =head1 SYNOPSIS
227              
228             #!perl
229             use MooseX::ShortCut::BuildInstance qw( build_instance );
230             use Data::Walk::Extracted;
231             use Data::Walk::Prune;
232             use Data::Walk::Print;
233              
234             my $edward_scissorhands = build_instance(
235             package => 'Edward::Scissorhands',
236             superclasses =>['Data::Walk::Extracted'],
237             roles =>[qw( Data::Walk::Print Data::Walk::Prune )],
238             change_array_size => 1, #Default
239             );
240             my $firstref = {
241             Helping => [
242             'Somelevel',
243             {
244             MyKey => {
245             MiddleKey => {
246             LowerKey1 => 'low_value1',
247             LowerKey2 => {
248             BottomKey1 => 'bvalue1',
249             BottomKey2 => 'bvalue2',
250             },
251             },
252             },
253             },
254             ],
255             };
256             my $result = $edward_scissorhands->prune_data(
257             tree_ref => $firstref,
258             slice_ref => {
259             Helping => [
260             undef,
261             {
262             MyKey => {
263             MiddleKey => {
264             LowerKey1 => {},
265             },
266             },
267             },
268             ],
269             },
270             );
271             $edward_scissorhands->print_data( $result );
272              
273             ######################################################################################
274             # Output of SYNOPSIS
275             # 01 {
276             # 02 Helping => [
277             # 03 'Somelevel',
278             # 04 {
279             # 05 MyKey => {
280             # 06 MiddleKey => {
281             # 07 LowerKey2 => {
282             # 08 BottomKey1 => 'bvalue1',
283             # 09 BottomKey2 => 'bvalue2',
284             # 10 },
285             # 12 },
286             # 13 },
287             # 14 },
288             # 15 ],
289             # 16 },
290             ######################################################################################
291              
292             =head1 DESCRIPTION
293              
294             This L<Moose::Role|https://metacpan.org/module/Moose::Manual::Roles> implements the method
295             L<prune_data|/prune_data( %args )>. It takes a $tree_ref and a $slice_ref and uses
296             L<Data::Walk::Extracted|https://metacpan.org/module/Data::Walk::Extracted>. To remove
297             portions of the 'tree_ref' defined by an empty hash ref (no keys) or an empty array ref
298             (no positions) at all required points of the 'slice_ref'. The 'slice_ref' must match the
299             tree ref up to each slice point. If the slice points are on a branch of the slice_ref that
300             does not exist on the tree_ref then no cut takes place.
301              
302             =head2 USE
303              
304             This is a L<Moose::Role|https://metacpan.org/module/Moose::Manual::Roles> specifically
305             designed to be used with L<Data::Walk::Extracted
306             |https://metacpan.org/module/Data::Walk::Extracted#Extending-Data::Walk::Extracted>.
307             It can be combined traditionaly to the ~::Extracted class using L<Moose
308             |https://metacpan.org/module/Moose::Manual::Roles> methods or for information on how to join
309             this role to Data::Walk::Extracted at run time see L<Moose::Util
310             |https://metacpan.org/module/Moose::Util> or L<MooseX::ShortCut::BuildInstance
311             |https://metacpan.org/module/MooseX::ShortCut::BuildInstance> for more information.
312              
313             =head1 Attributes
314              
315             Data passed to -E<gt>new when creating an instance. For modification of these attributes
316             see L<Methods|/Methods>. The -E<gt>new function will either accept fat comma lists or a
317             complete hash ref that has the possible attributes as the top keys. Additionally
318             some attributes that have all the following methods; get_$attribute, set_$attribute,
319             has_$attribute, and clear_$attribute, can be passed to L<prune_data
320             |/prune_data( %args )> and will be adjusted for just the run of that
321             method call. These are called 'one shot' attributes. The class and each role (where
322             applicable) in this package have a list of L<supported one shot attributes
323             |/Supported one shot attributes>.
324              
325             =head2 prune_memory
326              
327             =over
328              
329             B<Definition:> When running a prune operation any branch called on the pruner
330             that does not exist in the tree will not be used. This attribute turns on tracking
331             of the actual cuts made and stores them for review after the method is complete.
332             This is a way to know if the cut was actually implemented.
333              
334             B<Default> undefined
335              
336             B<Range> 1 = remember the cuts | 0 = don't remember
337              
338             =back
339              
340             =head2 (see also)
341              
342             L<Data::Walk::Extracted|https://metacpan.org/module/Data::Walk::Extracted#Attributes>
343             - Attributes
344              
345             =head1 Methods
346              
347             =head2 prune_data( %args )
348              
349             =over
350              
351             B<Definition:> This is a method used to remove targeted parts of a data reference.
352              
353             B<Accepts:> a hash ref with the keys 'slice_ref' and 'tree_ref' (both required).
354             The slice ref can contain more than one 'slice' location in the data reference.
355              
356             =over
357              
358             B<tree_ref> This is the primary data ref that will be manipulated and returned changed.
359              
360             B<slice_ref> This is a data ref that will be used to prune the 'tree_ref'. In general
361             the slice_ref should match the tree_ref for positions that should remain unchanged.
362             Where the tree_ref should be trimmed insert either an empty array ref or an empty hash
363             ref. If this position represents a value in a hash key => value pair then the hash
364             key is deleted. If this position represents a value in an array then the position is
365             deleted/cleared depending on the attribute L<change_array_size
366             |https://metacpan.org/module/Data::Walk::Extracted#change_array_size> in
367             Data::Walk::Extracted. If the slice ref diverges from the tree ref then no action is
368             taken past the divergence, even if there is a mandated slice. (no auto vivication occurs!)
369              
370             B<[attribute name]> - attribute names are accepted with temporary attribute settings.
371             These settings are temporarily set for a single "prune_data" call and then the original
372             attribute values are restored. For this to work the the attribute must meet the
373             L<necessary criteria|/Attributes>.
374              
375             =back
376              
377             B<Example>
378              
379             $pruned_tree_ref = $self->prune_data(
380             tree_ref => $tree_data,
381             slice_ref => $slice_data,
382             prune_memory => 0,
383             );
384              
385             B<Returns:> The $tree_ref with any changes
386              
387             =back
388              
389             =head2 set_prune_memory( $Bool )
390              
391             =over
392              
393             B<Definition:> This will change the setting of the L<prune_memory|/prune_memory>
394             attribute.
395              
396             B<Accepts:> 1 = remember | 0 = no memory
397              
398             B<Returns:> nothing
399              
400             =back
401              
402             =head2 get_prune_memory
403              
404             =over
405              
406             B<Definition:> This will return the current setting of the L<prune_memory|/prune_memory>
407             attribute.
408              
409             B<Accepts:> nothing
410              
411             B<Returns:> A $Bool value for the current state
412              
413             =back
414              
415             =head2 has_prune_memory
416              
417             =over
418              
419             B<Definition:> This will indicate if the L<prune_memory|/prune_memory> attribute is set
420              
421             B<Accepts:> nothing
422              
423             B<Returns:> A $Bool value 1 = defined, 0 = not defined
424              
425             =back
426              
427             =head2 clear_prune_memory
428              
429             =over
430              
431             B<Definition:> This will clear the L<prune_memory|/prune_memory> attribute value
432             (Not the actual prune memory)
433              
434             B<Accepts:> nothing
435              
436             B<Returns:> A $Bool value 1 = defined, 0 = not defined
437              
438             =back
439              
440             =head2 has_pruned_positions
441              
442             =over
443              
444             B<Definition:> This answers if any pruned positions were stored
445              
446             B<Accepts:> nothing
447              
448             B<Returns:> A $Bool value 1 = pruned cuts are stored, 0 = no stored cuts
449              
450             =back
451              
452             =head2 get_pruned_positions
453              
454             =over
455              
456             B<Definition:> This returns an array ref of stored cuts
457              
458             B<Accepts:> nothing
459              
460             B<Returns:> an ArrayRef - although the cuts were defined in one data ref
461             this will return one data ref per cut. Each ref will go to the root of the
462             original data ref.
463              
464             =back
465              
466             =head2 number_of_cuts
467              
468             =over
469              
470             B<Definition:> This returns the number of cuts actually made
471              
472             B<Accepts:> nothing
473              
474             B<Returns:> an integer
475              
476             =back
477              
478             =head1 Caveat utilitor
479              
480             =head2 deep cloning
481              
482             Because this uses Data::Walk::Extracted the final $tree_ref is deep cloned where
483             the $slice_ref passed through.
484              
485             =head2 Supported Node types
486              
487             =over
488              
489             =item ARRAY
490              
491             =item HASH
492              
493             =item SCALAR
494              
495             =item UNDEF
496              
497             =back
498              
499             =head2 Supported one shot attributes
500              
501             L<explanation|/Attributes>
502              
503             =over
504              
505             =item prune_memory
506              
507             =back
508              
509             =head1 GLOBAL VARIABLES
510              
511             =over
512              
513             B<$ENV{Smart_Comments}>
514              
515             The module uses L<Smart::Comments|https://metacpan.org/module/Smart::Comments> if the '-ENV'
516             option is set. The 'use' is encapsulated in an if block triggered by an environmental
517             variable to comfort non-believers. Setting the variable $ENV{Smart_Comments} in a BEGIN
518             block will load and turn on smart comment reporting. There are three levels of 'Smartness'
519             available in this module '###', '####', and '#####'.
520              
521             =back
522              
523             =head1 SUPPORT
524              
525             =over
526              
527             L<github Data-Walk-Extracted/issues|https://github.com/jandrew/Data-Walk-Extracted/issues>
528              
529             =back
530              
531             =head1 TODO
532              
533             =over
534              
535             B<1.> Add L<Log::Shiras|https://metacpan.org/module/Log::Shiras> debugging in exchange for
536             L<Smart::Comments|https://metacpan.org/module/Smart::Comments>
537              
538             B<2.> Support pruning through Objects / Instances nodes
539              
540             B<3.> Support pruning through CodeRef nodes
541              
542             B<4.> Support pruning through REF nodes
543              
544             =back
545              
546             =head1 AUTHOR
547              
548             =over
549              
550             =item Jed Lund
551              
552             =item jandrew@cpan.org
553              
554             =back
555              
556             =head1 COPYRIGHT
557              
558             This program is free software; you can redistribute
559             it and/or modify it under the same terms as Perl itself.
560              
561             The full text of the license can be found in the
562             LICENSE file included with this module.
563              
564             This software is copyrighted (c) 2013 by Jed Lund.
565              
566             =head1 Dependencies
567              
568             L<version|https://metacpan.org/module/version>
569              
570             L<Moose::Role|https://metacpan.org/module/Moose::Role>
571              
572             =over
573              
574             B<requires>
575              
576             =over
577              
578             =item _process_the_data
579              
580             =item _dispatch_method
581              
582             =item _build_branch
583              
584             =back
585              
586             =back
587              
588             L<MooseX::Types::Moose|https://metacpan.org/module/MooseX::Types::Moose>
589              
590             L<Data::Walk::Extracted|https://metacpan.org/module/Data::Walk::Extracted>
591              
592             L<Data::Walk::Extracted::Dispatch|https://metacpan.org/module/Data::Walk::Extracted::Dispatch>
593              
594             =head1 SEE ALSO
595              
596             =over
597              
598             L<Smart::Comments|https://metacpan.org/module/Smart::Comments> - is used if the -ENV option is set
599              
600             L<Data::Walk|https://metacpan.org/module/Data::Walk>
601              
602             L<Data::Walker|https://metacpan.org/module/Data::Walker>
603              
604             L<Data::ModeMerge|https://metacpan.org/module/Data::ModeMerge>
605              
606             L<Data::Walk::Print|https://metacpan.org/module/Data::Walk::Print> - available Data::Walk::Extracted Role
607              
608             L<Data::Walk::Graft|https://metacpan.org/module/Data::Walk::Graft> - available Data::Walk::Extracted Role
609              
610             L<Data::Walk::Clone|https://metacpan.org/module/Data::Walk::Clone> - available Data::Walk::Extracted Role
611              
612             =back
613              
614             =cut
615              
616             #########1 Main POD ends 3#########4#########5#########6#########7#########8#########9