File Coverage

blib/lib/Tie/TwoLevelHash.pm
Criterion Covered Total %
statement 123 222 55.4
branch 45 96 46.8
condition 5 10 50.0
subroutine 10 16 62.5
pod 0 1 0.0
total 183 345 53.0


line stmt bran cond sub pod time code
1             package Tie::TwoLevelHash;
2              
3             # $Id: TwoLevelHash.pm,v 1.2 1998/10/30 13:52:04 kmeltz Exp kmeltz $
4              
5             # $Log: TwoLevelHash.pm,v $
6             # Revision 1.2 1998/10/30 13:52:04 kmeltz
7             # Fixed FETCH so it will return correctly when doing %foo = %bar; when using a tie to a HoH's. Still not working right for hash in the HoH's, so the GetHash method stays.
8             #
9             #
10             # Revision 1.1 1998/10/27 15:43:47 kmeltz
11             # Changed croaks to carps for Hash Invalid warning. May need to continue script, so let script die and module return undef.
12             # Changed CLEAR to not erase TLH file when clearing hash in HoH's, or resetting it.
13             # Added exported method GetHash. This allows for user to import hash values into their script, and change values before setting them to TLH file.
14             # Changed a bunch in the POD.
15             #
16              
17 1     1   2295 use FileHandle;
  1         23527  
  1         8  
18 1     1   777 use Carp;
  1         3  
  1         81  
19 1     1   5 use vars qw($VERSION @ISA @EXPORT);
  1         13  
  1         103  
20             @ISA = qw(Exporter);
21             @EXPORT = qw();
22 1     1   7 use strict;
  1         1  
  1         4940  
