File Coverage

blib/lib/AsciiDB/TagFile.pm
Criterion Covered Total %
statement 108 114 94.7
branch 29 38 76.3
condition 9 16 56.2
subroutine 20 20 100.0
pod 0 7 0.0
total 166 195 85.1


line stmt bran cond sub pod time code
1             package AsciiDB::TagFile;
2              
3             # Copyright (c) 1997-2001 Jose A. Rodriguez. All rights reserved.
4             # This program is free software; you can redistribute it and/or modify it
5             # under the same terms as Perl itself.
6              
7             require Tie::Hash;
8             @ISA = (Tie::Hash);
9              
10 6     6   5125 use Cwd;
  6         11  
  6         527  
11              
12 6     6   33 use vars qw($VERSION $catPathFileName);
  6         10  
  6         748  
13              
14             BEGIN {
15 6     6   632 eval "use File::Spec";
  6     6   40  
  6         11  
  6         77  
16             $catPathFileName = ($@) ?
17 0         0 sub { join('/', @_) } : # Unix way
18 6 50       215 sub { File::Spec->catfile(@_) }; # Portable way
  175         194022  
19             }
20              
21             $VERSION = '1.06';
22              
23 6     6   29 use Carp;
  6         9  
  6         4060  
24 6     6   4346 use AsciiDB::TagRecord;
  6         15  
  6         7307  
