File Coverage

blib/lib/Data/Library/ManyPerFile.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::ManyPerFile;
2 1     1   16726 use base qw(Data::Library);
  1         2  
  1         584  
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 1     1   1496 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::ManyPerFile - multiple-queries-per-file
19             support class for Data
20              
21             =head1 SYNOPSIS
22              
23             Provides repository service to Data. This package
24             supports SQL in template files, where each file contains one
25             or more query blocks.
26              
27             =head1 DESCRIPTION
28              
29             Format of queries in a template file is as follows:
30              
31             queryname1:
32              
33             [One or more SQL statements]
34              
35             ;;
36              
37             Query name must start at beginning of line and end with a colon.
38             Terminate is a pair of semicolons on a line by itself.
39              
40             When searching through the repository for a matching tag, the first
41             match will be used. Conflicts are not detected.
42              
43             ManyPerFile recognizes when a query file is changed, and will
44             instruct Data to reload the query from the file.
45              
46             =head1 METHODS
47              
48             =cut
49              
50             require 5.004;
51             use strict;
52             use Carp;
53              
54             my %parameters = (
55             "LIB" => ".",
56             "EXTENSION" => "data",
57             );
58              
59             =item B
60              
61             my $library = new Data::Library::ManyPerFile
62             ({ name => "value" ... });
63              
64             Supported Library::ManyPerFile parameters:
65              
66             LIB Search path for SQL files. Defaults to [ "sql" ]
67              
68             EXTENSION Filename extension for SQL files. Defaults to ".sql"
69              
70             =cut
71              
72             sub new {
73             my ($proto, $config) = @_;
74             my $class = ref ($proto) || $proto;
75              
76             my $self = $config || {};
77              
78             bless ($self, $class);
79              
80             $self->_init;
81              
82             return $self;
83             }
84              
85              
86             sub _init {
87             my ($self) = shift;
88              
89             # verify input params and set defaults
90             # dies on any unknown parameter
91             # fills in the default for anything that is not provided
92              
93             foreach my $key (keys %$self) {
94             if (!exists $parameters{$key}) {
95             croak "Undefined ", __PACKAGE__, " parameter $key";
96             }
97             }
98              
99             foreach my $key (keys %parameters) {
100             $self->{$key} = $parameters{$key} unless defined $self->{$key};
101             }
102              
103             if ($self->{LIB} && !ref $self->{LIB}) {
104             $self->{LIB} = [ $self->{LIB} ];
105             }
106             }
107              
108              
109             sub lookup {
110             my ($self, $tag) = @_;
111              
112             lblog "LOOKUP $tag\n";
113              
114             if (! $self->_cache_valid($tag)) {
115             return;
116             }
117              
118             return $self->{TAGS}->{$tag}->{STMTS};
119             }
120              
121              
122             sub _cache_valid {
123             my ($self, $tag) = @_;
124              
125             return unless defined $self->{TAGS}->{$tag};
126             return unless defined $self->{TAGS}->{$tag}->{STMTS};
127              
128             return unless ($self->{TAGS}->{$tag}->{LOADTS}
129             >= (stat($self->{TAGS}->{$tag}->{FILE}))[9]);
130              
131             return 1;
132             }
133              
134              
135             sub find {
136             my ($self, $tag) = @_;
137              
138             lblog "FIND $tag\n";
139              
140             my $data;
141             my $thefile;
142             foreach my $lib (@{$self->{LIB}}) {
143             opendir (DIR, $lib) or croak "opendir $lib failed: $!";
144             my @files = sort grep { /^[^\.]/ && /\.$self->{EXTENSION}$/ && -r "$lib/$_" } readdir(DIR);
145             closedir (DIR);
146              
147             foreach my $file (@files) {
148             open (FILE, "$lib/$file") or croak "open $file failed: $!";
149             local $/ = undef;
150             my $body = ;
151             if ($body =~ /^$tag:/ms) {
152             ($data) = $body =~ /^$tag:\s*(.*?)\s*^;;/ms;
153             $thefile = "$lib/$file";
154             }
155             close (FILE);
156             last if $data;
157             }
158             last if $data;
159             }
160             if (! $data) {
161             # never found the tag in any file
162             carp "Unable to find tag $tag";
163             return;
164             }
165              
166             lblog "FOUND $tag in $thefile\n";
167              
168             $self->{TAGS}->{$tag}->{FILE} = $thefile;
169             $self->{TAGS}->{$tag}->{LOADTS} = (stat($self->{TAGS}->{$tag}->{FILE}))[9];
170              
171             return $data;
172             }
173              
174              
175             =item B
176              
177             $library->cache($tag, $data);
178              
179             Caches statement handles for later fetching via lookup().
180              
181             =cut
182              
183             sub cache {
184             my ($self, $tag, $data) = @_;
185              
186             lblog "CACHE $tag\n";
187              
188             $self->{TAGS}->{$tag}->{STMTS} = $data;
189             }
190              
191              
192             =item B
193              
194             my @array = $library->toc();
195              
196             Search through the library and return a list of all available entries.
197             Does not import any of the items.
198              
199             =cut
200              
201             sub toc {
202             my ($self) = @_;
203              
204             my %items;
205             foreach my $lib (@{$self->{LIB}}) {
206             opendir (DIR, $lib) or croak "opendir $lib failed: $!";
207             my @files = sort grep { /^[^\.]/ && /\.$self->{EXTENSION}$/ && -r "$lib/$_" } readdir(DIR);
208             closedir (DIR);
209              
210             foreach my $file (@files) {
211             open (FILE, "$lib/$file") or croak "open $file failed: $!";
212             local $/ = undef;
213             my $body = ;
214             close FILE;
215             foreach my $tag ($body =~ /^(\w+):/msg) {
216             $items{$tag}++;
217             }
218             }
219             }
220              
221             return sort keys %items;
222             }
223              
224              
225             =item B
226              
227             $library->reset;
228              
229             Erase all entries from the cache.
230              
231             =cut
232              
233             sub reset {
234             my ($self) = @_;
235              
236             foreach my $tag (keys %$self) {
237             delete $self->{TAGS};
238             }
239             }
240              
241              
242             1;
243              
244             =head1 AUTHOR
245              
246             Jason W. May
247              
248             =head1 COPYRIGHT
249              
250             Copyright (C) 2001 Jason W. May. All rights reserved.
251             This module is free software; you can redistribute it and/or
252             modify it under the same terms as Perl itself.