File Coverage

blib/lib/Data/v.pm
Criterion Covered Total %
statement 373 398 93.7
branch 101 134 75.3
condition 29 35 82.8
subroutine 73 73 100.0
pod 0 4 0.0
total 576 644 89.4


line stmt bran cond sub pod time code
1             package Data::v;
2              
3 2     2   137380 use warnings;
  2         7  
  2         97  
4 2     2   13 use strict;
  2         5  
  2         76  
5              
6 2     2   12 use Carp;
  2         3  
  2         159  
7 2     2   20 use Scalar::Util 'blessed';
  2         9  
  2         177  
8 2     2   1570 use List::MoreUtils 'any';
  2         24155  
  2         24  
9              
10             our $VERSION = '0.03';
11              
12 2     2   1531 use base 'Data::Header::Fields';
  2         5  
  2         1174  
13              
14             our %v_types = (
15             'VCARD' => 'Data::v::Card',
16             );
17              
18             sub new {
19 13     13 0 4428 my $class = shift;
20 13         80 return $class->SUPER::new(
21             tight_folding => 1,
22             key_cmp => \&default_key_cmp,
23             parent => $class->_default_parent,
24             @_,
25             );
26             }
27              
28             sub default_key_cmp {
29 162     162 0 182 my $a = shift;
30 162         164 my $b = shift;
31            
32 162         201 $a = lc $a;
33 162         199 $b = lc $b;
34            
35 162 100       1487 return 0
36             if $b =~ qr{^$a (?: ; | $)}xms;
37            
38 130         479 return $a cmp $b;
39             }
40              
41             sub decode {
42 6     6 0 26 my $self = shift;
43 6         12 my $any = shift;
44            
45 6         15 my $return_self = ref $self;
46 6 50       25 $self = $self->new()
47             if not ref $self;
48              
49 6         60 my $dhf = $self->SUPER::decode($any);
50 6         27 my $lines = $dhf->_lines;
51            
52 6         14 my @v_entries;
53             my $v_type;
54 6         11 while (my $line = shift @{$lines}) {
  90         314  
55 84 100       188 if ($line->key eq 'BEGIN') {
    100          
56 6         29 $v_type = $line->value->as_string;
57 6 50       29 croak 'unknown v-type "'.$v_type.'"'
58             if not $v_types{$v_type};
59            
60 6         55 my $v_data = $v_types{$v_type}->new();
61 6         89 my $v_entry = ($v_types{$v_type}.'::Entry')->new(
62             'key' => $v_type,
63             'value' => $v_data,
64             'parent' => $self,
65             );
66 6         31 $v_data->parent($v_entry);
67 6         12 push @v_entries, $v_entry;
68 6         55 next;
69             }
70             elsif ($line->key eq 'END') {
71 6 50       25 croak 'BEGIN and END mismatch "'.$v_type.'" ne "'.$line->value->as_string.'"'
72             if $v_type ne $line->value->as_string;
73            
74 6         11 $v_type = undef;
75 6         32 next;
76             }
77            
78 72         95 push @{$v_entries[-1]->value->_lines}, $line;
  72         186  
79             }
80            
81 6         18 foreach my $v_entry (@v_entries) {
82 6         21 $v_entry->value->rebless_lines;
83             }
84            
85 6 50       24 if (not $return_self) {
86 0         0 return \@v_entries;
87             }
88              
89 6         34 $dhf->_lines(\@v_entries);
90 6         31 return $dhf;
91             }
92              
93             sub _read_lines {
94 6     6   9 my $self = shift;
95 6         12 my $any = shift;
96            
97 6         48 my $fh = IO::Any->read($any);
98            
99             # put folded lines to an array http://tools.ietf.org/html/rfc2822#section-2.2.3
100 6         919 my @lines;
101 6         13 my $quoted_printable = 0;
102 6         49 while (my $line = <$fh>) {
103             # folded line
104 208 100 100     5925 if (($line =~ m/^\s/xms) or ($quoted_printable and ($lines[-1] =~ m/ = \r? \Z /xms))) {
      66        
105             # ignore if the first line starts with white space
106 124 50       241 next if not @lines;
107            
108 124         270 $lines[-1] .= $line;
109 124         422 next;
110             }
111            
112             # detect quoted-printable encoding which continues on a next lines when the line ends with "="
113 84         288 my ($key, $value) = split(/:/, $line, 2);
114 84         233 my @key_parts = split(/;/, $key);
115 84         112 shift @key_parts;
116 84     78   433 $quoted_printable = (any { $_ eq 'encoding=quoted-printable' } map { lc $_; } @key_parts);
  78         113  
  78         309  
117            
118 84         541 push @lines, $line;
119             }
120            
121 6         172 close $fh;
122              
123 6         143 return @lines;
124             }
125              
126             sub _default_parent {
127 6     6   58 return 'Data::Header::Fields';
128             }
129              
130             sub parent {
131 21     21 0 33 my $self = shift;
132 21 100       161 $self->{'parent'} = shift
133             if @_;
134            
135 21 50       117 return (ref $self ? $self->{'parent'} : $self->_default_parent);
136             }
137              
138             1;
139              
140             package Data::v::Card;
141              
142 2     2   13 use base 'Data::v';
  2         4  
  2         220  
