/[suikacvs]/messaging/manakai/lib/Message/Field/Structured.pm
Suika

Contents of /messaging/manakai/lib/Message/Field/Structured.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (hide annotations) (download)
Sat May 4 06:03:58 2002 UTC (22 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.8: +301 -44 lines
2002-05-04  wakaba <w@suika.fam.cx>

	* XMoe.pm: New module.
	* CSV.pm: Use XMoe.pm.

1 wakaba 1.1
2     =head1 NAME
3    
4 wakaba 1.5 Message::Field::Structured -- Perl module for
5     structured header field bodies of the Internet message
6 wakaba 1.1
7     =cut
8    
9     package Message::Field::Structured;
10     use strict;
11 wakaba 1.5 use vars qw($VERSION);
12 wakaba 1.9 $VERSION=do{my @r=(q$Revision: 1.8 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
13 wakaba 1.3 require Message::Util;
14 wakaba 1.5 use overload '""' => sub { $_[0]->stringify },
15     '.=' => sub { $_[0]->value_append ($_[1]) },
16     'eq' => sub { $_[0]->{field_body} eq $_[1] },
17     'ne' => sub { $_[0]->{field_body} ne $_[1] },
18     fallback => 1;
19 wakaba 1.1
20 wakaba 1.5 =head1 CONSTRUCTORS
21 wakaba 1.1
22 wakaba 1.5 The following methods construct new C<Message::Field::Structured> objects:
23 wakaba 1.1
24 wakaba 1.5 =over 4
25 wakaba 1.1
26 wakaba 1.5 =cut
27 wakaba 1.1
28 wakaba 1.5 ## Initialize of this class -- called by constructors
29     sub _init ($;%) {
30     my $self = shift;
31     my %options = @_;
32 wakaba 1.9 $self->{option} = Message::Util::make_clone ({
33     _ARRAY_NAME => '',
34     _HASH_NAME => '',
35     dont_croak => 0, ## Don't die unless very very fatal error
36     encoding_after_encode => '*default',
37     encoding_before_decode => '*default',
38     field_param_name => '',
39     field_name => 'x-structured',
40     format => 'mail-rfc2822',
41     hook_encode_string => #sub {shift; (value => shift, @_)},
42     \&Message::Util::encode_header_string,
43     hook_decode_string => #sub {shift; (value => shift, @_)},
44     \&Message::Util::decode_header_string,
45     #name ## Reserved for method level option
46     #parse ## Reserved for method level option
47     parse_all => 0,
48     prepend => 0, ## (Reserved for method level option)
49     value_type => {'*default' => [':none:']},
50     });
51 wakaba 1.5 $self->{field_body} = '';
52    
53     for my $name (keys %options) {
54     if (substr ($name, 0, 1) eq '-') {
55     $self->{option}->{substr ($name, 1)} = $options{$name};
56     } elsif (lc $name eq 'body') {
57     $self->{field_body} = $options{$name};
58     }
59     }
60     }
61 wakaba 1.3
62 wakaba 1.5 =item Message::Field::Structured->new ([%options])
63 wakaba 1.1
64 wakaba 1.5 Constructs a new C<Message::Field::Structured> object. You might pass some
65     options as parameters to the constructor.
66 wakaba 1.1
67     =cut
68    
69 wakaba 1.2 sub new ($;%) {
70 wakaba 1.3 my $class = shift;
71 wakaba 1.5 my $self = bless {}, $class;
72     $self->_init (@_);
73 wakaba 1.3 $self;
74 wakaba 1.1 }
75    
76 wakaba 1.5 =item Message::Field::Structured->parse ($field-body, [%options])
77 wakaba 1.1
78 wakaba 1.5 Constructs a new C<Message::Field::Structured> object with
79     given field body. You might pass some options as parameters to the constructor.
80 wakaba 1.1
81     =cut
82    
83 wakaba 1.2 sub parse ($$;%) {
84 wakaba 1.3 my $class = shift;
85 wakaba 1.5 my $self = bless {}, $class;
86     $self->_init (@_);
87     #my $field_body = $self->Message::Util::decode_qcontent (shift);
88     $self->{field_body} = shift; #$field_body;
89 wakaba 1.1 $self;
90     }
91    
92 wakaba 1.5 =back
93    
94 wakaba 1.9 =cut
95    
96     ## Template procedures for array/hash fields
97     ## (As bare Message::Field::Structured module,
98     ## these shall not be used.)
99    
100     sub add ($$$%) {
101     my $self = shift;
102    
103     my $array = $self->{option}->{_ARRAY_NAME};
104     if ($array) {
105    
106     ## --- field is non-named value list (i.e. not hash)
107    
108     ## Options
109     my %option = %{$self->{option}};
110     if (ref $_[0] eq 'HASH') {
111     my $option = shift (@_);
112     for (keys %$option) {my $n = $_; $n =~ s/^-//; $option{$n} = $$option{$_}}
113     }
114    
115     ## Additional items
116     my $avalue;
117     for (@_) {
118     my ($ok, undef, $avalue) = $self->_add_array_check ($_, \%option);
119     if ($ok) {
120     if ($option{prepend}) {
121     unshift @{$self->{$array}}, $avalue;
122     } else {
123     push @{$self->{$array}}, $avalue;
124     }
125     }
126     }
127     $avalue; ## Return last added value if necessary.
128    
129     } else {
130     $array = $self->{option}->{_HASH_NAME};
131    
132     ## --- field is not list
133    
134     unless ($array) {
135     my %option = @_;
136     return if $option{-dont_croak};
137     Carp::croak q{add: Method not available for this module};
138     }
139    
140     ## --- field is named value list (i.e. hash)
141    
142     ## Options
143     my %p = @_; my %option = %{$self->{option}};
144     for (grep {/^-/} keys %p) {$option{substr ($_, 1)} = $p{$_}}
145     $option{parse} = 1 if defined wantarray && !defined $option{parse};
146    
147     ## Additional items
148     my $avalue;
149     while (my ($name => $value) = splice (@_, 0, 2)) {
150     next if $name =~ /^-/; $name =~ s/^\\//;
151    
152     my $ok;
153     ($ok, undef, $avalue) = $self->_add_hash_check ($name => $value, \%option);
154     if ($ok) {
155     if ($option{prepend}) {
156     unshift @{$self->{$array}}, $avalue;
157     } else {
158     push @{$self->{$array}}, $avalue;
159     }
160     }
161     }
162     $avalue; ## Return last added value if necessary.
163     }
164     }
165    
166     sub _add_array_check ($$\%) {
167     shift; 1, $_[0] => $_[0];
168     }
169     sub _add_hash_check ($$$\%) {
170     shift; 1, $_[0] => [@_[0,1]];
171     }
172    
173     sub replace ($$$%) {
174     my $self = shift;
175    
176     $self->_replace_cleaning;
177     my $array = $self->{option}->{_ARRAY_NAME};
178     if ($array) {
179    
180     ## --- field is non-named value list (i.e. not hash)
181    
182     ## Options
183     my %option = %{$self->{option}};
184     if (ref $_[0] eq 'HASH') {
185     my $option = shift (@_);
186     for (keys %$option) {my $n = $_; $n =~ s/^-//; $option{$n} = $$option{$_}}
187     }
188    
189     ## Additional items
190     my ($avalue, %replace);
191     for (@_) {
192     my ($ok, $aname);
193     ($ok, $aname => $avalue)
194     = $self->_replace_array_check ($_, \%option);
195     if ($ok) {
196     $replace{$aname} = $avalue;
197     }
198     }
199     for (@{$self->{$array}}) {
200     my ($v) = $self->_replace_array_shift (\%replace => $_, \%option);
201     if (defined $v) {
202     $_ = $v;
203     }
204     }
205     for (keys %replace) {
206     if ($option{prepend}) {
207     unshift @{$self->{$array}}, $replace{$_};
208     } else {
209     push @{$self->{$array}}, $replace{$_};
210     }
211     }
212     $avalue; ## Return last added value if necessary.
213    
214     } else {
215     $array = $self->{option}->{_HASH_NAME};
216    
217     ## --- field is not list
218    
219     unless ($array) {
220     my %option = @_;
221     return if $option{-dont_croak};
222     Carp::croak q{replace: Method not available for this module};
223     }
224    
225     ## --- field is named value list (i.e. hash)
226    
227     ## Options
228     my %p = @_; my %option = %{$self->{option}};
229     for (grep {/^-/} keys %p) {$option{substr ($_, 1)} = $p{$_}}
230     $option{parse} = 1 if defined wantarray && !defined $option{parse};
231    
232     ## Additional items
233     my ($avalue, %replace);
234     while (my ($name => $value) = splice (@_, 0, 2)) {
235     next if $name =~ /^-/; $name =~ s/^\\//;
236    
237     my ($ok, $aname);
238     ($ok, $aname => $avalue)
239     = $self->_replace_hash_check ($name => $value, \%option);
240     if ($ok) {
241     $replace{$aname} = $avalue;
242     }
243     }
244     for (@{$self->{$array}}) {
245     my ($v) = $self->_replace_hash_shift (\%replace => $_, \%option);
246     if (defined $v) {
247     $_ = $v;
248     }
249     }
250     for (keys %replace) {
251     if ($option{prepend}) {
252     unshift @{$self->{$array}}, $replace{$_};
253     } else {
254     push @{$self->{$array}}, $replace{$_};
255     }
256     }
257     $avalue; ## Return last added value if necessary.
258     }
259     }
260    
261     sub _replace_cleaning ($) {
262     # $_[0]->_delete_empty;
263     }
264     sub _replace_array_check ($$\%) {
265     shift; 1, $_[0] => $_[0];
266     }
267     sub _replace_array_shift ($\%$\%) {
268     shift; my $r = shift; my $n = $_[0]->[0];
269     if ($$r{$n}) {
270     my $d = $$r{$n};
271     $$r{$n} = undef;
272     return $d;
273     }
274     undef;
275     }
276     sub _replace_hash_check ($$$\%) {
277     shift; 1, $_[0] => [@_[0,1]];
278     }
279     sub _replace_hash_shift ($\%$\%) {
280     shift; my $r = shift; my $n = $_[0]->[0];
281     if ($$r{$n}) {
282     my $d = $$r{$n};
283     $$r{$n} = undef;
284     return $d;
285     }
286     undef;
287     }
288    
289     sub count ($;%) {
290     my $self = shift; my %option = @_;
291     my $array = $self->{option}->{_ARRAY_NAME}
292     || $self->{option}->{_HASH_NAME};
293     unless ($array) {
294     return if $option{-dont_croak};
295     Carp::croak q{count: Method not available for this module};
296     }
297     $self->_count_cleaning;
298     return $self->_count_by_name ($array => \%option) if defined $option{-name};
299     $#{$self->{$array}} + 1;
300     }
301     sub _count_cleaning ($) {
302     # $_[0]->_delete_empty;
303     }
304     sub _count_by_name ($$\%) {
305     # my $self = shift;
306     # my ($array, $option) = @_;
307     # my $name = $self->_n11n_*name* ($$option{-name});
308     # my @a = grep {$_->[0] eq $name} @{$self->{$array}};
309     # $#a + 1;
310     }
311    
312     ## Delete empty items
313     sub _delete_empty ($) {
314     # my $self = shift;
315     # $self->{*$array*} = [grep {ref $_ && length $_->[0]} @{$self->{*$array*}}];
316     # $self;
317     }
318    
319     ## $self->_parse_value ($type, $value);
320     sub _parse_value ($$$) {
321     my $self = shift;
322     my $name = shift || '*default';
323     my $value = shift;
324     return $value if ref $value;
325     my $vtype = $self->{option}->{value_type}->{$name}->[0]
326     || $self->{option}->{value_type}->{'*default'}->[0];
327     my %vopt; %vopt = %{$self->{option}->{value_type}->{$name}->[1]}
328     if ref $self->{option}->{value_type}->{$name}->[1];
329     if ($vtype eq ':none:') {
330     return $value;
331     } elsif (defined $value) {
332     eval "require $vtype" or Carp::croak qq{<parse>: $vtype: Can't load package: $@};
333     return $vtype->parse ($value,
334     -format => $self->{option}->{format},
335     -field_name => $self->{option}->{field_name},
336     -field_param_name => $name,
337     -parse_all => $self->{option}->{parse_all},
338     %vopt);
339     } else {
340     eval "require $vtype" or Carp::croak qq{<parse>: $vtype: Can't load package: $@};
341     return $vtype->new (
342     -format => $self->{option}->{format},
343     -field_name => $self->{option}->{field_name},
344     -field_param_name => $name,
345     -parse_all => $self->{option}->{parse_all},
346     %vopt);
347     }
348     }
349    
350 wakaba 1.5 =head1 METHODS
351    
352     =over 4
353    
354     =item $self->stringify ([%options])
355 wakaba 1.1
356 wakaba 1.5 Returns field body as a string. Returned string is encoded,
357     quoted if necessary (by C<hook_encode_string>).
358 wakaba 1.1
359     =cut
360    
361 wakaba 1.7 sub stringify ($;%) {
362 wakaba 1.1 my $self = shift;
363 wakaba 1.5 #$self->Message::Util::encode_qcontent ($self->{field_body});
364     $self->{field_body};
365 wakaba 1.1 }
366 wakaba 1.5 *as_string = \&stringify;
367 wakaba 1.1
368 wakaba 1.5 =item $self->as_plain_string
369 wakaba 1.1
370 wakaba 1.5 Returns field body as a string. Returned string is not encoded
371     or quoted, i.e. internal/bare coded string. This string
372     may be unable to use as field body content. (Its I<structures>
373     such as C<comment> and C<quoted-string> are lost.)
374 wakaba 1.1
375     =cut
376    
377     sub as_plain_string ($) {
378     my $self = shift;
379 wakaba 1.5 my $s = $self->Message::Util::decode_qcontent ($self->{field_body});
380     Message::Util::unquote_quoted_string (Message::Util::unquote_ccontent ($s));
381 wakaba 1.1 }
382 wakaba 1.4
383 wakaba 1.5 =item $self->option ( $option-name / $option-name, $option-value, ...)
384 wakaba 1.4
385 wakaba 1.5 If @_ == 1, returns option value. Else...
386 wakaba 1.4
387 wakaba 1.5 Set option value. You can pass multiple option name-value pair
388     as parameter. Example:
389 wakaba 1.1
390 wakaba 1.5 $msg->option (-format => 'mail-rfc822',
391     -capitalize => 0);
392     print $msg->option ('-format'); ## mail-rfc822
393 wakaba 1.3
394 wakaba 1.5 Note that introduction character, i.e. C<-> (HYPHEN-MINUS)
395     is optional. You can also write as this:
396 wakaba 1.3
397 wakaba 1.5 $msg->option (format => 'mail-rfc822',
398     capitalize => 0);
399     print $msg->option ('format'); ## mail-rfc822
400 wakaba 1.1
401     =cut
402    
403 wakaba 1.5 sub option ($@) {
404 wakaba 1.1 my $self = shift;
405 wakaba 1.5 if (@_ == 1) {
406     return $self->{option}->{ $_[0] };
407     }
408     while (my ($name, $value) = splice (@_, 0, 2)) {
409     $name =~ s/^-//;
410     $self->{option}->{$name} = $value;
411     }
412 wakaba 1.1 }
413    
414 wakaba 1.9 ## TODO: multiple value-type support
415     sub value_type ($;$$%) {
416     my $self = shift;
417     my $name = shift || '*default';
418     my $new_value_type = shift;
419     if ($new_value_type) {
420     $self->{option}->{value_type}->{$name} = []
421     unless ref $self->{option}->{value_type}->{$name};
422     $self->{option}->{value_type}->{$name}->[0] = $new_value_type;
423     }
424     if (ref $self->{option}->{value_type}->{$name}) {
425     $self->{option}->{value_type}->{$name}->[0]
426     || $self->{option}->{value_type}->{'*default'}->[0];
427     } else {
428     $self->{option}->{value_type}->{'*default'}->[0];
429     }
430     }
431    
432 wakaba 1.5 =item $self->clone ()
433 wakaba 1.1
434 wakaba 1.5 Returns a copy of Message::Field::Structured object.
435 wakaba 1.1
436     =cut
437    
438 wakaba 1.5 sub clone ($) {
439 wakaba 1.1 my $self = shift;
440 wakaba 1.5 my $clone = ref($self)->new;
441 wakaba 1.9 $clone->_delete_empty;
442     $clone->{option} = Message::Util::make_clone ($self->{option});
443     $clone->{field_body} = Message::Util::make_clone ($self->{field_body});
444 wakaba 1.5 ## Common hash value (not used in this module)
445 wakaba 1.9 $clone->{value} = Message::Util::make_clone ($self->{value});
446     $clone->{comment} = Message::Util::make_clone ($self->{comment});
447 wakaba 1.5 $clone;
448 wakaba 1.1 }
449    
450 wakaba 1.8 sub _n11n_field_name ($$) {
451     my $self = shift;
452     my $s = shift;
453 wakaba 1.9 $s = lc $s ;#unless $self->{option}->{field_name_case_sensible};
454 wakaba 1.8 $s;
455     }
456    
457 wakaba 1.5
458 wakaba 1.1 =head1 EXAMPLE
459    
460     use Message::Field::Structured;
461    
462     my $field_body = '"This is an example of <\"> (quotation mark)."
463     (Comment within \q\u\o\t\e\d\-\p\a\i\r\(\s\))';
464     my $field = Message::Field::Structured->parse ($field_body);
465    
466     print $field->as_plain_string;
467    
468 wakaba 1.5 =head1 SEE ALSO
469    
470     =over 4
471    
472     =item L<Message::Entity>, L<Message::Header>
473    
474     =item L<Message::Field::Unstructured>
475    
476     =item RFC 2822 E<lt>urn:ietf:rfc:2822E<gt>, usefor-article, HTTP/1.0, HTTP/1.1
477    
478     =back
479    
480 wakaba 1.1 =head1 LICENSE
481    
482     Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
483    
484     This program is free software; you can redistribute it and/or modify
485     it under the terms of the GNU General Public License as published by
486     the Free Software Foundation; either version 2 of the License, or
487     (at your option) any later version.
488    
489     This program is distributed in the hope that it will be useful,
490     but WITHOUT ANY WARRANTY; without even the implied warranty of
491     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
492     GNU General Public License for more details.
493    
494     You should have received a copy of the GNU General Public License
495     along with this program; see the file COPYING. If not, write to
496     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
497     Boston, MA 02111-1307, USA.
498    
499     =head1 CHANGE
500    
501     See F<ChangeLog>.
502 wakaba 1.9 $Date: 2002/04/21 04:27:42 $
503 wakaba 1.1
504     =cut
505    
506     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24