File Coverage

blib/lib/Hash/Mogrify.pm
Criterion Covered Total %
statement 95 103 92.2
branch 27 52 51.9
condition n/a
subroutine 10 10 100.0
pod 0 4 0.0
total 132 169 78.1


line stmt bran cond sub pod time code
1             package Hash::Mogrify;
2              
3 1     1   26244 use 5.006;
  1         4  
  1         41  
4 1     1   7 use strict;
  1         1  
  1         97  
5 1     1   5 use warnings;
  1         7  
  1         75  
6              
7             =head1 NAME
8              
9             Hash::Mogrify - Perl extension for modifying hashes
10              
11             =head1 SYNOPSIS
12              
13             use Hash::Mogrify qw(kmap vmap hmap);
14             # or :all
15             or
16             use Hash::Mogrify qw(kmap vmap hmap :force :nowarning :dieonerror);
17             # to set global bitmaps
18             or
19             use Hash::Mogrify qw(:all :const);
20             # also get constants for setting local bitmaps.
21              
22             my %hash = ( foo => 'bar',
23             quuz => 'quux',
24             bla => 'bulb',);
25              
26             my %newhash = kmap { $_ =~ s/foo/food/ } %hash;
27             my $newhashref = vmap { $_ =~ s/bulb/burp/ } %hash;
28             my $samehashref = hmap { $_[0] =~ s/foo/food/; $_[1] =~ s/bulb/burp/ } \%hash;
29              
30             ## setting local bitmaps
31             my %newhash = kmap { $_ =~ s/foo/food/ } %hash, NOWARNING | FORCE;
32             # to enable nowarning and force for this action.
33              
34             kmap { $_ =~ s/foo/food/ } \%hash, DIEONERR
35             # to let kmap die on error.
36              
37             ktrans { foo => 'food' }, \%hash;
38             # Change key foo into key food.
39            
40             =head1 DESCRIPTION
41              
42             Hash::Mogrify contains functions for changes parts of hashes, change/mogrify it's keys or it's values.
43              
44             The functions are flexible in design.
45             The functions kmap, vmap and hmap return a hash/list in list context and a hash-reference in scalar context.
46             The first argument to these functions is a code block to mogrify the hash, the second either a hash or a hashref.
47              
48             If a hash(list) is provided as an argument a new hash is created. When a hash-reference (e.a \%hash) is provided the original hash is changed.
49              
50             The function ktrans works similar to kmap, except that it takes a hashref as translation table instead of a codeblock.
51              
52             By default no function overwrites existing keys and warns about this when trying.
53             this can be changed by setting the global or local bitmap.
54             The global bitmap can be set on load by the following keys:
55             :nowarning # do not warn about errors
56             :dieonerror # die incase you're trying to override an existing key
57             :force # override existing keys (overrrides :dieonerror).
58             The local bitmap can be set by adding to the end of the function, there are the following constants:
59             NOWARNING
60             FORCE
61             DIEONERR
62             The local bitmap will completely override the global bitmap.
63              
64             More options might be provided in later versions.
65              
66             =head2 EXPORT
67              
68             None by default.
69              
70             =cut
71              
72 1     1   5 use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $GLOBALMAP);
  1         1  
  1         1245  