143              
144 2     2   13 use List::MoreUtils 'any';
  2         3  
  2         14  
145 2     2   874 use Carp 'croak';
  2         2  
  2         525  
146              
147 19   100 19   60 sub version { return $_[0]->get_value('version') || '2.1'; }
148              
149             sub rebless_lines {
150 6     6   11 my $self = shift;
151            
152 6         12 foreach my $line (@{$self->_lines}) {
  6         21  
153 72         207 $line = Data::v::Card::Line->new(
154             line => $line,
155             parent => $self,
156             );
157             }
158             }
159              
160             sub _default_parent {
161 7     7   53 return 'Data::v::Card::Entry';
162             }
163              
164             sub line_ending {
165 15     15   24 my $self = shift;
166 15         43 return $self->parent->parent->line_ending(@_);
167             }
168              
169             sub get_fields {
170 32     32   51 my $self = shift;
171 32 50       84 my $field_name = shift or croak 'field_name argument is mandatory';
172 32         50 my $param_name = shift;
173 32         42 my $param_value = shift;
174            
175 32         126 my @fields = $self->SUPER::get_fields($field_name);
176 32 100       85 if (defined $param_name) {
177             @fields =
178 1     3   4 grep { any { lc $_->value eq $param_value } $_->get_key_params($param_name) }
  2         15  
  3         9  
179             @fields
180             ;
181             }
182            
183 32         109 return @fields;
184             }
185              
186             1;
187              
188              
189             package Data::v::Card::Line;
190              
191 2     2   13 use base 'Data::Header::Fields::Line';
  2         2  
  2         644  
192              
193 2     2   13 use Carp 'croak';
  2         3  
  2         100  
194 2     2   1039 use MIME::QuotedPrint 'encode_qp', 'decode_qp';
  2         2504  
  2         137  
195 2     2   12 use MIME::Base64 'encode_base64', 'decode_base64';
  2         2  
  2         80  
196 2     2   1104 use Encode ();
  2         16167  
  2         51  
197 2     2   14 use List::MoreUtils 'none';
  2         3  
  2         22  
198              
199             use overload
200 2         20 '""' => \&as_string,
201             'cmp' => \&Data::Header::Fields::Line::cmp,
202 2     2   744 ;
  2         2  
