File Coverage

blib/lib/Data/Library/OnePerFile.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Data::Library::OnePerFile;
2 2     2   23292 use base qw(Data::Library);
  2         4  
  2         1065  
3              
4             $VERSION = '0.2';
5              
6             my @missing = __PACKAGE__->missing_methods;
7             die __PACKAGE__ . ' forgot to implement ' . join ', ', @missing
8             if @missing;
9              
10 2     2   3190 use Log::Channel;
  0            
  0            
11             {
12             my $lblog = new Log::Channel;
13             sub lblog { $lblog->(@_) }
14             }
15              
16             =head1 NAME
17              
18             Data::Library::OnePerFile - one-item-per-file repository support class
19              
20             =head1 SYNOPSIS
21              
22             Provides a general repository service. This package
23             supports source data in files, where each file contains a
24             single source item. A tag corresponds to a filename
25             (tag.EXTENSION where EXTENSION is specified at initialization).
26             Searching will be done through a list of directories.
27             The first matching file will be used.
28             Conflicts are not detected.
29              
30             OnePerFile recognizes when a source file is changed.
31              
32             =head1 METHODS
33              
34             =cut
35              
36             require 5.004;
37             use strict;
38             use Carp;
39              
40             my %parameters = (
41             "LIB" => ".",
42             "EXTENSION" => "data",
43             );
44              
45             =item B
46              
47             my $library = new Data::Library::OnePerFile
48             ({ name => "value" ... });
49              
50             Supported Library::OnePerFile parameters:
51              
52             LIB Search path for data files. Defaults to current directory.
53              
54             EXTENSION Filename extension for data files. Defaults to "data".
55              
56             =cut
57              
58             sub new {
59             my ($proto, $config) = @_;
60             my $class = ref ($proto) || $proto;
61              
62             my $self = $config || {};
63              
64             bless ($self, $class);
65              
66             $self->_init;
67              
68             return $self;
69             }
70              
71              
72             sub _init {
73             my ($self) = shift;
74              
75             # verify input params and set defaults
76             # dies on any unknown parameter
77             # fills in the default for anything that is not provided
78              
79             foreach my $key (keys %$self) {
80             if (!exists $parameters{$key}) {
81             croak "Undefined ", __PACKAGE__, " parameter $key";
82             }
83             }
84              
85             foreach my $key (keys %parameters) {
86             $self->{$key} = $parameters{$key} unless defined $self->{$key};
87             }
88              
89             if ($self->{LIB} && !ref $self->{LIB}) {
90             $self->{LIB} = [ $self->{LIB} ];
91             }
92             }
93              
94              
95             =item B
96              
97             $library->lookup($tag);
98              
99             Returns cached data items. If the source has changed since
100             it was cached, returns false.
101              
102             =cut
103              
104             sub lookup {
105             my ($self, $tag) = @_;
106              
107             lblog "LOOKUP $tag\n";
108              
109             if (! $self->_cache_valid($tag)) {
110             return;
111             }
112              
113             return $self->{TAGS}->{$tag}->{CACHE};
114             }
115              
116              
117             sub _cache_valid {
118             my ($self, $tag) = @_;
119              
120             return unless defined $self->{TAGS}->{$tag};
121             return unless defined $self->{TAGS}->{$tag}->{CACHE};
122              
123             return unless ($self->{TAGS}->{$tag}->{LOADTS}
124             >= (stat($self->{TAGS}->{$tag}->{FILE}))[9]);
125              
126             return 1;
127             }
128              
129              
130             =item B
131              
132             $library->find($tag);
133              
134             Searches through the directory path in LIB for a file named
135             "$tag.EXTENSION". Returns the contents of that file if successful,
136             and records the path for subsequent checking by lookup().
137              
138             =cut
139              
140             sub find {
141             my ($self, $tag) = @_;
142              
143             lblog "FIND $tag\n";
144              
145             my $file;
146             foreach my $lib (@{$self->{LIB}}) {
147             $file = "$lib/$tag.$self->{EXTENSION}";
148             next unless -r $file;
149             }
150             if (! -r $file) {
151             # never found a matching readable file
152             carp "Unable to read $tag.$self->{EXTENSION}";
153             return;
154             }
155              
156             open(INPUT, $file) or croak "open $file failed: $!";
157             local $/ = undef;
158             my $data = ;
159             close INPUT;
160              
161             lblog "FOUND $tag in $file\n";
162              
163             $self->{TAGS}->{$tag}->{FILE} = $file;
164             $self->{TAGS}->{$tag}->{LOADTS} = (stat($self->{TAGS}->{$tag}->{FILE}))[9];
165              
166             return $data;
167             }
168              
169              
170             =item B
171              
172             $library->cache($tag, $data);
173              
174             Caches data by tag for later fetching via lookup().
175              
176             =cut
177              
178             sub cache {
179             my ($self, $tag, $data) = @_;
180              
181             lblog "CACHE $tag\n";
182              
183             $self->{TAGS}->{$tag}->{CACHE} = $data;
184             }
185              
186              
187             =item B
188              
189             my @array = $library->toc();
190              
191             Search through the library and return a list of all available entries.
192             Does not import any of the items.
193              
194             =cut
195              
196             sub toc {
197             my ($self) = @_;
198              
199             my %items;
200             foreach my $lib (@{$self->{LIB}}) {
201             opendir DIR, $lib or die "open $lib failed: $!";
202             foreach my $file (readdir DIR) {
203             next unless $file =~ /\.$self->{EXTENSION}$/;
204             $file =~ s/\.$self->{EXTENSION}$//;
205             $items{$file}++;
206             }
207             closedir DIR;
208             }
209              
210             return sort keys %items;
211             }
212              
213              
214             =item B
215              
216             $library->reset;
217              
218             Erase all entries from the cache.
219              
220             =cut
221              
222             sub reset {
223             my ($self) = @_;
224              
225             foreach my $tag (keys %$self) {
226             delete $self->{TAGS};
227             }
228             }
229              
230             1;
231              
232             =head1 AUTHOR
233              
234             Jason W. May
235              
236             =head1 COPYRIGHT
237              
238             Copyright (C) 2001,2002 Jason W. May. All rights reserved.
239             This module is free software; you can redistribute it and/or
240             modify it under the same terms as Perl itself.
241              
242             =cut