73             require Exporter;
74              
75             @ISA = qw(Exporter);
76              
77             %EXPORT_TAGS = (
78             'all' => [ qw(
79             hmap
80             kmap
81             vmap
82             ktrans
83             ) ],
84             'const' => [ qw(
85             FORCE
86             NOWARNING
87             DIEONERR
88             ) ],
89             nowarning => [],
90             force => [],
91             dieonerror => [],);
92              
93             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} }, @{ $EXPORT_TAGS{'const'} });
94              
95             @EXPORT = ();
96              
97             $VERSION = '0.03';
98              
99             sub FORCE() { 1; }
100             sub NOWARNING() { 2; }
101             sub DIEONERR() { 4; }
102              
103             $GLOBALMAP = 0;
104              
105             sub import {
106 2 50   2   3715 $GLOBALMAP |= FORCE if(grep /:force/, @_);
107 2 100       11 $GLOBALMAP |= NOWARNING if(grep /:nowarning/, @_);
108 2 50       9 $GLOBALMAP |= DIEONERR if(grep /:dieonerror/, @_);
109 2         2901 Hash::Mogrify->export_to_level(1, @_);
110             }
111              
112             sub kmap(&@) {
113 3     3 0 1086 my $code = shift;
114 3         4 my $hash = $_[0];
115 3         4 my $bitmap;
116 3 100       9 if(!ref $hash) {
117 1 50       5 $bitmap = shift if((scalar @_) % 2);
118 1         3 $hash = { @_ };
119             }
120              
121 3         2 my $temp;
122 3         4 for (keys %{$hash}) {
  3         10  
123 11         17 my $value = $hash->{$_};
124 11         26 $code->($_, $value);
125 11 100       46 _double($temp, $_, $bitmap) or return;
126 9         22 $temp->{$_} = $value;
127             }
128 1         2 %{$hash} = %{$temp};
  1         6  
  1         2  
129              
130 1 50       6 return %{$hash} if(wantarray);
  0         0  
131 1         5 return $hash;
132             }
133              
134             sub vmap(&@) {
135 1     1 0 972 my $code = shift;
136 1         2 my $hash = $_[0];
137 1         1 my $bitmap; # we don't use this, but maybe once :)
138 1 50       4 if(!ref $hash) {
139 1 50       3 $bitmap = shift if((scalar @_) % 2);
140 1         4 $hash = { @_ };
141             }
142              
143 1         1 my $temp;
144 1         2 for my $key (keys(%{ $hash })) {
  1         3  
145 4         6 $_ = $hash->{$key};
146 4         7 $code->($key, $_);
147 4         14 $temp->{$key} = $_;
148             }
149 1         2 %{$hash} = %{$temp};
  1         5  
  1         3  
150              
151 1 50       5 return %{$hash} if(wantarray);
  1         6  
152 0         0 return $hash;
153             }
154              
155             sub hmap(&@) {
156 1     1 0 1315 my $code = shift;
157 1         2 my $hash = $_[0];
158 1         1 my $bitmap;
159 1 50       4 if(!ref $hash) {
160 0 0       0 $bitmap = shift if(@_ % 2);
161 0         0 $hash = { @_ };
162             }
163              
164 1         2 my $temp;
165 1         2 for my $key (keys(%{ $hash })) {
  1         18  
166 4         8 my $value = $hash->{$key};
167 4         11 $code->($key, $value);
168 4 50       21 _double($temp, $key, $bitmap) or return;
169 4         11 $temp->{$key} = $value;
170             }
171 1         3 %{$hash} = %{$temp};
  1         5  
  1         4  
172              
173 1 50       5 return %{$hash} if(wantarray);
  0         0  
174 1         4 return $hash;
175             }
176              
177             sub ktrans($@) {
178 1     1 0 367 my $table = shift;
179 1         2 my $hash = $_[0];
180              
181 1         1 my $bitmap;
182 1 50       7 if(!ref $hash) {
183 1 50       5 $bitmap = shift if(@_ % 2);
184 1         4 $hash = { @_ };
185             }
186              
187 1         2 my $temp = { %{$hash} };
  1         4  
188 1         2 for my $old (keys(%{ $table })) {
  1         4  
189 2 50       6 next if(!exists $temp->{$old});
190 2         3 my $new = $table->{$old};
191              
192 2 50       4 _double($temp, $new, $bitmap) or return;
193              
194 2         4 my $value = $temp->{$old};
195 2         4 delete $temp->{$old};
196 2         8 $temp->{$new} = $value;
197             }
198 1         2 %{$hash} = %{$temp};
  1         6  
  1         4  
199              
200 1 50       5 return %{$hash} if(wantarray);
  1         8  
201 0         0 return $hash;
202             }
203              
204             # check if a hashkey exists, and act depending on global&local settings
205             sub _double {
206 17     17   25 my ($hash, $key, $bitmap) = @_;
207 17 50       32 my $map = defined($bitmap) ? $bitmap : $GLOBALMAP;
208              
209 17 100       61 return 1 if(!exists $hash->{$key});
210 2 50       5 if(!($map & NOWARNING)) {
211 0 0       0 warn('Attempting to override existing key, failing.') if(!$map & FORCE);
212 0 0       0 warn('Attempting to override existing key, forcing.') if($map & FORCE);
213             }
214 2 50       7 return 1 if($map & FORCE);
215 2 50       6 die 'Died, trying to override existing key' if($map & DIEONERR);
216 2         11 return;
217             }
218             1;
219             __END__