File Coverage

blib/lib/Metadata/Base.pm
Criterion Covered Total %
statement 139 214 64.9
branch 59 110 53.6
condition 13 15 86.6
subroutine 21 34 61.7
pod 24 30 80.0
total 256 403 63.5


line stmt bran cond sub pod time code
1             # Hey emacs, this is -*-perl-*- !
2             #
3             # $Id: Base.pm,v 1.10 2001/01/09 12:04:12 cmdjb Exp $
4             #
5             # Metadata::Base - base class for metadata
6             #
7             # Copyright (C) 1997-2001 Dave Beckett - http://purl.org/net/dajobe/
8             # All rights reserved.
9             #
10             # This module is free software; you can redistribute it and/or modify
11             # it under the same terms as Perl itself.
12             #
13              
14             package Metadata::Base;
15              
16             require 5.004;
17              
18 4     4   717 use strict;
  4         6  
  4         150  
19 4     4   23 use vars qw($VERSION $Debug);
  4         6  
  4         200  
20              
21 4     4   26 use Carp;
  4         10  
  4         12913  
22              
23             $VERSION = sprintf("%d.%02d", ('$Revision: 1.10 $ ' =~ /\$Revision:\s+(\d+)\.(\d+)/));
24              
25              
26             # Class debugging
27             $Debug = 0;
28              
29             sub debug {
30 0     0 1 0 my $self=shift;
31             # Object debug - have an object reference
32 0 0       0 if (ref ($self)) {
33 0         0 my $old=$self->{DEBUG};
34 0 0       0 $self->{DEBUG}=@_ ? shift : 1;
35 0         0 return $old;
36             }
37              
38             # Class debug (self is debug level)
39 0 0       0 return $Debug if !defined $self; # Careful, could be debug(0)
40              
41 0         0 my $old=$Debug;
42 0         0 $Debug=$self;
43 0         0 $old;
44             }
45              
46 0     0 0 0 sub whowasi { (caller(1))[3] }
47              
48              
49             # Constructor
50             sub new ($%) {
51 10     10 1 90 my ($type,$self)=@_;
52 10 100       131 $self = {} unless defined $self;
53              
54 10   33     61 my $class = ref($type) || $type;
55 10         141 bless $self, $class;
56              
57 10 100       58 $self->{DEBUG}=$Debug unless defined $self->{DEBUG};
58              
59 10         118 $self->{DEFAULT_OPTIONS}={ %$self };
60              
61             # Create empty order if needed
62 10 100       52 $self->{ORDER}=[] if $self->{ORDERED};
63              
64 10         35 $self->{ELEMENTS}={};
65 10         24 $self->{ELEMENTS_COUNT}=0;
66              
67 10 50       36 warn "@{[&whowasi]}\n" if $self->{DEBUG};
  0         0  
68              
69 10         36 $self;
70             }
71              
72              
73             # Clone
74             sub clone ($) {
75 0     0 1 0 my $self=shift;
76              
77 0         0 my $copy=new ref($self);
78              
79 0 0       0 my(@order)=$self->{ORDERED} ? @{$self->{ORDER}} : keys %{$self->{ELEMENTS}};
  0         0  
  0         0  
80 0         0 for my $element (@order) {
81 0         0 my(@values)=$self->get($element);
82 0         0 $copy->set($element, [ @values ]);
83             }
84              
85 0         0 $copy->{DEBUG}=$self->{DEBUG};
86 0         0 $copy->{DEFAULT_OPTIONS}={ %{$self->{DEFAULT_OPTIONS}} };
  0         0  
87              
88 0         0 $copy;
89             }
90              
91              
92             sub set ($$$;$) {
93 21     21 1 70 my $self=shift;
94 21         71 return $self->_set('set',@_);
95             }
96              
97              
98             sub add ($$$;$) {
99 4     4 0 17 my $self=shift;
100 4         9 return $self->_set('add',@_);
101             }
102              
103              
104             sub _set ($$$$;$) {
105 25     25   67 my $self=shift;
106 25         53 my $operation=shift;
107              
108 25         170 my($element,$value,$index)=$self->validate(@_);
109 25 100       102 return if !defined $element;
110              
111 24 100       74 if (!defined $self->{ELEMENTS}->{$element}) {
112             # Update order
113 21 100       200 push(@{$self->{ORDER}}, $element) if $self->{ORDERED};
  20         48  
114 21         35 $self->{ELEMENTS_COUNT}++;
115 21 50       63 warn "@{[&whowasi]} Adding new element $element\n" if $self->{DEBUG};
  0         0  
116             }
117              
118 24 50       55 if (ref($value)) { # Assuming eq 'ARRAY'
119 0         0 $self->{ELEMENTS}->{$element}=[ @$value ];
120 0 0       0 warn "@{[&whowasi]} Set $element to values @$value\n" if $self->{DEBUG};
  0         0  
121             } else {
122 24 100       44 if (defined $index) {
123             # Set new value at a particular index
124 4         18 $self->{ELEMENTS}->{$element}->[$index]=$value;
125             } else {
126 20 100       50 if ($operation eq 'add') {
127             # Append value to end of list
128 4         5 push(@{$self->{ELEMENTS}->{$element}}, $value);
  4         9  
129 4         6 $index=@{$self->{ELEMENTS}->{$element}} - 1;
  4         9  
130             } else {
131 16         26 $index='(all)';
132 16         61 $self->{ELEMENTS}->{$element}=[ $value ];
133             }
134             }
135 24 50       123 warn "@{[&whowasi]} Set $element subvalue $index to value $value\n" if $self->{DEBUG};
  0         0  
136             }
137             }
138              
139              
140             sub get ($$;$) {
141 31     31 1 462 my $self=shift;
142 31         51 my($element,$index)=@_;
143 31 0       87 warn "@{[&whowasi]} Get $element subvalue ", (defined $index) ? $index : "(undefined)","\n" if $self->{DEBUG};
  0 50       0  
144 31         167 ($element,$index)=$self->validate_elements($element,$index);
145 31 50       164 return if !defined $element;
146              
147 31 0       86 warn "@{[&whowasi]} After validate, element $element subvalue ", (defined $index) ? $index : "(undefined)", "\n" if $self->{DEBUG};
  0 50       0  
148              
149 31         63 my $value=$self->{ELEMENTS}->{$element};
150 31 100       72 return if !defined $value;
151              
152 30 100       694 if (defined $index) {
153 3         10 return $value->[$index];
154             } else {
155 27 100       171 return wantarray ? @$value : join(' ', grep (defined $_, @$value));
156             }
157             }
158              
159              
160             sub delete ($$;$) {
161 2     2 1 31 my $self=shift;
162 2         13 my($element,$index)=@_;
163 2 0       6 warn "@{[&whowasi]} element $element subvalue ", (defined $index) ? $index : "(undefined)","\n" if $self->{DEBUG};
  0 50       0  
164 2         5 ($element,$index)=$self->validate_elements($element,$index);
165 2 50       6 return if !defined $element;
166              
167 2 0       7 warn "@{[&whowasi]} After validate, element $element subvalue ", (defined $index) ? $index : "(undefined)", "\n" if $self->{DEBUG};
  0 50       0  
168              
169 2         4 my $value=$self->{ELEMENTS}->{$element};
170 2 50       9 return if !defined $value;
171              
172 2         3 my(@old)=@{$value};
  2         4  
173 2 50       6 if (defined $index) {
174 0         0 undef $value->[$index];
175             # Are all element subvalues missing / undefined? If so, then
176             # allow code below to delete entire element.
177 0 0       0 $index=undef if !grep (defined $_, @{$self->{ELEMENTS}->{$element}});
  0         0  
178             }
179              
180 2 50       3 if (!defined $index) {
181 2         3 undef @{$self->{ELEMENTS}->{$element}};
  2         6  
182 2         12 delete $self->{ELEMENTS}->{$element};
183 2         3 $self->{ELEMENTS_COUNT}--;
184 2 50       5 if ($self->{ORDERED}) {
185 2         4 @{$self->{ORDER}} = grep ($_ ne $element, @{$self->{ORDER}});
  2         13  
  2         6  
186             }
187             }
188 2         9 return(@old);
189             }
190              
191              
192             sub exists ($$;$) {
193 2     2 1 38 my $self=shift;
194 2         6 my($element,$index)=$self->validate_elements(@_);
195              
196 2 50       33 return if !exists $self->{ELEMENTS}->{$element};
197 2 100       7 return 1 if !defined $index;
198             # Trying to find sub-element
199 1         5 return $self->{ELEMENTS}->{$element}->[$index];
200             }
201              
202              
203             sub size ($;$) {
204 5     5 1 37 my $self=shift;
205 5         13 my $element=shift;
206              
207 5 100       20 return $self->{ELEMENTS_COUNT} if !defined $element;
208              
209 4 50       22 return if !exists $self->{ELEMENTS}->{$element};
210              
211 4         11 my $value=$self->{ELEMENTS}->{$element};
212 4         20 return scalar(@$value);
213             }
214              
215              
216             sub elements ($) {
217 2     2 1 382 my $self=shift;
218 2 50       9 return @{$self->{ORDER}} if $self->{ORDERED};
  2         10  
219 0         0 return keys %{$self->{ELEMENTS}};
  0         0  
220             }
221              
222              
223             # Old name
224             sub fields ($) {
225 0     0 0 0 sub fields_warn { warn Carp::longmess @_; }
226 0     0 0 0 fields_warn "Depreciated method called\n";
227 0         0 return shift->elements;
228             }
229              
230              
231             sub order ($;@) {
232 8     8 1 101 my $self=shift;
233 8 50       37 return unless $self->{ORDERED};
234              
235 8 100       24 return @{$self->{ORDER}} if !@_;
  7         924  
236              
237 1 50       5 my(@old_order)=@{$self->{ORDER}} if defined wantarray;
  0         0  
238 1         3 $self->{ORDER}=[@_];
239              
240 1 50       6 return @old_order if defined wantarray;
241             }
242              
243              
244             # Set the given element, value and index?
245             sub validate ($$$;$) {
246 17     17 1 34 my $self=shift;
247             # Not used here
248             #my($self, $element, $value, $index)=@_;
249 17         51 return @_;
250             }
251              
252              
253             # Check the legality of the given element and index
254             sub validate_elements ($$;$) {
255 21     21 1 27 my $self=shift;
256             # Not used here
257             #my($self, $element, $value, $index)=@_;
258 21         58 return @_;
259             }
260              
261              
262             # Return a native-formatted version of this metadata
263             sub format ($) {
264 0     0 1 0 my $self=shift;
265 0         0 my $string=$self->{ELEMENTS_COUNT}." elements\n";
266 0 0       0 my(@order)=$self->{ORDERED} ? @{$self->{ORDER}} : keys %{$self->{ELEMENTS}};
  0         0  
  0         0  
267 0 0       0 $string.="Order: @order\n" if $self->{ORDERED};
268 0         0 for my $element (@order) {
269 0         0 for my $value ($self->get($element)) {
270 0         0 $string.="$element: $value\n";
271             }
272             }
273 0         0 $string;
274             }
275              
276              
277             # Probably possible to do this using symbol table references
278 1     1 1 9 sub as_string ($) { shift->format; }
279              
280              
281             # Pack the metadata as small as possible - binary OK and preferred
282             sub pack ($) {
283 1     1 1 2 my $self=shift;
284 1 50       5 my(@order)=$self->{ORDERED} ? @{$self->{ORDER}} : keys %{$self->{ELEMENTS}};
  1         126  
  0         0  
285 1         2 my $string='';
286 1         3 for my $element (@order) {
287 0         0 for my $value ($self->get($element)) {
288 0 0       0 $value='' if !defined $value;
289 0         0 $string.="$element\0$value\0";
290             }
291             }
292 1         4 $string;
293             }
294              
295              
296             # Read the packed format and restore the same metadata state
297             sub unpack ($$) {
298 1     1 1 2 my $self=shift;
299 1         2 my $value=shift;
300              
301 1 50       5 return if !defined $value;
302              
303 1         3 $self->clear;
304 1         2 my(@vals)=(split(/\0/,$value));
305 1         4 while(@vals) {
306 0         0 my($element,$value)=splice(@vals,0,2);
307 0         0 $self->add($element,$value);
308             }
309              
310 1         3 1;
311             }
312              
313              
314             sub read ($) {
315 0     0 1 0 confess "Not implemented in base class\n";
316             }
317              
318              
319             sub write ($$) {
320 0     0 1 0 my $self=shift;
321 0         0 my $fd=shift;
322 0         0 print $fd $self->format;
323             }
324              
325              
326             sub reset ($) {
327 0     0 1 0 my $self=shift;
328              
329 0         0 my $default_options=$self->{DEFAULT_OPTIONS};
330 0         0 while(my($attr,$value)=each %$default_options) {
331 0         0 $self->{$attr}=$value;
332             }
333              
334 0         0 $self->clear;
335             }
336              
337              
338             sub clear ($) {
339 4     4 1 8 my $self=shift;
340              
341 4         12 $self->{ELEMENTS}={};
342 4         12 $self->{ELEMENTS_COUNT}=0;
343              
344             # Empty order if needed
345 4 50       26 $self->{ORDER}=[] if $self->{ORDERED};
346             }
347              
348              
349             sub get_date_as_seconds ($$) {
350 0     0 1 0 my $self=shift;
351 0         0 iso8601_to_seconds($self->get(shift));
352             }
353              
354              
355             sub set_date_as_seconds ($$$) {
356 0     0 1 0 my $self=shift;
357 0         0 my($element,$value)=shift;
358 0         0 $self->set($element, seconds_to_iso8601($value));
359             }
360              
361              
362             sub get_date_as_iso8601 ($$) {
363 0     0 0 0 my $self=shift;
364 0         0 $self->get(shift);
365             }
366              
367              
368             sub set_date_as_iso8601 ($$$) {
369 0     0 0 0 my $self=shift;
370 0         0 $self->set(@_);
371             }
372              
373              
374             sub seconds_to_iso8601 ($) {
375 1     1 1 261 my($ss,$mm,$hh,$day,$month,$year)=gmtime(shift);
376 1         12 sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",
377             $year+1900, $month+1,$day,$hh,$mm,$ss);
378             }
379              
380              
381             sub iso8601_to_seconds ($) {
382 7     7 1 936 my $value=shift;
383 7         54 my($year,$month,$day,$hh,$mm,$ss,$tz)= ($value =~ m{
384             ^
385             (\d\d\d\d) (?: # year YYYY required
386             - (\d\d) (?: # month -MM optional
387             - (\d\d) (?: # day -DD optional
388             T (\d\d) : (\d\d) (?: # time 'T'HH:MM optional
389             (?: : (\d\d (?: \.\d+)?) )? # :SS :SS.frac opt. followed by
390             (Z | (?: [+-]\d+:\d+)) # 'Z' | +/-HH:MM timezone
391             )? # optional TZ/SS/SS+TZ
392             )? # optional THH:MM ..
393             )? # optional -DD...
394             )? # optional -MM...
395             $
396             }x);
397              
398 7 50       18 return if !defined $year;
399              
400             # Round to start of year, month, etc. since it is too difficult to round
401             # to the end (leap years).
402             # Really it should return two values for the start & end of period
403             # - maybe in V2.0
404 7   100     29 $month ||=1; $day ||=1; $hh ||=0; $mm ||=0; $ss ||=0; $tz ||='Z';
  7   100     17  
  7   100     17  
  7   100     15  
  7   100     17  
  7   100     14  
405              
406 7 100       17 $tz='' if $tz eq 'Z';
407              
408 7         2018 require 'Time/Local.pm';
409            
410 7         1923 $value=Time::Local::timegm(int($ss),$mm,$hh,$day,$month-1,$year-1900);
411              
412 7 100       180 if ($tz =~ /^(.)(\d+):(\d+)$/) {
413 3         10 my $s=(($2*60)+$3)*60;
414 3 50       11 $value= ($1 eq '+') ? $value+$s : $value-$s;
415             }
416 7 100       16 if ($ss=~ /(\.\d+)$/) {
417 1         4 $value.= $1; # Note string concatenation
418             }
419 7         18 $value;
420             }
421              
422              
423              
424             1;
425              
426             __END__