203              
204             sub new {
205 79     79   111 my $class = shift;
206 79         294 my $self = $class->SUPER::new(
207             @_,
208             );
209 79         201 $self->_decode_key_params;
210 79         201 return $self;
211             }
212              
213 18     18   61 sub version { return $_[0]->parent->version; }
214              
215             sub params {
216 254     254   247 my $self = shift;
217            
218 254 100       481 if (@_) {
219 73         125 $self->{params} = shift;
220             }
221 254 100       675 $self->{params} = []
222             if (not $self->{params});
223            
224 254         380 return $self->{params};
225             }
226              
227             sub _decode_key_params {
228 93     93   166 my $self = shift;
229            
230 93         211 my $key = $self->key;
231            
232 93 100       504 if ($key =~ m/^([^;]+);(.+)$/xms) {
233 60         160 my $orig_key_name = $1;
234 60         247 my @raw_key_params = split /;/, $2;
235 60         78 my @key_params;
236            
237 60         94 my $key_name = lc $orig_key_name;
238              
239 60         107 foreach my $key_param (@raw_key_params) {
240 106 50       513 croak 'unknown key param "'.$key_param.'"'
241             if $key_param !~ m/^ (?: ([^=]+) = )? (.+) $/xms;
242 106   100     459 my $param_name = $1 || 'TYPE';
243 106         146 my $param_str = $2;
244            
245 117         322 push
246             @key_params,
247 106         284 map { Data::v::Param->new('name' => $param_name, 'value' => $_, 'parent' => $self) }
248             (split(/,/, $param_str))
249             ;
250             }
251            
252 60         229 $self->key($orig_key_name);
253 60         149 $self->params(\@key_params);
254            
255 60   100     123 my $enc_type = lc ($self->get_key_param_value('encoding') || '');
256 60 100       113 if ($enc_type) {
257 10 100       32 if ($enc_type eq 'quoted-printable') {
    50          
258 7         65 $self->{value} = Data::Header::Fields::Value->new(
259             decode_qp($self->{value})
260             );
261             }
262             elsif ($enc_type eq 'base64') {
263 3         19 $self->{value} = Data::Header::Fields::Value->new(
264             decode_base64($self->{value})
265             );
266             }
267             else {
268 0         0 croak 'unknown encoding "'.$enc_type.'"';
269             }
270             }
271              
272 60   100     139 my $charset = lc ($self->get_key_param_value('charset') || '');
273             $charset ||= 'utf8'
274 60 100 100 213   411 if (none { $_ eq $key_name } qw(photo logo sound key));
  213         436  
275              
276 60 100       222 if ($charset) {
277             $self->{'value'} = Data::Header::Fields::Value->new(
278 53         84 eval { Encode::decode($charset, $self->{'value'}) }
  53         256  
279             );
280             }
281             }
282            
283 93 100 66     285 if ((lc $self->key eq 'n') and (not $self->key->isa('Data::v::Card::Value::Name'))) {
    100 66        
284 9         39 $self->{'value'} = Data::v::Card::Value::Name->new( # not calling value() because the set doesn't affect the content of the value
285             'value' => $self->value,
286             'parent' => $self,
287             );
288             }
289             elsif ((lc $self->key eq 'adr') and (not $self->key->isa('Data::v::Card::Value::Adr'))) {
290 9         35 $self->{'value'} = Data::v::Card::Value::Adr->new( # not calling value() because the set doesn't affect the content of the value
291             'value' => $self->value,
292             'parent' => $self,
293             );
294             }
295            
296 93         169 return;
297             }
298              
299             sub get_key_params {
300 160     160   180 my $self = shift;
301 160 50       330 my $param_name = shift or croak 'param param_name is mandatory';
302 160         272 my $params = $self->params;
303            
304 160         312 $param_name = lc $param_name;
305 160         148 return grep { lc $_->{'name'} eq $param_name } @{$params};
  315         986  
  160         253  
306             }
307              
308             sub get_key_param {
309 146     146   148 my $self = shift;
310 146 50       297 my $param_name = shift or croak 'param param_name is mandatory';
311            
312 146         265 my @params = $self->get_key_params($param_name);
313 146 50       318 croak 'more then one key param with name "'.$param_name.'"'
314             if @params > 1;
315            
316 146         228 return $params[0];
317             }
318              
319             sub get_key_param_value {
320 146     146   180 my $self = shift;
321 146 50       303 my $param_name = shift or croak 'param param_name is mandatory';
322            
323 146         292 my $param = $self->get_key_param($param_name);
324 146 100       746 return undef if not $param;
325 28         133 return $param->{'value'};
326             }
327              
328             sub update_key_params {
329 4     4   5 my $self = shift;
330 4 50       8 my $param_name = shift or croak 'param param_name is mandatory';
331 4         4 my $param_value = shift;
332            
333             # updating via array set
334 4 100       9 if (ref $param_value) {
335 2         2 my @new_params = @{$param_value};
  2         5  
336            
337             # update existing
338 2         3 foreach my $param (@{$self->params}) {
  2         3  
339 4 100       6 $param->value(shift @new_params) # will returns undefs if depleeted
340             if ($param->name eq $param_name);
341             }
342            
343             # add any additional new
344 2         3 foreach my $add_value (@new_params) {
345 2         2 push @{$self->{params}}, Data::v::Param->new(
  2         6  
346             'parent' => $self,
347             'name' => $param_name,
348             'value' => $add_value,
349             );
350             }
351            
352             # remove any additional old
353 6         12 $self->{params} = [
354 2         4 grep { defined $_->{'value'} }
355 2         3 @{$self->{params}}
356             ];
357 2         5 return $self;
358             }
359              
360 3 100       7 my @params = (
361             map {
362 2         5 ($_->{'name'} eq $param_name ? $_->{value} = $param_value : ());
363 3         6 $_;
364 2         2 } @{$self->params}
365             );
366            
367 2         4 return $self;
368             }
369              
370             sub set_key_param {
371 5     5   10 my $self = shift;
372 5 50       13 my $param_name = shift or croak 'param param_name is mandatory';
373 5         5 my $param_value = shift;
374              
375 5         10 my @params = $self->get_key_params($param_name);
376 5 100 100     22 if ((@params > 0) or (ref $param_value)) {
    50          
377 4         8 $self->update_key_params($param_name, $param_value);
378             }
379             elsif (@params == 0) {
380 1         1 push @{$self->params}, Data::v::Param->new('name' => $param_name, 'value' => $param_value, 'parent' => $self);
  1         3  
381             }
382             else {
383 0         0 croak 'more then one param field with name "'.$param_name.'"';
384             }
385            
386 5         9 return $self;
387             }
388              
389             sub rm_key_param {
390 1     1   3 my $self = shift;
391 1 50       7 my $param_name = shift or croak 'param param_name is mandatory';
392              
393 3         6 my @params = (
394             grep {
395 1         3 $_->name ne $param_name
396 1         2 } @{$self->params}
397             );
398 1         5 $self->params(\@params);
399            
400 1         3 return $self;
401             }
402              
403             sub _encode_key_params {
404 14     14   20 my $self = shift;
405              
406 14         35 my $params = $self->params;
407 14 100       119 return if scalar @{$params} == 0;
  14         46  
408 12         40 my $key = $self->key;
409              
410 12   100     31 my $charset = lc ($self->get_key_param_value('charset') || 'utf8');
411 12         19 $self->{value} = eval { Encode::encode($charset, $self->{value}) };
  12         53  
412            
413 12   100     424 my $enc_type = lc ($self->get_key_param_value('encoding') || '');
414 12 100       28 if ($enc_type) {
415 1 50       4 if ($enc_type eq 'quoted-printable') {
    0          
416 1         9 $self->{value} = encode_qp($self->{value}, "");
417             }
418             elsif ($enc_type eq 'base64') {
419 0         0 $self->{value} = encode_base64($self->{value}, "");
420             }
421             else {
422 0         0 croak 'unknown encoding "'.$enc_type.'"';
423             }
424             }
425            
426 12 100       31 if ($self->version eq '2.1') {
    50          
427 14         30 $key .= ';'.(
428             join(
429             ';',
430             (
431 15         29 map { $_->as_string }
432 8         18 grep { defined $_->value }
433 8         13 @{$params}
434             ),
435             )
436             );
437             }
438             elsif ($self->version ge '3.0') {
439 4         13 my @types = map { $_->as_string } $self->get_key_params('type');
  8         20  
440 10 100       17 $key .= ';'.(
    100          
441             join(
442             ';',
443             (
444             map {
445 10         17 (lc $_->name eq 'type')
446             ? ( @types ? ('TYPE='.join(',',splice(@types,0,scalar @types))) : () )
447             : $_->as_string
448             }
449 4         7 grep { defined $_->value }
450 4         11 @{$params}
451             ),
452             )
453             );
454             }
455             else {
456 0         0 croak 'unsupported VCARD version '.$self->version;
457             }
458            
459 12         38 $self->params(undef);
460 12         39 $self->key($key);
461            
462 12         58 return;
463             }
464              
465             sub as_string {
466 68     68   2250 my $self = shift;
467            
468 68 100       174 if (exists $self->{'original_line'}) {
469 54         72 my $original_line = $self->{'original_line'};
470            
471             # make sure the line has line_ending, even the original one could be created without using ->new()
472 54 50       198 $original_line .= $self->parent->line_ending
473             if $original_line !~ m/ \n \Z /xms;
474            
475 54         171 return $original_line;
476             }
477              
478 14         43 $self->_encode_key_params;
479              
480 14         36 my ($key, $value) = ($self->key, $self->value);
481             #$value = String::Escape::printable($value);
482             # FIXME ^^^ should be moved to _encode_key_params
483              
484 14         45 my $line = join(':', $key, $value);
485            
486 14 50       77 $line .= $self->parent->line_ending
487             if $line !~ m/\n$/xms;
488              
489 14         60 $self->_decode_key_params;
490            
491 14         83 return $line;
492             }
493              
494             1;
495              
496             package Data::v::Card::Entry;
497              
498 2     2   3646 use base 'Data::Header::Fields::Line';
  2         4  
  2         744  
