File Coverage

blib/lib/WebFetch/Data/Store.pm
Criterion Covered Total %
statement 63 110 57.2
branch 2 22 9.0
condition n/a
subroutine 14 25 56.0
pod 17 17 100.0
total 96 174 55.1


line stmt bran cond sub pod time code
1             # WebFetch::Data::Store
2             # ABSTRACT: WebFetch Embedding API top-level data store
3             #
4             # Copyright (c) 2009-2022 Ian Kluft. This program is free software; you can
5             # redistribute it and/or modify it under the terms of the GNU General Public
6             # License Version 3. See https://www.gnu.org/licenses/gpl-3.0-standalone.html
7             #
8             # The WebFetch Embedding API manages the following data:
9             # * {data} - top level hash container (WebFetch::Data::Store)
10             # * {fields} - array of field names
11             # * {records} - array of data records (WebFetch::Data::Record)
12             # * each record is an array of data fields in the order of the field names
13             # * {wk_names} - hash of WebFetch well-known fields to actual field names
14             # * {feed} - top-level arbitrary info about the feed
15             #
16              
17             # pragmas to silence some warnings from Perl::Critic
18             ## no critic (Modules::RequireExplicitPackage)
19             # This solves a catch-22 where parts of Perl::Critic want both package and use-strict to be first
20 3     3   1728 use strict;
  3         7  
  3         106  
21 3     3   18 use warnings;
  3         8  
  3         87  
22 3     3   19 use utf8;
  3         6  
  3         20  
23             ## use critic (Modules::RequireExplicitPackage)
24              
25             package WebFetch::Data::Store;
26             $WebFetch::Data::Store::VERSION = '0.15.8';
27 3     3   149 use strict;
  3         7  
  3         52  
28 3     3   32 use warnings;
  3         8  
  3         113  
29 3     3   17 use WebFetch;
  3         8  
  3         97  
30 3     3   16 use base qw( WebFetch );
  3         8  
  3         298  
31              
32             # define exceptions/errors
33 3     3   22 use Exception::Class ();
  3         8  
  3         3583  
