File Coverage

blib/lib/Hash/CoerceToArray.pm
Criterion Covered Total %
statement 12 64 18.7
branch 0 28 0.0
condition 0 3 0.0
subroutine 4 7 57.1
pod 0 2 0.0
total 16 104 15.3


line stmt bran cond sub pod time code
1             package Hash::CoerceToArray;
2              
3 1     1   44534 use 5.010001;
  1         4  
  1         40  
4 1     1   6 use strict;
  1         2  
  1         130  
5              
6 1     1   71 use Exporter;
  1         7  
  1         163  
7             our @ISA = qw/Exporter/;
8             our $VERSION = '0.02';
9              
10 1     1   6 use Carp qw/croak/;
  1         2  
  1         2712  
11              
12             our @EXPORT_OK = qw/coerceArray getMinMaxDepth/;
13              
14             our ($hashRefLocal,$depth);
15             sub coerceArray {
16 0     0 0   my ($hashRef, $givenDepth, $sort) = @_;
17              
18             ## This would be changed in called functions
19             ## hence 'local' declaration
20 0           local $hashRefLocal = $hashRef; ## This would be
21              
22             ## die if not a HASH REFERENCE
23 0 0         if (ref($hashRefLocal) ne 'HASH') {
24 0           croak 'Please provide a HashRef';
25             }
26              
27 0 0 0       if($sort && $sort !~ /^(keys|values)$/) {
28 0           croak 'Please provide sort option as keys|values';
29             }
30              
31             ## Use the maximum depth if not given one
32             ## This depth should be accessible to all local functions
33             ## hence 'local' declaration
34 0 0         local $depth = getMinMaxDepth($hashRefLocal) if (!$givenDepth);
35 0 0         $depth = $givenDepth if($givenDepth);
36              
37             ## Recursive iteration to go where HASH REFERENCE
38             ## to ARRAY REFERENCE coercion is sought
39 0           my $counter = 1;
40 0           foreach my $rec (keys %$hashRefLocal) {
41 0           _goDeepAndCoerce($$hashRefLocal{$rec},$counter,$rec,$sort);
42             }
43              
44 0           return $hashRefLocal;
45              
46             }
47              
48             sub _goDeepAndCoerce {
49 0     0     my ($hashRef,$counter,$key,$sort) = @_;
50              
51 0 0         if ($depth == ($counter+1)) {
52              
53             ## Keys would be used as breadcrumb
54             ## to change the key value at any level
55 0           my $keyString = '$hashRefLocal->';
56              
57 0           foreach my $rec (split /\:/, $key) {
58 0           $keyString .= "{'$rec'}";
59             }
60              
61             ## Put the key, values as elements to an ARRAY
62 0           my $arrayRef;
63 0 0         if(!ref $hashRef) {
64 0           $arrayRef = $hashRef;
65             }
66             else {
67 0 0         if ($sort) {
68 0 0         if ($sort eq 'keys') {
69 0           foreach my $keyLocal (sort {$a cmp $b} keys %$hashRef) {
  0            
70 0           push @$arrayRef, $keyLocal, $$hashRef{$keyLocal};
71             }
72             }
73             else {
74 0           foreach my $keyLocal (sort {$$hashRef{$a} cmp $$hashRef{b}} keys %$hashRef) {
  0            
75 0           push @$arrayRef, $keyLocal, $$hashRef{$keyLocal};
76             }
77             }
78             }
79             else {
80 0           while (my ($keyLocal, $valueLocal) = each %$hashRef) {
81 0           push @$arrayRef, $keyLocal, $valueLocal;
82             }
83             }
84             }
85              
86             ## Do in-place replacement and return
87 0           eval "$keyString = \$arrayRef";
88 0           return;
89             }
90              
91 0 0         return if (ref ($hashRef) ne 'HASH');
92              
93 0           $counter++;
94 0           foreach my $rec (keys %$hashRef) {
95 0           _goDeepAndCoerce($$hashRef{$rec},$counter,"$key:$rec",$sort);
96             }
97             }
98              
99             sub getMinMaxDepth {
100 0     0 0   my ($hashRef,$minMax) = @_;
101              
102 0 0         $minMax = 'max' if(!$minMax);
103              
104 0 0         if ($minMax !~ /^(min|max)$/) {
105 0           croak 'Please provide option for depth - min|max';
106             }
107              
108             ## Used to keep track which key at certain level
109             ## has value with maximum depth
110 0           my $maxDepthThisLevel;
111              
112 0           foreach my $rec (keys %$hashRef) {
113             ## Increment and recursively call getMinMaxDepth
114             ## If value is a hash refearence
115 0 0         if (ref($$hashRef{$rec}) eq 'HASH') {
116 0           $$maxDepthThisLevel{$rec} = 1+getMinMaxDepth($$hashRef{$rec});
117             }
118             else {
119 0           $$maxDepthThisLevel{$rec} = 1;
120             }
121             }
122            
123             ## Return the maximum or minimum depth as obtained in certain level
124 0           my $depth;
125 0 0         if ($minMax eq 'max') {
    0          
126 0           $depth = (sort {$b<=>$a} values %$maxDepthThisLevel)[0];
  0            
127             }
128             elsif ($minMax eq 'min') {
129 0           $depth = (sort {$a<=>$b} values %$maxDepthThisLevel)[0];
  0            
130             }
131              
132 0           return $depth;
133             }
134              
135             1;
136              
137             =head1 NAME
138              
139             Hash::CoerceToArray - Find the depth of any multi-hierarchical HASH REFERENCE structure
140             - Go to any level of the HASH REFERENCE randomly and convert the value
141             against a key to an ARRAY REFERENCE if it is HASH REFERENCE
142            
143             =head1 SYNOPSIS
144              
145             use Hash::CoerceToArray qw /coerceArray getMinMaxDepth/;
146            
147             my $maxDepth = getMinMaxDepth (\%hash);
148             my $minDepth = getMinMaxDepth (\%hash, 'min');
149              
150             my $hashRef = coerceArray(\%hash);
151             my $hashRef = coerceArray(\%hash, $maxDepth);
152              
153             my $hashRef = coerceArray(\%hash, $maxDepth, 'keys') --> sorts at $maxDepth based on keys
154             my $hashRef = coerceArray(\%hash, $maxDepth, 'values') --> sorts at $maxDepth based on values
155            
156             map {$hashRef = coerceArray($hashRef,$_);} (1..$maxDepth)
157            
158             =head1 ABSTRACT
159              
160             This module allows the user to get maximum or minimum depth of a HASH REFERENCE
161             variable in a multilevel structure where values are HASH REFERENCES themselves.
162              
163             Also, user is allowed to change the HASH REFERENCE value at any level randomly
164             to an ARRAY REFERENCE. By selecting the deepest level of the HASH REFERENCE
165             structure first and calling coerceArray() subroutine from thereon to depth level
166             of 1 sequentially, user can change the whole HASH REFERENCE structure
167             to an ARRAY REFERENCE hierarchy.
168              
169             =head1 DESCRIPTION
170              
171             Example HashRef.
172              
173             my $hashRef = { 'L1_1' => {'L2_1' => {'L3_1' => 'V1',
174             'L3_2' => 'V2',
175             'L3_3' => 'V3'
176             },
177             'L2_2' => {'L3_1' => {'L4_1' => 'V1',
178             'L4_2' => 'V2',
179             },
180             },
181             },
182             'L1_2' => 'V1',
183             };
184             print getMinMaxDepth($hashRef)
185             >>>> 4
186              
187             print getMinMaxDepth($hashRef, 'min')
188             >>>> 1
189              
190             $hashRef = coerceArray($hashRef);
191             print Dumper $hashRef;
192             >>>>>
193             {
194             'L1_1' => {
195             'L2_1' => {
196             'L3_2' => 'V2',
197             'L3_3' => 'V3',
198             'L3_1' => 'V1'
199             },
200             'L2_2' => {
201             'L3_1' => [
202             'L4_1',
203             'V1',
204             'L4_2',
205             'V2'
206             ]
207             }
208             }
209             };
210              
211             $hashRef = coerceArray($hashRef,2);
212             print Dumper $hashRef;
213             >>>>>
214             {
215             'L1_1' => [
216             'L2_1',
217             {
218             'L3_2' => 'V2',
219             'L3_3' => 'V3',
220             'L3_1' => 'V1'
221             },
222             'L2_2',
223             {
224             'L3_1' => [
225             'L4_1',
226             'V1',
227             'L4_2',
228             'V2'
229             ]
230             }
231             ]
232             };
233              
234             =head1 CAVEATS
235              
236             The coerceArray() routine as of now works only if the Hash References are found continuously,
237             if any other reference like Array References occur in between, it won't work as desired.
238              
239             Eg. take the following Hash Reference which has Array Reference at Level 1
240              
241             {
242             'L1_1' => [
243             'L2_1',
244             {
245             'L3_2' => 'V2',
246             'L3_3' => 'V3',
247             'L3_1' => 'V1'
248             },
249             'L2_2',
250             {
251             'L3_1' => [
252             'L4_1',
253             'V1',
254             'L4_2',
255             'V2'
256             ]
257             }
258             ]
259             };
260             Now here $hashRef = coerceArray($hashRef,2);
261             print Dumper $hashRef; - won't work as desired.
262             I will look to improve it in a future release.
263              
264             =head1 SUPPORT
265              
266             debashish@cpan.org
267              
268             =head1 ACKNOWLEDGEMENTS
269              
270             =head1 COPYRIGHT & LICENSE
271              
272             Copyright 2013 Debashish Parasar, all rights reserved.
273              
274             This program is free software; you can redistribute it and/or modify it
275             under the same terms as Perl itself.
276              
277             =cut