499              
500             use overload
501 2         63 '""' => \&as_string,
502             'cmp' => \&Data::Header::Fields::Line::cmp,
503 2     2   12 ;
  2         4  
504              
505             sub as_string {
506 5     5   11 my $self = shift;
507              
508             return
509 5         18 'BEGIN:VCARD'.$self->parent->line_ending
510             .$self->value->as_string()
511             .'END:VCARD'.$self->parent->line_ending
512             ;
513             }
514              
515             1;
516              
517             package Data::v::Card::Value::Name;
518              
519 2     2   283 use base 'Data::Header::Fields::Value';
  2         3  
  2         596  
520              
521             our @NAME_PART_TYPES = qw{family_name given_name additional_names honorific_prefixes honorific_suffixes};
522              
523             use overload
524 2         10 '""' => \&Data::Header::Fields::Value::as_string,
525             'cmp' => \&Data::Header::Fields::Value::cmp,
526 2     2   10 ;
  2         2  
527              
528             sub new {
529 11     11   25 my $class = shift;
530 11         58 my $self = $class->SUPER::new(@_);
531            
532 11 100       67 defined $self->{'value'}
533             ? $self->_parse_value()
534             : $self->_update_value();
535            
536 11         107 return $self;
537             }
538              
539             sub _update_value {
540 3     3   6 my $self = shift;
541            
542 3         8 my @name_parts = map { $self->$_() } @NAME_PART_TYPES;
  15         36  
543             # remove the undef fields from the end of the N
544 3   66     133 while ((@name_parts) and (not defined $name_parts[-1])) {
545 2         13 pop @name_parts;
546             }
547 3 100       8 @name_parts = map { defined $_ ? $_ : '' } @name_parts;
  13         42  
548            
549 3         30 $self->value(join(';', @name_parts));
550            
551 3         6 return $self;
552             }
553              
554             sub _parse_value {
555 10     10   17 my $self = shift;
556            
557 10         26 my $name_str = $self->{'value'};
558 10         42 my @name_parts = split(/;/, $name_str);
559            
560 10         34 foreach my $name_part_type (@NAME_PART_TYPES) {
561 50         72 my $name_part_value = shift @name_parts;
562 50         133 $self->{$name_part_type} = $name_part_value;
563             }
564            
565 10         24 return $self;
566             }
567              
568             sub family_name {
569 4     4   11 my $self = shift;
570            
571 4 50       11 if (@_) {
572 0         0 $self->{'family_name'} = shift;
573 0         0 $self->_update_value();
574             }
575 4         14 return $self->{'family_name'};
576             }
577             sub given_name {
578 4     4   5 my $self = shift;
579 4 50       12 if (@_) {
580 0         0 $self->{'given_name'} = shift;
581 0         0 $self->_update_value();
582             }
583 4         12 return $self->{'given_name'};
584             }
585             sub additional_names {
586 5     5   6 my $self = shift;
587 5 100       13 if (@_) {
588 1         3 $self->{'additional_names'} = shift;
589 1         4 $self->_update_value();
590             }
591 5         16 return $self->{'additional_names'};
592             }
593             sub honorific_prefixes {
594 4     4   6 my $self = shift;
595 4 50       9 if (@_) {
596 0         0 $self->{'honorific_prefixes'} = shift;
597 0         0 $self->_update_value();
598             }
599 4         11 return $self->{'honorific_prefixes'};
600             }
601             sub honorific_suffixes {
602 5     5   6 my $self = shift;
603 5 100       14 if (@_) {
604 1         3 $self->{'honorific_suffixes'} = shift;
605 1         4 $self->_update_value();
606             }
607 5         18 return $self->{'honorific_suffixes'};
608             }
609              
610             1;
611              
612             package Data::v::Card::Value::Adr;
613              
614 2     2   970 use base 'Data::Header::Fields::Value';
  2         2  
  2         530  