34              
35             # no user-servicable parts beyond this point
36              
37             # instantiate new object
38             sub new
39             {
40 4     4 1 1008 my ( $class, @params ) = @_;
41 4         10 my $self = {};
42 4         11 bless $self, $class;
43 4         16 $self->init(@params);
44 4         16 return $self;
45             }
46              
47             # initialization
48             sub init
49             {
50 4     4 1 11 my ( $self, @params ) = @_;
51 4         19 $self->{fields} = [];
52 4         11 $self->{findex} = {};
53 4         9 $self->{records} = [];
54 4         7 $self->{wk_names} = {};
55 4         8 $self->{wkindex} = {};
56 4         7 $self->{feed} = {};
57              
58             # signal WebFetch that Data subclasses do not provide a fetch function
59 4         9 $self->{no_fetch} = 1;
60 4         19 $self->SUPER::init(@params);
61              
62 4         8 return $self;
63             }
64              
65             # add field names
66             sub add_fields
67             {
68 2     2 1 12 my ( $self, @fields ) = @_;
69 2         5 foreach my $field (@fields) {
70 18         21 $self->{findex}{$field} = scalar @{ $self->{fields} };
  18         52  
71 18         21 push @{ $self->{fields} }, $field;
  18         67  
72             }
73 2         7 return;
74             }
75              
76             # get number of fields
77             sub num_fields
78             {
79 0     0 1 0 my $self = shift;
80 0         0 return scalar @{ $self->{fields} };
  0         0  
81             }
82              
83             # get field names
84             sub get_fields
85             {
86 0     0 1 0 my $self = shift;
87 0         0 return keys %{ $self->{fields} };
  0         0  
88             }
89              
90             # get field name by number
91             sub field_bynum
92             {
93 0     0 1 0 my $self = shift;
94 0         0 my $num = shift;
95 0         0 return $self->{fields}[$num];
96             }
97              
98             # add well-known names
99             sub add_wk_names
100             {
101 2     2 1 4 my $self = shift;
102 2         4 my ( $wk_name, $field );
103              
104 2         8 while ( @_ >= 2 ) {
105 10         13 $wk_name = shift;
106 10         20 $field = shift;
107 10         32 WebFetch::debug "add_wk_names $wk_name => $field";
108 10         23 $self->{wk_names}{$wk_name} = $field;
109 10         33 $self->{wkindex}{$wk_name} = $self->{findex}{$field};
110             }
111 2         5 return;
112             }
113              
114             # get feed info
115             sub get_feed
116             {
117 0     0 1 0 my $self = shift;
118 0         0 my $name = shift;
119 0 0       0 return ( exists $self->{$name} ) ? $self->{$name} : undef;
120             }
121              
122             # set feed info
123             sub set_feed
124             {
125 0     0 1 0 my $self = shift;
126 0         0 my $name = shift;
127 0         0 my $value = shift;
128 0 0       0 my $retval = ( exists $self->{$name} ) ? $self->{$name} : undef;
129 0         0 $self->{$name} = $value;
130 0         0 return $retval;
131             }
132              
133             # add a data record
134             # this adds the field values in the same order the field names were added
135             sub add_record
136             {
137 33     33 1 99 my ( $self, @args ) = @_;
138 33         47 push @{ $self->{records} }, [@args];
  33         122  
139 33         86 return;
140             }
141              
142             # TODO: add a function add_record_unordered( name => value, ... )
143             # less efficient, but may be OK for cases where that doesn't matter
144              
145             # get the number of data records
146             sub num_records
147             {
148 0     0 1 0 my $self = shift;
149 0         0 return scalar @{ $self->{records} };
  0         0  
150             }
151              
152             # get a data record by index
153             sub get_record
154             {
155 0     0 1 0 my $self = shift;
156 0         0 my $n = shift;
157 0         0 WebFetch::debug "get_record $n";
158 0         0 require WebFetch::Data::Record;
159 0         0 return WebFetch::Data::Record->new( $self, $n );
160             }
161              
162             # reset iterator position
163             sub reset_pos
164             {
165 0     0 1 0 my $self = shift;
166              
167 0         0 WebFetch::debug "reset_pos";
168 0         0 delete $self->{pos};
169 0         0 return;
170             }
171              
172             # get next record
173             sub next_record
174             {
175 0     0 1 0 my $self = shift;
176              
177             # initialize if necessary
178 0 0       0 if ( !exists $self->{pos} ) {
179 0         0 $self->{pos} = 0;
180             }
181 0         0 WebFetch::debug "next_record n=" . $self->{pos} . " of " . scalar @{ $self->{records} };
  0         0  
182              
183             # return undef if position is out of bounds
184 0 0       0 ( $self->{pos} < 0 ) and return;
185 0 0       0 ( $self->{pos} > scalar @{ $self->{records} } - 1 ) and return;
  0         0  
186              
187             # get record
188 0         0 return $self->get_record( $self->{pos}++ );
189             }
190              
191             # convert well-known name to field name
192             sub wk2fname
193             {
194 0     0 1 0 my $self = shift;
195 0         0 my $wk = shift;
196              
197 0 0       0 WebFetch::debug "wk2fname $wk => " . ( ( exists $self->{wk_names}{$wk} ) ? $self->{wk_names}{$wk} : "undef" );
198             return ( exists $self->{wk_names}{$wk} )
199 0 0       0 ? $self->{wk_names}{$wk}
200             : undef;
201             }
202              
203             # convert a field name to a field number
204             sub fname2fnum
205             {
206 258     258 1 354 my $self = shift;
207 258         337 my $fname = shift;
208              
209             WebFetch::debug "fname2fnum $fname => "
210             . (
211             ( exists $self->{findex}{$fname} )
212 258 50       905 ? $self->{findex}{$fname}
213             : "undef"
214             );
215             return ( exists $self->{findex}{$fname} )
216 258 50       916 ? $self->{findex}{$fname}
217             : undef;
218             }
219              
220             # convert well-known name to field number
221             sub wk2fnum
222             {
223 0     0 1   my $self = shift;
224 0           my $wk = shift;
225              
226 0 0         WebFetch::debug "wk2fnum $wk => " . ( ( exists $self->{wkindex}{$wk} ) ? $self->{wkindex}{$wk} : "undef" );
227             return ( exists $self->{wkindex}{$wk} )
228 0 0         ? $self->{wkindex}{$wk}
229             : undef;
230             }
231              
232             1;
233              
234             __END__
235              
236             =pod
237              
238             =encoding UTF-8
239              
240             =head1 NAME
241              
242             WebFetch::Data::Store - WebFetch Embedding API top-level data store
243              
244             =head1 VERSION
245              
246             version 0.15.8
247              
248             =head1 SYNOPSIS
249              
250             use WebFetch::Data::Store;
251              
252             $data = webfetch_obj->data;
253             $data->add_fields( "field1", "field2", ... );
254             $num = $data->num_fields;
255             @field_names = $data->get_fields;
256             $name = $data->field_bynum( 3 );
257             $data->add_wk_names( "title" => "heading", "url" => "link", ... );
258             $value = $data->get_feed( $name );
259             $data->set_feed( $name, $value );
260             $data->add_record( $field1, $field2, ... ); # order corresponds to add_fields
261             $num = $data->num_records;
262             $record = $data->get_record( $n );
263             $data->reset_pos;
264             $record = $data->next_record;
265             $name = $data->wk2fname( $wk_name );
266             $num = $data->fname2fnum( $field_name );
267             $num = $data->wk2fnum( $wk_name );
268              
269             =head1 DESCRIPTION
270              
271             This module provides access to the WebFetch data.
272             WebFetch instantiates the object for the input module.
273             The input module uses this to construct the data set from its input.
274             The output module uses the this to access the data and
275             produce its output object/format.
276              
277             =over 4
278              
279             =item $obj->add_fields( "field1", "field2", ... );
280              
281             Add the field names in the order their values will appear in the data table.
282              
283             =item $num = $obj->num_fields;
284              
285             Returns the number of fields/columns in the data.
286              
287             =item @field_names = $obj->get_fields;
288              
289             Gets a list of the field names in the order their values appear in the data
290             table;
291              
292             =item $field_name = $obj->field_bynum( $num );
293              
294             Return a field name string based on the numeric position of the field.
295              
296             =item $obj->add_wk_names( "title" => "heading", "url" => "link", ... );
297              
298             Add associations between WebFetch well-known field names, which allows
299             WebFetch to apply meaning to these fields, such as titles, dates and URLs.
300             The parameters are pairs of well-known and actual field names.
301             Running this function more than once will add to the existing associations
302             of well-known to actual field names.
303              
304             =item $value = $obj->get_feed( $name );
305              
306             Get an item of per-feed data by name.
307              
308             =item $obj->set_feed( $name, $value );
309              
310             Set an item of per-feed data by name and value.
311              
312             =item $obj->add_record( $value1, $value2, $value3, ... );
313              
314             Add a row to the end of the data table. Values must correspond to the
315             positions of the field names that were provided earlier.
316              
317             =item $num = $obj->num_records;
318              
319             Get the number of records/rows in the data table.
320              
321             =item $record = get_record( $num );
322              
323             Returns a WebFetch::Data::Record object for the row located
324             by the given row number in the data table. The first row is numbered 0.
325             Calling this function does not affect the position used by the next_record
326             function.
327              
328             =item $obj->reset_pos;
329              
330             Reset the position counter used by the next_record function back to the
331             beginning of the data table.
332              
333             =item $record = $obj->next_record;
334              
335             The first call to this function returns the first record.
336             Each successive call to this function returns the following record until
337             the end of the data table.
338             After the last record, the function returns undef until
339             reset_pos is called to reset it back to the beginning.
340              
341             =item $obj->wk2fname( $wk )
342              
343             Obtain a field name from a well-known name.
344              
345             =item $obj->fname2fnum( $fname )
346              
347             Obtain a field number from a field name.
348              
349             =item $obj->wk2fnum( $wk )
350              
351             Obtain a field number from a well-known name.
352              
353             =back
354              
355             =head1 SEE ALSO
356              
357             L<WebFetch>, L<WebFetch::Data::Record>
358             L<https://github.com/ikluft/WebFetch>
359              
360             =head1 BUGS AND LIMITATIONS
361              
362             Please report bugs via GitHub at L<https://github.com/ikluft/WebFetch/issues>
363              
364             Patches and enhancements may be submitted via a pull request at L<https://github.com/ikluft/WebFetch/pulls>
365              
366             =head1 AUTHOR
367              
368             Ian Kluft <https://github.com/ikluft>
369              
370             =head1 COPYRIGHT AND LICENSE
371              
372             This software is Copyright (c) 1998-2023 by Ian Kluft.
373              
374             This is free software, licensed under:
375              
376             The GNU General Public License, Version 3, June 2007
377              
378             =cut