line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package List::Filter::Storage; |
2
|
1
|
|
|
1
|
|
294217
|
use base qw( Class::Base ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
898
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 NAME |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
List::Filter::Storage - storage handler for filters (e.g. filters) |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 SYNOPSIS |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use List::Filter::Storage; |
12
|
|
|
|
|
|
|
$stash_file = "$ENV{HOME}/project_filters.yaml"; |
13
|
|
|
|
|
|
|
my $filter_storage = List::Filter::Storage->new({ |
14
|
|
|
|
|
|
|
storage => [ $stash_file ], |
15
|
|
|
|
|
|
|
}); |
16
|
|
|
|
|
|
|
my $filter = List::Filter->new( |
17
|
|
|
|
|
|
|
{ name => 'skip_boring_stuff', |
18
|
|
|
|
|
|
|
terms => ['-\.vb$', '\-.js$'], |
19
|
|
|
|
|
|
|
method => 'skip_boring_stuff', |
20
|
|
|
|
|
|
|
description => "Skip the really boring stuff", |
21
|
|
|
|
|
|
|
modifiers => "xi", |
22
|
|
|
|
|
|
|
} ); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
$filter_storage->save( $filter ); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# And later, in some other code... |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $filter_storage = List::Filter::Storage->new({ storage => |
29
|
|
|
|
|
|
|
[ $stash_file ] }); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $filter = $filter_storage->lookup( 'skip_boring_stuff' ); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Filters lookd up from a path of storage locations: |
35
|
|
|
|
|
|
|
# (1) yaml file (2) a DBI database connection |
36
|
|
|
|
|
|
|
my $yaml_file = "/tmp/filter_storage.yaml"; |
37
|
|
|
|
|
|
|
my $lfs = List::Filter::Storage->new( { |
38
|
|
|
|
|
|
|
storage=> [ |
39
|
|
|
|
|
|
|
$yaml_file, |
40
|
|
|
|
|
|
|
{ format => 'DBI', |
41
|
|
|
|
|
|
|
connect_to => $connect_to, # e.g. "dbi:Pg:dbname=$dbname" |
42
|
|
|
|
|
|
|
owner => $owner, |
43
|
|
|
|
|
|
|
password => $password, |
44
|
|
|
|
|
|
|
}, |
45
|
|
|
|
|
|
|
] } ); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# storage format "MEM" keeps data in memory only |
49
|
|
|
|
|
|
|
my $lfs = List::Filter::Storage->new( { |
50
|
|
|
|
|
|
|
storage=> [ |
51
|
|
|
|
|
|
|
[ |
52
|
|
|
|
|
|
|
{ format => 'MEM', |
53
|
|
|
|
|
|
|
connect_to => {}, |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
] }); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# automatically make copies in the yaml file of any filters used from DBI |
58
|
|
|
|
|
|
|
my $filter_storage = List::Filter::Storage->new( |
59
|
|
|
|
|
|
|
{ save_filters_when_used => $args->{ save_filters_when_used }, |
60
|
|
|
|
|
|
|
storage => [ $yaml_file, |
61
|
|
|
|
|
|
|
{ format => 'DBI', |
62
|
|
|
|
|
|
|
connect_to => $connect_to, |
63
|
|
|
|
|
|
|
owner => $owner, |
64
|
|
|
|
|
|
|
password => $password, |
65
|
|
|
|
|
|
|
}, |
66
|
|
|
|
|
|
|
], |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
} ); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# a storage handler can save objects of type 'transform' |
71
|
|
|
|
|
|
|
# (a child of filter): |
72
|
|
|
|
|
|
|
my $storage_tran = List::Filter::Storage->new( |
73
|
|
|
|
|
|
|
{ storage => [ $stash_file ], |
74
|
|
|
|
|
|
|
type => 'transform', |
75
|
|
|
|
|
|
|
} ); |
76
|
|
|
|
|
|
|
$storage_tran->save( $transform ); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head1 DESCRIPTION |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
List::Filter::Storage is a "storage handler", it deals with |
83
|
|
|
|
|
|
|
multiple locations of different types of pluggable backing stores |
84
|
|
|
|
|
|
|
to save and retrieve "filters" (and variant types of filters such |
85
|
|
|
|
|
|
|
as 'transforms'). See L and L. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
To review the nature of the items that need to be stored: At the |
88
|
|
|
|
|
|
|
heart of a "filter" is an array reference called 'terms' which |
89
|
|
|
|
|
|
|
contains a list of arbitrary perl data structures. In the case |
90
|
|
|
|
|
|
|
of the simple 'filter" type, this is a list of regular |
91
|
|
|
|
|
|
|
expressions, in the case of 'transform' it's a list of array |
92
|
|
|
|
|
|
|
references, each containing the three parts of a perl |
93
|
|
|
|
|
|
|
substitution (in an unusual order, counting from 1 to 3: s/1/3/2). |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
Also, in addition to this list of 'terms', each filter object |
96
|
|
|
|
|
|
|
also has some attached to it some additional fields of data: |
97
|
|
|
|
|
|
|
'name', 'method', 'modifiers', and 'description'. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
So this might be thought of an ORM system, except that it's much |
100
|
|
|
|
|
|
|
more specialized (or perhaps "even more braindead") than ORMs |
101
|
|
|
|
|
|
|
usually are. Also, while it can use a database as a backing |
102
|
|
|
|
|
|
|
store (via DBI), the default storage system is simply to dump the |
103
|
|
|
|
|
|
|
data to YAML files, which have the advantage of being relatively |
104
|
|
|
|
|
|
|
easy to read and edit. |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head2 METHODS |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=over |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=cut |
111
|
|
|
|
|
|
|
|
112
|
1
|
|
|
1
|
|
1554
|
use 5.8.0; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
54
|
|
113
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
25
|
|
114
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
115
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
81
|
|
116
|
1
|
|
|
1
|
|
8
|
use Data::Dumper; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
58
|
|
117
|
1
|
|
|
1
|
|
1079
|
use Hash::Util qw( lock_keys unlock_keys ); |
|
1
|
|
|
|
|
3413
|
|
|
1
|
|
|
|
|
8
|
|
118
|
1
|
|
|
1
|
|
985
|
use List::Filter::Internal; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
37
|
|
119
|
1
|
|
|
1
|
|
7
|
use File::Path qw(mkpath); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
48
|
|
120
|
1
|
|
|
1
|
|
6
|
use File::Basename qw(dirname fileparse); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
49
|
|
121
|
1
|
|
|
1
|
|
6
|
use Env qw(HOME); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
122
|
1
|
|
|
1
|
|
165
|
use YAML qw(DumpFile LoadFile); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
63
|
|
123
|
1
|
|
|
1
|
|
1035
|
use Module::List::Pluggable qw( list_modules_under import_modules ); |
|
1
|
|
|
|
|
26748
|
|
|
1
|
|
|
|
|
2031
|
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
126
|
|
|
|
|
|
|
my $DEBUG = 0; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item new |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Instantiates a new List::Filter::Storage object. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Takes an optional hashref as an argument, with named fields |
133
|
|
|
|
|
|
|
identical to the names of the object attributes. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
With no arguments creates a storage handler using the |
136
|
|
|
|
|
|
|
default values: we're assumed to be storing data of type |
137
|
|
|
|
|
|
|
"filter" in a "filters.yaml" file located in the |
138
|
|
|
|
|
|
|
".list-filter" subdirectory of the users home directory. |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
Optional arguments: |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=over |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item type |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
scalar: the type of the filter to be stored (e.g. 'filter', 'transform') |
147
|
|
|
|
|
|
|
Default: 'filter' |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item storage |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
aref: a search path of yaml files or hrefs specifying less |
152
|
|
|
|
|
|
|
commonly used storage formats (DBI, MEM, CODE, etc) |
153
|
|
|
|
|
|
|
Filter look-ups try each one in sequence. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
If not specified, defaults to a single yaml file in a dot |
156
|
|
|
|
|
|
|
location in the $HOME directory. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Valid entries in the storage path are described in more detail |
159
|
|
|
|
|
|
|
below in L"the storage search path"> |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item write_storage |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
By default filters are saved to the first place in the storage path. |
164
|
|
|
|
|
|
|
Setting this field should be done to save to an alternate location. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
(This may or may not be a location present in the storage path, |
167
|
|
|
|
|
|
|
but it almost always will be, or else you would then be saving |
168
|
|
|
|
|
|
|
things you couldn't see again later. Sometimes though, you might |
169
|
|
|
|
|
|
|
want to do this, e.g. when copying filters from one location to |
170
|
|
|
|
|
|
|
another.) |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=item save_filters_when_used |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
A flag to indicate that copies of any filters that are used |
175
|
|
|
|
|
|
|
should be saved off to the "write_storage" location. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=back |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=cut |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# Note: "new" (inherited from Class::Base) |
182
|
|
|
|
|
|
|
# calls the following "init" routine automatically. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=item init |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Initialize object attributes and then lock them down to prevent |
187
|
|
|
|
|
|
|
accidental creation of new ones. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Note: there is no leading underscore on name "init", though it's |
190
|
|
|
|
|
|
|
arguably an "internal" routine (i.e. not likely to be of use to |
191
|
|
|
|
|
|
|
client code). |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=cut |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub init { |
196
|
26
|
|
|
26
|
1
|
126949
|
my $self = shift; |
197
|
26
|
|
|
|
|
53
|
my $args = shift; |
198
|
26
|
|
|
|
|
48
|
unlock_keys( %{ $self } ); |
|
26
|
|
|
|
|
119
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# get names of all modules under List::Filter::Storage |
201
|
26
|
|
|
|
|
246
|
my $storage_plugins = list_modules_under( 'List::Filter::Storage'); |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# create a lookup hash to check for existence of a plugin |
204
|
26
|
|
|
|
|
23399
|
my %lookup; |
205
|
26
|
|
|
|
|
49
|
@lookup{ @{ $storage_plugins } } = (1) x @{ $storage_plugins }; |
|
26
|
|
|
|
|
111
|
|
|
26
|
|
|
|
|
82
|
|
206
|
26
|
|
|
|
|
66
|
my $storage_plugin_lookup = \%lookup; |
207
|
26
|
|
|
|
|
112
|
$self->set_storage_plugin_lookup( $storage_plugin_lookup ); # later init code needs this |
208
|
|
|
|
|
|
|
|
209
|
26
|
|
100
|
|
|
173
|
my $type = $args->{ type } || 'filter'; |
210
|
26
|
|
|
|
|
90
|
$self->set_type( $type ); # later init code needs this |
211
|
|
|
|
|
|
|
|
212
|
26
|
|
|
|
|
210
|
my $lfi = List::Filter::Internal->new(); |
213
|
|
|
|
|
|
|
my $storage = $lfi->qualify_storage_from_namespace( |
214
|
|
|
|
|
|
|
$args->{ storage }, |
215
|
26
|
|
|
|
|
184
|
$type, |
216
|
|
|
|
|
|
|
); |
217
|
|
|
|
|
|
|
|
218
|
26
|
|
|
|
|
111
|
my $storage_objects = $self->define_storage_objects( $storage ); |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# First entry in storage attribute is the default location to save to |
221
|
26
|
|
33
|
|
|
135
|
my $write_storage = $args->{write_storage} || $storage->[0]; |
222
|
26
|
|
|
|
|
69
|
my $write_storage_object = $self->objectify_storage( $write_storage ); |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# define new attributes |
225
|
|
|
|
|
|
|
my $attributes = { |
226
|
|
|
|
|
|
|
type => $type, |
227
|
|
|
|
|
|
|
storage => $storage, # aref |
228
|
|
|
|
|
|
|
write_storage => $write_storage, # scalar |
229
|
|
|
|
|
|
|
save_filters_when_used => $args->{ save_filters_when_used }, # boolean |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# internal use |
232
|
26
|
|
|
|
|
192
|
write_storage_object => $write_storage_object, # scalar |
233
|
|
|
|
|
|
|
storage_objects => $storage_objects, # aref |
234
|
|
|
|
|
|
|
storage_plugin_lookup => $storage_plugin_lookup, # href |
235
|
|
|
|
|
|
|
}; |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# add attributes to object |
238
|
26
|
|
|
|
|
51
|
my @fields = (keys %{ $attributes }); |
|
26
|
|
|
|
|
133
|
|
239
|
26
|
|
|
|
|
65
|
@{ $self }{ @fields } = @{ $attributes }{ @fields }; # hash slice |
|
26
|
|
|
|
|
134
|
|
|
26
|
|
|
|
|
131
|
|
240
|
|
|
|
|
|
|
|
241
|
26
|
|
|
|
|
55
|
lock_keys( %{ $self } ); |
|
26
|
|
|
|
|
95
|
|
242
|
26
|
|
|
|
|
360
|
return $self; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item lookup |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Given a filter name, returns a matching filter object, or undef. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
Interates over the storage path, looking in each until a matching |
250
|
|
|
|
|
|
|
name has been found. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
If the lookup fails it returns undef, emitting the warning: |
253
|
|
|
|
|
|
|
"Failed lookup of $type with name: $name"; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=cut |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub lookup { |
258
|
13
|
|
|
13
|
1
|
4022
|
my $self = shift; |
259
|
13
|
|
|
|
|
31
|
my $name = shift; |
260
|
13
|
|
|
|
|
35
|
my $storage_objects = $self->{storage_objects}; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# interate over storage path, look in each until a matching |
263
|
|
|
|
|
|
|
# name has been found. |
264
|
|
|
|
|
|
|
|
265
|
13
|
|
|
|
|
21
|
my $filter; |
266
|
13
|
|
|
|
|
26
|
foreach my $storage_handle ( @{ $storage_objects } ) { |
|
13
|
|
|
|
|
33
|
|
267
|
14
|
100
|
|
|
|
69
|
if ( $filter = $storage_handle->lookup( $name ) ) { |
268
|
12
|
|
|
|
|
31
|
last; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
13
|
100
|
|
|
|
48
|
unless( $filter ) { |
273
|
1
|
|
|
|
|
6
|
my $type = $self->type; |
274
|
1
|
|
|
|
|
210
|
carp "Failed lookup of $type with name: $name"; |
275
|
1
|
|
|
|
|
119
|
return; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
# let the filter know where it came from |
279
|
12
|
|
|
|
|
61
|
$filter->set_storage_handler( $self ); |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# pass on the flag setting to the filter |
282
|
12
|
50
|
|
|
|
44
|
if( $self->save_filters_when_used ) { |
283
|
0
|
|
|
|
|
0
|
$filter->set_save_filters_when_used( 1 ); |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
12
|
|
|
|
|
62
|
return $filter; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=item save |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Save the given filter object. |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
Returns a copy of it. |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=cut |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub save { |
298
|
11
|
|
|
11
|
1
|
115
|
my $self = shift; |
299
|
11
|
|
|
|
|
18
|
my $filter = shift; |
300
|
|
|
|
|
|
|
|
301
|
11
|
|
|
|
|
49
|
my $wso = $self->write_storage_object; |
302
|
11
|
|
|
|
|
68
|
$wso->save( $filter ); |
303
|
11
|
|
|
|
|
51
|
return $filter; # more likely to be a useful return than $self |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=item define_storage_objects |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Converts the array of storage locations into an array of |
309
|
|
|
|
|
|
|
storage objects to make "lookups" simpler. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=cut |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub define_storage_objects { |
314
|
26
|
|
|
26
|
1
|
38
|
my $self = shift; |
315
|
26
|
|
|
|
|
47
|
my $storage = shift; |
316
|
|
|
|
|
|
|
|
317
|
26
|
|
|
|
|
50
|
my @storage_objects = (); |
318
|
26
|
|
|
|
|
35
|
foreach my $stash (@{ $storage }){ |
|
26
|
|
|
|
|
69
|
|
319
|
27
|
|
|
|
|
89
|
my $storage_object = $self->objectify_storage( $stash ); |
320
|
27
|
|
|
|
|
85
|
push @storage_objects, $storage_object; |
321
|
|
|
|
|
|
|
} |
322
|
26
|
|
|
|
|
67
|
return \@storage_objects; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=item objectify_storage |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
Convert an entry from the storage path into an object of the |
328
|
|
|
|
|
|
|
appropriate class: List::Filter::Storage::* |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=cut |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# Determines the type of storage requested (YAML, DBI, etc.) |
333
|
|
|
|
|
|
|
# and does a "require" of the appropriate plugin, or croaks |
334
|
|
|
|
|
|
|
# if it can't be found. |
335
|
|
|
|
|
|
|
sub objectify_storage { |
336
|
53
|
|
|
53
|
1
|
303
|
my $subname = ( caller(0) )[3]; |
337
|
53
|
|
|
|
|
100
|
my $self = shift; |
338
|
53
|
|
|
|
|
58
|
my $stash = shift; |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# allowed list of plugin formats (a hash ref) |
341
|
53
|
|
|
|
|
119
|
my $storage_plugin_lookup = $self->storage_plugin_lookup; |
342
|
|
|
|
|
|
|
|
343
|
53
|
|
|
|
|
86
|
my ($format, @plugin_name, $plugin_class, $db_type, |
344
|
|
|
|
|
|
|
$connect_to, $owner, $password, $attributes); |
345
|
|
|
|
|
|
|
|
346
|
53
|
100
|
|
|
|
117
|
if (ref $stash eq 'HASH') { |
347
|
|
|
|
|
|
|
|
348
|
35
|
|
|
|
|
78
|
$format = $stash->{format}; |
349
|
35
|
|
|
|
|
60
|
$connect_to = $stash->{connect_to}; |
350
|
35
|
|
|
|
|
61
|
$owner = $stash->{owner}; |
351
|
35
|
|
|
|
|
48
|
$password = $stash->{password}; |
352
|
35
|
|
|
|
|
46
|
$attributes = $stash->{attributes}; |
353
|
|
|
|
|
|
|
|
354
|
35
|
|
|
|
|
80
|
push @plugin_name, uc( $format ); |
355
|
|
|
|
|
|
|
|
356
|
35
|
50
|
|
|
|
102
|
if ($format eq 'DBI') { |
357
|
0
|
|
|
|
|
0
|
require DBI; |
358
|
0
|
|
|
|
|
0
|
$db_type = ( split ":", $connect_to )[1]; |
359
|
0
|
|
|
|
|
0
|
my $specific_plugin = "DBI::$db_type"; |
360
|
0
|
|
|
|
|
0
|
push @plugin_name, $specific_plugin; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
} else { # if not href, $stash is a file name, extension determines format |
364
|
18
|
|
|
|
|
20
|
$connect_to = $stash; |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# examine the string, looking for a file-extension. |
367
|
18
|
|
|
|
|
73
|
my $ext_pat = qr{ (?<=\.) [^.]{0,5} $ }x; |
368
|
|
|
|
|
|
|
# extension up to 5 chars, sans dot |
369
|
18
|
|
|
|
|
519
|
my $extension = ( fileparse($stash, $ext_pat ) )[2]; |
370
|
|
|
|
|
|
|
|
371
|
18
|
|
|
|
|
72
|
push @plugin_name, uc( $extension ); |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# does a plugin exist? For DBI plugins, use database-specific |
375
|
|
|
|
|
|
|
# one if available. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
PLUGIN: |
378
|
53
|
|
|
|
|
103
|
foreach my $plugin_name (@plugin_name) { |
379
|
53
|
|
|
|
|
90
|
$plugin_class = "List::Filter::Storage::$plugin_name"; |
380
|
53
|
50
|
|
|
|
153
|
if ( $storage_plugin_lookup->{ $plugin_class } ) { |
381
|
53
|
|
|
|
|
118
|
last PLUGIN; |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
} continue { |
384
|
0
|
|
|
|
|
0
|
my $mess = "No storage plug-in found for format $format"; |
385
|
0
|
0
|
|
|
|
0
|
$mess .= " (db type: $db_type)" if $db_type; |
386
|
0
|
|
|
|
|
0
|
croak $mess; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
# "last PLUGIN" jumps to here |
389
|
|
|
|
|
|
|
|
390
|
53
|
|
|
|
|
3482
|
eval "require $plugin_class"; |
391
|
53
|
50
|
|
|
|
238
|
if ($@) { |
392
|
0
|
|
|
|
|
0
|
die "Could not require $plugin_class: $@\n"; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
53
|
|
|
|
|
142
|
my $type = $self->type; |
396
|
53
|
|
|
|
|
463
|
my $storage_obj = $plugin_class->new( |
397
|
|
|
|
|
|
|
{ connect_to => $connect_to, |
398
|
|
|
|
|
|
|
owner => $owner, |
399
|
|
|
|
|
|
|
password => $password, |
400
|
|
|
|
|
|
|
attributes => $attributes, |
401
|
|
|
|
|
|
|
type => $type, # type of filters to store |
402
|
|
|
|
|
|
|
} ); |
403
|
|
|
|
|
|
|
|
404
|
53
|
|
|
|
|
7406
|
return $storage_obj; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=item list_filters |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
Returns a list of all avaliable named filters. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=cut |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
sub list_filters { |
416
|
2
|
|
|
2
|
1
|
34
|
my $self = shift; |
417
|
|
|
|
|
|
|
|
418
|
2
|
|
|
|
|
4
|
my %uniq = (); |
419
|
2
|
|
|
|
|
8
|
my $storage_objects = $self->storage_objects; |
420
|
2
|
|
|
|
|
4
|
foreach my $store (@{ $storage_objects}) { |
|
2
|
|
|
|
|
5
|
|
421
|
2
|
|
|
|
|
14
|
my $add_filters = $store->list_filters; |
422
|
2
|
|
|
|
|
5
|
@uniq{ @{ $add_filters } } = (1) x @{ $add_filters }; |
|
2
|
|
|
|
|
26
|
|
|
2
|
|
|
|
|
5
|
|
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
2
|
|
|
|
|
18
|
my @filters = keys( %uniq ); |
426
|
2
|
|
|
|
|
15
|
return \@filters; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=back |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head2 Basic accessors (setters use "set_" prefix, getters have none) |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=over |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=item type |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Getter for object attribute type |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=cut |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
sub type { |
444
|
54
|
|
|
54
|
1
|
82
|
my $self = shift; |
445
|
54
|
|
|
|
|
89
|
my $type = $self->{ type }; |
446
|
54
|
|
|
|
|
114
|
return $type; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=item set_type |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Setter for object attribute set_type |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=cut |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
sub set_type { |
456
|
26
|
|
|
26
|
1
|
40
|
my $self = shift; |
457
|
26
|
|
|
|
|
59
|
my $type = shift; |
458
|
26
|
|
|
|
|
64
|
$self->{ type } = $type; |
459
|
26
|
|
|
|
|
44
|
return $type; |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=item storage |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
Getter for object attribute storage |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=cut |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub storage { |
469
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
470
|
0
|
|
|
|
|
0
|
my $storage = $self->{ storage }; |
471
|
0
|
|
|
|
|
0
|
return $storage; |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
=item set_storage |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
Setter for object attribute set_storage |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=cut |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
sub set_storage { |
481
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
482
|
0
|
|
|
|
|
0
|
my $storage = shift; |
483
|
0
|
|
|
|
|
0
|
$self->{ storage } = $storage; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
# if this is changed, keep storage_objects in sync |
486
|
0
|
|
|
|
|
0
|
my $storage_objects = $self->define_storage_objects( $storage ); |
487
|
0
|
|
|
|
|
0
|
$self->set_storage_objects( $storage_objects ); |
488
|
|
|
|
|
|
|
|
489
|
0
|
|
|
|
|
0
|
return $storage; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=item write_storage |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
Getter for object attribute write_storage |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=cut |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub write_storage { |
500
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
501
|
0
|
|
|
|
|
0
|
my $write_storage = $self->{ write_storage }; |
502
|
0
|
|
|
|
|
0
|
return $write_storage; |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=item set_write_storage |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
Setter for object attribute set_write_storage. |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
Note, this also automatically sets write_storage_object. |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=cut |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
sub set_write_storage { |
514
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
515
|
0
|
|
|
|
|
0
|
my $write_storage = shift; |
516
|
0
|
|
|
|
|
0
|
$self->{ write_storage } = $write_storage; |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
# if this is changed, keep the object form of this in sync |
519
|
0
|
|
|
|
|
0
|
my $write_storage_object = $self->objectify_storage( $write_storage ); |
520
|
0
|
|
|
|
|
0
|
$self->set_write_storage_object( $write_storage_object ); |
521
|
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
0
|
return $write_storage; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=item save_filters_when_used |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
Getter for object attribute save_filters_when_used |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=cut |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub save_filters_when_used { |
534
|
12
|
|
|
12
|
1
|
19
|
my $self = shift; |
535
|
12
|
|
|
|
|
30
|
my $save_filters_when_used = $self->{ save_filters_when_used }; |
536
|
12
|
|
|
|
|
34
|
return $save_filters_when_used; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=item set_save_filters_when_used |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
Setter for object attribute set_save_filters_when_used |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=cut |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
sub set_save_filters_when_used { |
546
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
547
|
0
|
|
|
|
|
0
|
my $save_filters_when_used = shift; |
548
|
0
|
|
|
|
|
0
|
$self->{ save_filters_when_used } = $save_filters_when_used; |
549
|
0
|
|
|
|
|
0
|
return $save_filters_when_used; |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
=item write_storage_object |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
Getter for object attribute write_storage_object. |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=cut |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
sub write_storage_object { |
560
|
11
|
|
|
11
|
1
|
20
|
my $self = shift; |
561
|
11
|
|
|
|
|
26
|
my $write_storage_object = $self->{ write_storage_object }; |
562
|
11
|
|
|
|
|
25
|
return $write_storage_object; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=item set_write_storage_object |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
Setter for object attribute set_write_storage_object |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
=cut |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub set_write_storage_object { |
572
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
573
|
0
|
|
|
|
|
0
|
my $write_storage_object = shift; |
574
|
0
|
|
|
|
|
0
|
$self->{ write_storage_object } = $write_storage_object; |
575
|
0
|
|
|
|
|
0
|
return $write_storage_object; |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=item storage_plugin_lookup |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
Getter for object attribute storage_plugin_lookup |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=cut |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
sub storage_plugin_lookup { |
585
|
53
|
|
|
53
|
1
|
86
|
my $self = shift; |
586
|
53
|
|
|
|
|
84
|
my $storage_plugin_lookup = $self->{ storage_plugin_lookup }; |
587
|
|
|
|
|
|
|
|
588
|
53
|
|
|
|
|
91
|
return $storage_plugin_lookup; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=item set_storage_plugin_lookup |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
Setter for object attribute set_storage_plugin_lookup |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=cut |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub set_storage_plugin_lookup { |
598
|
26
|
|
|
26
|
1
|
50
|
my $self = shift; |
599
|
26
|
|
|
|
|
42
|
my $storage_plugin_lookup = shift; |
600
|
26
|
|
|
|
|
70
|
$self->{ storage_plugin_lookup } = $storage_plugin_lookup; |
601
|
26
|
|
|
|
|
58
|
return $storage_plugin_lookup; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=item storage_objects |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
Getter for object attribute storage_objects |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=cut |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub storage_objects { |
611
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
612
|
2
|
|
|
|
|
3
|
my $storage_objects = $self->{ storage_objects }; |
613
|
2
|
|
|
|
|
5
|
return $storage_objects; |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=item set_storage_objects |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Setter for object attribute set_storage_objects |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=cut |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub set_storage_objects { |
623
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
624
|
0
|
|
|
|
|
|
my $storage_objects = shift; |
625
|
0
|
|
|
|
|
|
$self->{ storage_objects } = $storage_objects; |
626
|
0
|
|
|
|
|
|
return $storage_objects; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
1; |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=back |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=head1 MOTIVATION |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
L was designed to answer an immediate need |
636
|
|
|
|
|
|
|
of the L project: to provide a way to share |
637
|
|
|
|
|
|
|
"filters" among different applications. This in itself is |
638
|
|
|
|
|
|
|
requires only a very light-duty storage apparatus (dumping to |
639
|
|
|
|
|
|
|
L files will most likely be more than adequate). |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
But in order to hold open the door that List::Filter might |
642
|
|
|
|
|
|
|
someday need to scale larger than it's current intended purposes |
643
|
|
|
|
|
|
|
(writing command line utilities, and so on), it seemed logical to |
644
|
|
|
|
|
|
|
allow the use of storage facilities that allow concurrent, shared |
645
|
|
|
|
|
|
|
access, and this could be done most obviously via L. |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
(However: this project makes no use whatsover of the "relational" |
648
|
|
|
|
|
|
|
aspects of an RDBMS, and I offer my sincere apologies if this |
649
|
|
|
|
|
|
|
seems to be part of a disturbing trend -- remember, providing for |
650
|
|
|
|
|
|
|
DBI storage I already seems like over-kill for this |
651
|
|
|
|
|
|
|
project. And qualifying perl regular expressions with a |
652
|
|
|
|
|
|
|
relational database is a bit beyond the current scope.) |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
So, having gone that far, I took the project one step further, |
655
|
|
|
|
|
|
|
and provided a plug-in extension mechanism so that other storage |
656
|
|
|
|
|
|
|
formats could be defined in the future. Possibilities include: |
657
|
|
|
|
|
|
|
XML, TSV, CSV, INI... and so on. |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
=head2 the storage search path |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
The "storage" search path hopefully seems like a straight-forward |
663
|
|
|
|
|
|
|
concept (search paths are common enough: the PATH environment |
664
|
|
|
|
|
|
|
variable, the perl @INC array, etc.). However, the syntax of the |
665
|
|
|
|
|
|
|
"storage" attribute may seem a little peculiar: the general idea |
666
|
|
|
|
|
|
|
is to make it indefinitely extensible without making the most |
667
|
|
|
|
|
|
|
likely immediate uses excessively complex. |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
The most common thing (or so I imagine) is to just use a single |
670
|
|
|
|
|
|
|
yaml file in your home directory, so that's the default if no |
671
|
|
|
|
|
|
|
"storage" is specified: |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
~/.list-filter/filters.yaml |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
There might be some need for more than one of these files (say, a |
676
|
|
|
|
|
|
|
private one and a shared, or perhaps multiple ones for different |
677
|
|
|
|
|
|
|
projects), so that's the next most simple case: an array reference |
678
|
|
|
|
|
|
|
of multiple file paths. |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
If a file path is specified, the file extension is used to |
681
|
|
|
|
|
|
|
determine the format. Currently YAML is the only one supported, |
682
|
|
|
|
|
|
|
but plugins can be added for other formats (csv, etc.). |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
In order to specify something like a DBI database connection, we |
685
|
|
|
|
|
|
|
need a more complicated data-structure, so rather than simple |
686
|
|
|
|
|
|
|
scalars, a hash reference can appear in the storage path. With a |
687
|
|
|
|
|
|
|
hash ref, the format of the storage is spelled out explicitly, |
688
|
|
|
|
|
|
|
along with various other connection parameters that might be |
689
|
|
|
|
|
|
|
needed. This is discussed further in the following sections. |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
=head2 storage location hash references |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
The "storage" object attribute is designed to be very simple to |
694
|
|
|
|
|
|
|
use in the most common cases (see the discussion above). |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
The next step up in complexity beyond a single yaml file, is to |
697
|
|
|
|
|
|
|
use an array reference of storage locations that are searched in |
698
|
|
|
|
|
|
|
given sequence: a scalar element of this array is presumed to be |
699
|
|
|
|
|
|
|
a path to a data file. If the element is a hash reference, it |
700
|
|
|
|
|
|
|
can be used to specify something else, most commonly some sort of |
701
|
|
|
|
|
|
|
database accessed via DBI. |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
An example of intermixing DBI storage with a yaml file: |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
# Filters lookd up from a path of storage locations: |
706
|
|
|
|
|
|
|
# (1) yaml file (2) a DBI database connection |
707
|
|
|
|
|
|
|
my $yaml_file = "/tmp/filter_storage.yaml"; |
708
|
|
|
|
|
|
|
my $lfs = List::Filter::Storage->new( { |
709
|
|
|
|
|
|
|
storage=> [ |
710
|
|
|
|
|
|
|
$yaml_file, |
711
|
|
|
|
|
|
|
{ format => 'DBI', |
712
|
|
|
|
|
|
|
connect_to => $connect_to, |
713
|
|
|
|
|
|
|
owner => $owner, |
714
|
|
|
|
|
|
|
password => $password, |
715
|
|
|
|
|
|
|
}, |
716
|
|
|
|
|
|
|
] } ); |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
Note the fields in the hash reference in the second position in |
719
|
|
|
|
|
|
|
the storage array: The first is "format" (which obviously, is |
720
|
|
|
|
|
|
|
defined as 'DBI' in the case of DBI access), and the remaining |
721
|
|
|
|
|
|
|
three fields will no doubt seem familiar from L. |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
In the case of the 'DBI' format, these three parameters are |
724
|
|
|
|
|
|
|
passed through to the DBI module to create a database handle used |
725
|
|
|
|
|
|
|
internally. For example, postgresql, the "connect_to" would be: |
726
|
|
|
|
|
|
|
"dbi:Pg:dbname=$dbname". |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
These fields can have a different meaning for different storage |
729
|
|
|
|
|
|
|
formats, e.g. in the case of the 'MEM' (in-memory) format, the |
730
|
|
|
|
|
|
|
"connect_to" parameter takes an href of hrefs containing |
731
|
|
|
|
|
|
|
filter data in a format similar to what you see inside the yaml files. |
732
|
|
|
|
|
|
|
See L. |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=head2 Storage formats |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
Storage formats (e.g. 'DBI', 'YAML', 'MEM', etc.) are defined |
737
|
|
|
|
|
|
|
using a plug-in system, so that new types may be defined at a |
738
|
|
|
|
|
|
|
later date, all of them are named with the form |
739
|
|
|
|
|
|
|
List::Filter::Storage::. |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
For the special case of DBI handles, it is possible to define a |
742
|
|
|
|
|
|
|
database specific format handler that will over-ride the generic |
743
|
|
|
|
|
|
|
L. These should be named following |
744
|
|
|
|
|
|
|
the convention List::Filter::Storage::DBI::, where |
745
|
|
|
|
|
|
|
should match an existing DBD:: driver (e.g. "Pg" for the |
746
|
|
|
|
|
|
|
postgresql database: L). |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
As mentioned above, in the case of the 'MEM' format, the |
749
|
|
|
|
|
|
|
"connect_to" is used to point to a data structure. Other formats |
750
|
|
|
|
|
|
|
are free to use these connection parameters as they like. For |
751
|
|
|
|
|
|
|
example, a 'LWP' format might be written some day where the |
752
|
|
|
|
|
|
|
"connect_to" is a URL. |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
At present, documentation on how to write the code to handle a new |
755
|
|
|
|
|
|
|
storage format is very limited. It's suggested that you use the |
756
|
|
|
|
|
|
|
existing format definition modules as examples: |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
L |
759
|
|
|
|
|
|
|
L |
760
|
|
|
|
|
|
|
L |
761
|
|
|
|
|
|
|
L |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
=head1 SEE ALSO |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
L |
766
|
|
|
|
|
|
|
L |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=head1 AUTHOR |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
Joseph Brenner, Edoom@kzsu.stanford.eduE, |
771
|
|
|
|
|
|
|
18 May 2007 |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
Copyright (C) 2007 by Joseph Brenner |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
778
|
|
|
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.8.2 or, |
779
|
|
|
|
|
|
|
at your option, any later version of Perl 5 you may have available. |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=head1 BUGS |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
None reported... yet. |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
=cut |