615              
616             our @ADR_PART_TYPES = qw{po_box ext_address street city state postal_code country};
617              
618             use overload
619 2         15 '""' => \&Data::Header::Fields::Value::as_string,
620             'cmp' => \&Data::Header::Fields::Value::cmp,
621 2     2   12 ;
  2         3  
622              
623             sub new {
624 11     11   27 my $class = shift;
625 11         63 my $self = $class->SUPER::new(@_);
626            
627 11 100       58 defined $self->{'value'}
628             ? $self->_parse_value()
629             : $self->_update_value();
630            
631 11         36 return $self;
632             }
633              
634             sub _update_value {
635 2     2   6 my $self = shift;
636              
637 2         6 my @adr_parts = map { $self->$_() } @ADR_PART_TYPES;
  14         37  
638             # remove the undef fields from the end of the N
639 2   33     22 while ((@adr_parts) and (not defined $adr_parts[-1])) {
640 0         0 pop @adr_parts;
641             }
642 2 100       6 @adr_parts = map { defined $_ ? $_ : '' } @adr_parts;
  14         34  
643            
644 2         25 $self->value(join(';', @adr_parts));
645            
646 2         4 return $self;
647             }
648              
649             sub _parse_value {
650 10     10   19 my $self = shift;
651            
652 10         19 my $adr_str = $self->{'value'};
653 10         33 $adr_str =~ s/ \r? \n \Z//xms;
654 10         35 my @adr_parts = split(/;/, $adr_str);
655            
656 10         35 foreach my $adr_part_type (@ADR_PART_TYPES) {
657 70         94 my $adr_part_value = shift @adr_parts;
658 70         191 $self->{$adr_part_type} = $adr_part_value;
659             }
660            
661 10         23 return $self;
662             }
663              
664             sub po_box {
665 3     3   11 my $self = shift;
666              
667 3 50       11 if (@_) {
668 0         0 $self->{'po_box'} = shift @_;
669 0         0 $self->_update_value();
670             }
671              
672 3         14 return $self->{'po_box'};
673             }
674             sub ext_address {
675 3     3   5 my $self = shift;
676              
677 3 50       11 if (@_) {
678 0         0 $self->{'ext_address'} = shift @_;
679 0         0 $self->_update_value();
680             }
681              
682 3         10 return $self->{'ext_address'};
683             }
684             sub street {
685 3     3   5 my $self = shift;
686              
687 3 50       12 if (@_) {
688 0         0 $self->{'street'} = shift @_;
689 0         0 $self->_update_value();
690             }
691              
692 3         10 return $self->{'street'};
693             }
694             sub city {
695 3     3   7 my $self = shift;
696              
697 3 50       11 if (@_) {
698 0         0 $self->{'city'} = shift @_;
699 0         0 $self->_update_value();
700             }
701              
702 3         12 return $self->{'city'};
703             }
704             sub state {
705 3     3   7 my $self = shift;
706              
707 3 50       9 if (@_) {
708 0         0 $self->{'state'} = shift @_;
709 0         0 $self->_update_value();
710             }
711              
712 3         14 return $self->{'state'};
713             }
714             sub postal_code {
715 3     3   4 my $self = shift;
716              
717 3 50       11 if (@_) {
718 0         0 $self->{'postal_code'} = shift @_;
719 0         0 $self->_update_value();
720             }
721              
722 3         8 return $self->{'postal_code'};
723             }
724             sub country {
725 5     5   12 my $self = shift;
726              
727 5 100       17 if (@_) {
728 1         4 $self->{'country'} = shift @_;
729 1         4 $self->_update_value();
730             }
731              
732 5         22 return $self->{'country'};
733             }
734              
735             1;
736              
737             package Data::v::Param;
738              
739             use overload
740 2         17 '""' => \&as_string,
741             'cmp' => \&Data::Header::Fields::Value::cmp,
742 2     2   1245 ;
  2         3  
743              
744             sub new {
745 120     120   172 my $class = shift;
746 120         939 return bless {
747             @_
748             }, $class;
749             }
750              
751             sub name {
752 166     166   177 my $self = shift;
753              
754 166 50       289 $self->{'name'} = shift @_
755             if (@_);
756              
757 166         569 return $self->{'name'};
758             }
759              
760             sub value {
761 113     113   123 my $self = shift;
762              
763 113 100       206 $self->{'value'} = shift @_
764             if (@_);
765              
766 113         536 return $self->{'value'};
767             }
768              
769             sub as_string {
770 80     80   101 my $self = shift;
771            
772             return
773 80 100       132 (lc $self->name eq 'type')
774             ? $self->value
775             : $self->name.'='.$self->value
776             ;
777             }
778              
779             1;
780              
781             package Data::v::Calendar;
782              
783 2     2   482 use base 'Data::v';
  2         5  
  2         200  
784              
785             1;
786              
787              
788             __END__