23              
24             ($VERSION = substr(q$Revision: 1.2 $, 10)) =~ s/\s+$//;
25              
26             sub TIEHASH {
27 2     2   81 my $self = shift;
28 2         4 my $path = shift;
29 2   50     8 my $mode = shift || 'r';
30 2         3 my $oneHash = "";
31 2         2 my ($comment, %tlhash, %unihash, $key);
32 2         5 my $single=0;
33              
34             # Check to see if $path has two elements
35 2 100       9 if ($path =~ /,/) {
36 1         4 ($path, $oneHash) = split(/,/,$path);
37             }
38              
39 2 50       6 if (@_) {
40 0         0 croak ("usage: tie(\%hash, \$file[, Hash name], [mode])");
41             }
42              
43             # Nice-ify $path:
44 2         5 $path =~ s#/$##;
45              
46             # Can we make changes to the database?
47 2 50       7 my $clobber = ($mode eq 'rw' ? 1 : 0);
48              
49 2 50       35 unless (-e $path) {
50 0 0       0 if ($clobber) {
51             # Create the tlh if it does not exist
52 0 0       0 unless (open(FH,">$path")) {croak("Can't create $path: $!");}
  0         0  
53             } else {
54 0         0 croak("$path does not exist");
55             }
56             #croak "File does not exist\n";
57             }
58 2         4 close FH;
59              
60             # Get a filehandle and open the file:
61 2         17 my $fh = new FileHandle;
62 2 50       137 open($fh, $path) or croak("can't open $path: $!");
63              
64 2         5 my $tlh;
65              
66             # Showing one hash
67 2 100       4 if ($oneHash ne "") {
68 1         6 $oneHash =~ s/^\s//;
69 1         4 ($comment, %unihash) = $self->_get_HoH($path);
70             #%tlhash = $self->_get_SingHash("$oneHash", $path);
71 1         4 foreach $key (keys %unihash) {
72 3 100       8 if ($key eq $oneHash) {
73 1         2 %tlhash->{$key} = $unihash{$key};
74             }
75             }
76 1         2 $single=1;
77             # Show HoH's
78             }else{
79 1         7 ($comment, %tlhash) = $self->_get_HoH($path);
80             }
81              
82 2         11 my $node = {
83             PATH => $path,
84             CLOBBER => $clobber,
85             HANDLE => $fh,
86             SINGLEHASH => $single,
87             };
88 2         3 $node->{BIHASH} = \%tlhash;
89 2 100       6 $node->{UNIHASH} = \%unihash if defined(%unihash);
90 2 100       6 $node->{UNIHASHNAME} = $oneHash if defined(%unihash);
91 2 50       5 $node->{COMMENTS} = $comment if defined($comment);
92              
93 2 100       6 if ($oneHash ne "" ) { $node->{SINGLEHASH} = 1; }else{$node->{SINGLEHASH} = 0;}
  1         2  
  1         3  
94              
95 2         16 return bless $node => $self;
96            
97             }
98              
99             #-------------------------------------------------------#
100              
101             sub FETCH {
102 5     5   18 my $self = shift;
103 5         6 my $key = shift;
104            
105             # If showing one hash
106 5 100       12 if ($self->{SINGLEHASH}) {
107 3         4 my $uniname = $self->{UNIHASHNAME};
108 3 50       6 if ($key eq $uniname) {
109 0         0 my %return = $self->GetHash();
110 0         0 return \%return;
111             }
112 3 50       9 unless (exists $self->{BIHASH}->{$uniname}->{$key}) {
113 0         0 carp "Hash invalid";
114 0         0 return undef;
115             }
116 3 50       9 if (defined $self->{BIHASH}->{$uniname}->{$key}) {
117 3         13 return $self->{BIHASH}->{$uniname}->{$key};
118             } else {
119 0         0 return carp("Fetch failed for $key");
120             }
121             }
122            
123             # If showing HoH's
124 2 50       9 unless (exists $self->{BIHASH}->{$key}) {
125 0         0 carp "Hash invalid";
126 0         0 return undef;
127             }
128 2 50       6 if (defined $self->{BIHASH}->{$key}) {
129 2         6 return $self->{BIHASH}->{$key};
130             } else {
131 0         0 return carp("Fetch failed for $key");
132             }
133             }
134              
135             #-------------------------------------------------------#
136              
137             sub STORE {
138 7     7   15 my $self = shift;
139 7         11 my $key = shift;
140 7         9 my $value;# = shift || "";
141             my ($inKey);
142 7         11 my $file = $self->{PATH};
143 7         7 my ($foo,$val,$bar,$str, %value);
144 0         0 my (%foo);
145 7         13 my $single = $self->{SINGLEHASH};
146 7         8 my %bihash = %{$self->{'BIHASH'}};
  7         31  
147 7         10 my (%unihash);
148              
149 7 100 50     12 if ($single) {%unihash = %{$self->{'UNIHASH'}}; $value = shift;}else{$value=shift || "";}
  4         5  
  4         11  
  4         8  
  3         10  
150              
151             # HoH's AND no value/undef
152 7 50 66     26 if (!$single && $value eq "") {
153 0 0       0 if (!$self->EXISTS($key)) {
154 0         0 carp("Tried deleting $key which doesn't exist");
155 0         0 return 0;
156             }
157            
158 0 0       0 if (!$self->_deleteRecord($key)) {
159 0         0 return 0;
160             } else {
161 0         0 return 1;
162             }
163             }
164              
165 7 100       36 if (!$single) {
166 3         10 %value = %$value;
167             }
168              
169 7 50       17 unless ($self->{CLOBBER}) {
170 0         0 carp ("No write access for $self->{'PATH'}");
171 0         0 return;
172             }
173              
174 7         6 my $fh;
175 7 50       38 unless ($fh = new FileHandle(">$file")) {
176             #unless ($fh = new FileHandle("$file")) { # DEBUG
177 0         0 croak ("Can't open $file: $!");
178             }
179              
180             # Set the new value in original hash
181 7 100       657 if (!$single) {
182 3         11 foreach $inKey (sort keys %value) {
183             #print "$inKey $value{$inKey}\n"; # DEBUG
184 4 50       9 if ($inKey eq "") {
185 0         0 undef $bihash{$key}{$inKey};
186 0         0 next;
187             }
188 4         13 $bihash{$key}{$inKey} = $value{$inKey};
189             }
190             } else {
191 4 50       9 if (!defined($value)) {
192 0         0 undef $unihash{$self->{UNIHASHNAME}}{$key};
193 0         0 undef $bihash{$key};
194            
195             }
196              
197 4         10 $unihash{$self->{UNIHASHNAME}}{$key} = $value;
198 4         6 $bihash{$key} = $value;
199              
200             }# endif
201              
202             # If there were comments on the top, re-write them first
203 7 50       23 if (defined($self->{COMMENTS})) {
204 0         0 my $comment = $self->{COMMENTS};
205 0         0 $str .= "$comment";
206             }
207              
208              
209             # Run through HoH from memory and get out each Hash in %zog
210 7 100       10 if (!$single) {
211 3         13 foreach $foo (sort keys %bihash) {
212 9         13 $str .= "\n$foo\n";
213 9         11 my $zog = $bihash{$foo};
214 9         27 my %zog=%$zog;
215             # Get all values in %zog
216 9         22 foreach $bar (sort keys %zog) {
217 18 50       65 $str .= "\t$bar\: $zog{$bar}\n" unless !defined($zog{$bar});
218             }
219             }
220             } else {
221 4         14 foreach $foo (sort keys %unihash) {
222 12         19 $str .= "\n$foo\n";
223 12         15 my $zog = $unihash{$foo};
224 12         30 my %zog=%$zog;
225             # Get all values in %zog
226 12         23 foreach $bar (sort keys %zog) {
227 24 50       78 $str .= "\t$bar\: $zog{$bar}\n" unless !defined($zog{$bar});
228             }
229             }
230             }
231 7 100       17 $self->{'UNIHASH'} = \%unihash if defined(%unihash);
232 7         15 $self->{'BIHASH'} = \%bihash;
233 7         57 print $fh $str;
234 7         209 close $fh;
235 7         44 return 1;
236             }
237              
238             #-------------------------------------------------------#
239              
240             sub DELETE {
241 0     0   0 my ($self) = shift;
242 0         0 my ($key) = shift;
243 0 0       0 if ($self->{SINGLEHASH}) {
244 0         0 delete $self->{UNIHASH}->{$key};
245 0         0 delete $self->{BIHASH}->{$key};
246             }else{
247 0         0 delete $self->{BIHASH}->{$key};
248             }
249             }
250              
251             #-------------------------------------------------------#
252              
253             sub CLEAR {
254 0     0   0 my ($self) = shift;
255 0         0 my ($key);
256 0         0 my ($file) = $self->{'PATH'};
257              
258 0 0       0 if ($self->{SINGLEHASH}) {
259 0         0 foreach $key (keys %{$self->{BIHASH}}) {
  0         0  
260 0         0 $self->DELETE($key);
261             }
262 0         0 return 1;
263             }
264 0         0 foreach $key (keys %{$self->{BIHASH}}) {
  0         0  
265 0         0 $self->DELETE($key);
266             }
267              
268              
269             # Erase file, since it is being cleared
270              
271 0 0       0 unless ($self->{SINGLEHASH}) {
272 0         0 my $fh;
273 0 0       0 unless ($fh = new FileHandle(">$file")) {
274             #unless ($fh = new FileHandle("$file")) { # DEBUG
275 0         0 croak ("Can't open $file: $!");
276             }
277 0         0 close $fh;
278             }
279             # File erased, if tied to HoH
280              
281             }
282              
283             #-------------------------------------------------------#
284              
285             sub EXISTS {
286 2     2   5 my $self = shift;
287 2         3 my $key = shift;
288              
289 2         12 return exists $self->{BIHASH}->{$key};
290             }
291              
292             #-------------------------------------------------------#
293              
294             sub DESTROY {
295 2     2   14 my $self = shift;
296 2         111 my $node = {};
297             }
298              
299             #-------------------------------------------------------#
300              
301             sub FIRSTKEY {
302 0     0   0 my $self = shift;
303 0         0 my $a = keys %{$self->{BIHASH}};
  0         0  
304 0         0 each %{$self->{BIHASH}}
  0         0  
305             }
306              
307             #-------------------------------------------------------#
308              
309             sub NEXTKEY {
310 0     0   0 my $self = shift;
311 0         0 return each %{$self->{BIHASH}}
  0         0  
312             }
313              
314             #-------------------------------------------------------#
315              
316             sub _deleteRecord {
317 0     0   0 my $self = shift;
318 0         0 my $record = shift;
319 0 0       0 if (!defined($record)) {
320 0         0 carp("Not enough args passed to _deleteRecord");
321 0         0 return 0;
322             }
323 0         0 my $file = $self->{PATH};
324 0         0 my ($foo,$str,$bar);
325 0         0 my $fh;
326 0 0       0 unless ($fh = new FileHandle(">$file")) {
327             #unless ($fh = new FileHandle("$file")) { # DEBUG
328 0         0 croak ("can't open $file: $!");
329             }
330 0         0 my %bihash = %{$self->{'BIHASH'}};
  0         0  
331 0 0       0 $str .= $self->{'COMMENTS'} if defined($self->{'COMMENTS'});
332              
333 0         0 foreach $foo (sort keys %bihash) {
334             #print "$foo $bihash{$foo} d\n";
335 0 0       0 if ($foo eq $record) {
336             #$bihash{$foo} = undef;
337 0         0 next;
338             }
339 0         0 $str .= "\n$foo\n";
340 0         0 my $zog = $bihash{$foo};
341 0         0 my %zog=%$zog;
342             # Get all values in %zog
343 0         0 foreach $bar (sort keys %zog) {
344 0 0       0 $str .= "\t$bar\: $zog{$bar}\n" unless !defined($zog{$bar});
345             }
346             }
347              
348 0         0 $self->{'BIHASH'} = \%bihash;
349 0         0 print $fh $str;
350 0         0 close $fh;
351 0         0 return 1;
352             }
353              
354             #-----------------------------------------------------------#
355              
356             sub _get_HoH {
357 2     2   3 my ($self) = shift;
358 2         4 my ($slh) = shift;
359 2         3 my ($key, $val);
360 0         0 my ($name, @lines, $rec, $line);
361 0         0 my (%HoH);
362 2         9 my ($FH) = new FileHandle;
363              
364 2 50       91 if (!open($FH,"$slh")) {
365 0         0 croak "Cannot open $FH $slh: $!";
366             }
367              
368 2         9 local $/ = "";
369              
370 2         48 my @records = <$FH>;
371              
372             # Make sure comments at top of TLH file stay
373 2         3 my $comment;
374 2 50 33     16 if ($records[0] && $records[0] =~ /^#/) {
375 0         0 $comment = $records[0];
376 0         0 chop $comment;
377 0         0 shift @records;
378             }
379 2         4 foreach $rec (@records) {
380              
381 6         32 ($name, @lines) = split /\n[\s]*/, $rec;
382              
383 6         9 foreach $line (@lines) {
384 12         31 ($key, $val) = split /:\s*/, $line;
385 12         35 $HoH{$name}->{$key} = $val;
386              
387             }
388             }
389 2 50       20 if (!close($FH)) {
390 0         0 croak "Cannot close $FH: $!";
391             }
392              
393 2         19 return ($comment, %HoH);
394             } # end _get_HoH
395              
396             #-----------------------------------------------------------#
397              
398             sub GetHash {
399 0     0 0   my ($self) = shift;
400 0           my ($hash, %hash);
401 0 0         my $name = $self->{UNIHASHNAME} if ($self->{UNIHASHNAME} ne "");
402            
403 0 0         if (defined($name)) {
404 0           $hash = $self->{BIHASH}->{$name};
405             }else{
406 0           $hash = $self->{BIHASH};
407             }
408 0           %hash = %$hash;
409              
410 0           return %hash;
411             }
412              
413             #-----------------------------------------------------------#
414              
415             1;
416              
417             __END__