25              
26             sub TIEHASH {
27 6     6   4573 my $class = shift;
28 6         34 my %params = @_;
29              
30 6         18 my $self = {};
31 6   33     41 $self->{_DIRECTORY} = $params{DIRECTORY} || cwd;
32 6   50     32 $self->{_SUFIX} = $params{SUFIX} || '';
33 6         22 $self->{_SCHEMA} = $params{SCHEMA};
34 6         17 $self->{_READONLY} = $params{READONLY};
35 6         17 $self->{_FILEMODE} = $params{FILEMODE};
36 6   50     52 $self->{_LOCK} = $params{LOCK} || 0;
37 6         18 $self->{_CACHESIZE} = $params{CACHESIZE};
38              
39 6 50       91 unless (-d $self->{_DIRECTORY}) {
40 0         0 croak "Directory '$params{DIRECTORY}' does not exist";
41             }
42              
43 6 100       28 if (defined $self->{_CACHESIZE}) {
44 1         3 $self->{_CACHESIZE} = int($self->{_CACHESIZE});
45              
46 1 50       7 if ($self->{_CACHESIZE} == 0) {
    50          
47 0         0 undef $self->{_CACHESIZE};
48             } elsif ($self->{_CACHESIZE} < 1) {
49 0         0 croak "Cache size should be >= 0 (0 means no cache)";
50 0         0 $self->{_CACHESIZE} = 1;
51             }
52             }
53              
54             # Number of internal keys (ie. '_key')
55 6         29 $self->{_INTKEYCOUNT} = 1 + keys %$self;
56              
57 6         38 bless $self, $class;
58             }
59              
60             sub FETCH {
61 173     173   1605 my ($self, $key) = @_;
62              
63 173 100       615 return $self->{$key} if exists ($self->{$key});
64              
65 108         203 return $self->newRecord($key);
66             }
67              
68             sub STORE {
69 2     2   4 my ($self, $key, $value) = @_;
70              
71             # Return if the user is assigning an object to itself ($a{A} = $a{A})
72 2 100 66     13 return if exists $self->{$key} && $self->{$key} == $value;
73              
74 1 50       6 $self->newRecord($key) unless (exists $self->{$key});
75              
76 1         1 my $field;
77 1         2 foreach $field (keys %{$self->{$key}}) {
  1         8  
78 4         17 $self->{$key}{$field} = $value->{$field};
79             }
80             }
81              
82             sub FIRSTKEY {
83 1     1   17 my $self = shift;
84              
85             # Current keys are the union of saved keys and new created but
86             # not saved keys
87 1         2 my %currentKeys;
88              
89 1         27 my $sufix = $self->{_SUFIX};
90              
91 1         11 map { $currentKeys{$_} = 1 }
  1         5  
92 2         41 map { $self->decodeKey($_) }
93 1         6 grep { $_ =~ /(.+)\Q$sufix\E$/; $_ = $1 }
  2         11  
94             $self->getDirFiles();
95 1         11 map { $currentKeys{$_} = 1 } grep(!/^_/, keys %$self);
  0         0  
96              
97 1         5 my @currentKeys = keys %currentKeys;
98 1         3 $self->{_ITERATOR} = \@currentKeys;
99              
100 1         2 shift @{$self->{_ITERATOR}};
  1         9  
101             }
102              
103             sub NEXTKEY {
104 1     1   3 my $self = shift;
105            
106 1         2 shift @{$self->{_ITERATOR}};
  1         7  
107             }
108              
109             sub EXISTS {
110 2     2   18 my ($self, $key) = @_;
111              
112 2 100 66     13 $self->{$key} || -f $self->fileName($key) || 0;
113             }
114              
115             sub DELETE {
116 55     55   328 my ($self, $key) = @_;
117              
118 55 100       109 return if $self->{_READONLY};
119              
120 54         86 unlink $self->fileName($key);
121              
122 11         36 tied(%{$self->{$key}})->deleteRecord()
  54         187  
123 54 100       119 if tied(%{$self->{$key}});
124              
125 54 50       379 delete $self->{$key} if exists $self->{$key};
126             }
127              
128             sub sync {
129 1     1 0 7 my $self = shift;
130              
131 10 100 66     39 my @recordsToSync = grep {
132 1         4 ref $_ && ref($_) eq 'HASH' && tied(%$_)
133 1         2 } values %{$self};
134              
135 1         2 my $record;
136 1         2 foreach $record (@recordsToSync) {
137 2         9 tied(%$record)->sync();
138             }
139             }
140              
141             sub purge {
142 101     101 0 117 my $self = shift;
143 101         100 my ($cacheSize) = @_;
144              
145 101 100       161 if (defined($cacheSize)) {
146 100         143 my $dataRecords = scalar(keys %$self) - $self->{_INTKEYCOUNT};
147 100 100       224 return if $dataRecords < $cacheSize;
148             }
149              
150             # This works in 5.004 no 5.003
151             #delete @$self{grep !/^_/, keys %{$self}};
152             # instead we use this...
153 9         12 foreach (grep !/^_/, keys %{$self}) {
  9         108  
154 90         281 delete $self->{$_};
155             }
156             }
157              
158             sub newRecord {
159 109     109 0 120 my $self = shift;
160 109         120 my ($key) = @_;
161              
162 109 100       307 $self->purge($self->{_CACHESIZE}) if defined($self->{_CACHESIZE});
163              
164 109         128 my %record;
165 109         201 tie %record, 'AsciiDB::TagRecord',
166             FILENAME => $self->fileName($key),
167             SCHEMA => $self->{_SCHEMA},
168             READONLY => $self->{_READONLY},
169             FILEMODE => $self->{_FILEMODE};
170            
171 109         776 $self->{$key} = \%record;
172             }
173              
174             sub encodeKey {
175 171     171 0 159 my $self = shift;
176 171         194 my ($key) = @_;
177              
178 171         331 my $encodeSub = $self->{_SCHEMA}{KEY}{ENCODE};
179 171 50       424 ($encodeSub) ? &$encodeSub($key) : $key;
180             }
181              
182             sub decodeKey {
183 1     1 0 3 my $self = shift;
184 1         3 my ($key) = @_;
185              
186 1         3 my $decodeSub = $self->{_SCHEMA}{KEY}{DECODE};
187 1 50       8 ($decodeSub) ? &$decodeSub($key) : $key;
188             }
189              
190             sub fileName {
191 171     171 0 241 my $self = shift;
192 171         311 my ($key) = $self->encodeKey(@_);
193              
194 171         1021 &$catPathFileName($$self{_DIRECTORY}, "$key$$self{_SUFIX}")
195             }
196              
197             sub getDirFiles {
198 1     1 0 2 my $self = shift;
199              
200 1         5 local *DIR;
201 1 50       70 opendir(DIR, $$self{_DIRECTORY})
202             || die "Can't opendir $$self{_DIRECTORY}: $!";
203 1         42 my @files = grep { -f &$catPathFileName($$self{_DIRECTORY}, $_) }
  4         10  
204             readdir(DIR);
205 1         19 closedir DIR;
206              
207 1         6 @files;
208             }
209              
210             1;
211             __END__