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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (hide annotations) (download)
Thu Aug 1 09:19:46 2002 UTC (22 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.14: +41 -71 lines
2002-08-01  Wakaba <w@suika.fam.cx>

	* Unstructured.pm: Rewritten.
	* Subject.pm: Likewise.  Support Japanese government's
	spam mail prefix if Perl has defined $^V (=~ has UTF-8 support).
	* CSV.pm: Reformatted.

1 wakaba 1.1
2     =head1 NAME
3    
4 wakaba 1.7 Message::Field::CSV --- Perl module for Internet message
5     field body consist of comma separated values
6 wakaba 1.1
7     =cut
8    
9     package Message::Field::CSV;
10 wakaba 1.15 require 5.6.0; ## eval 're'
11 wakaba 1.1 use strict;
12 wakaba 1.15 use vars qw(%DEFAULT @ISA %REG $VERSION);
13     $VERSION=do{my @r=(q$Revision: 1.14 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
14 wakaba 1.7 require Message::Field::Structured;
15     push @ISA, qw(Message::Field::Structured);
16    
17     use overload '""' => sub { $_[0]->stringify },
18     '0+' => sub { $_[0]->count },
19     '.=' => sub { $_[0]->add ($_[1]); $_[0] },
20     fallback => 1;
21    
22 wakaba 1.15 %REG = %Message::Util::REG;
23 wakaba 1.7 ## Inherited: comment, quoted_string, domain_literal, angle_quoted
24     ## WSP, FWS, atext
25 wakaba 1.15
26     ## From usefor-article
27 wakaba 1.7 $REG{NON_component} = qr/[^\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5F\x61-\x7A\x80-\xFF\x2F\x3D\x3F]/;
28     $REG{NON_distribution} = qr/[^\x21\x2B\x2D\x30-\x39\x41-\x5A\x5F\x61-\x7A]/;
29    
30 wakaba 1.15 %DEFAULT = (
31     -_ARRAY_NAME => 'value',
32     -_MEMBERS => [qw|value_type|],
33     -_METHODS => [qw|add count delete item
34     comment_add comment_delete comment_count
35     comment_item|], # replace (not implemented yet)
36     #encoding_after_encode
37     #encoding_before_decode
38     #field_param_name
39     #field_name
40     #field_ns
41     #format
42     #header_default_charset
43     #header_default_charset_input
44     #hook_encode_string
45     #hook_decode_string
46     -is_quoted_string => 1, ## Can it be itself a quoted-string?
47     -long_count => 10,
48     #parse_all
49     -remove_comment => 1,
50     -separator => ', ',
51     -separator_long => ', ',
52     -use_comment => 1,
53     -max => 0,
54     #value_type
55     -value_unsafe_rule => 'NON_http_token_wsp',
56     );
57    
58 wakaba 1.7 =head1 CONSTRUCTORS
59    
60     The following methods construct new objects:
61    
62     =over 4
63    
64     =cut
65    
66     ## Initialize of this class -- called by constructors
67     sub _init ($;%) {
68     my $self = shift;
69     my %options = @_;
70     $self->SUPER::_init (%DEFAULT, %options);
71 wakaba 1.15
72 wakaba 1.1 my %field_type = qw(accept-charset accept accept-encoding accept
73 wakaba 1.12 accept-language accept followup-to newsgroups
74 wakaba 1.6 posted-to newsgroups
75 wakaba 1.10 x-brother x-moe x-boss x-moe x-classmate x-moe x-daughter x-moe
76 wakaba 1.12 x-dearfriend x-moe x-favoritesong x-moe
77 wakaba 1.9 x-friend x-moe x-me x-moe
78     x-respect x-moe x-sister x-moe x-son x-moe x-sublimate x-moe x-wife x-moe);
79 wakaba 1.12 my $field_name = $self->{option}->{field_name};
80 wakaba 1.1 $field_name = $field_type{$field_name} || $field_name;
81 wakaba 1.2 if ($field_name eq 'newsgroups') {
82     $self->{option}->{separator} = ',';
83 wakaba 1.4 $self->{option}->{separator_long} = ', ';
84     $self->{option}->{long_count} = 5;
85     $self->{option}->{value_unsafe_rule} = 'NON_component';
86 wakaba 1.5 $self->{option}->{encoding_after_encode} = 'utf-8';
87 wakaba 1.4 } elsif ($field_name eq 'distribution') {
88     $self->{option}->{separator} = ',';
89     $self->{option}->{separator_long} = ', ';
90     $self->{option}->{long_count} = 15;
91     $self->{option}->{value_unsafe_rule} = 'NON_distribution';
92 wakaba 1.2 } elsif ($field_name eq 'x-moe') {
93 wakaba 1.7 $self->{option}->{is_quoted_string} = 0;
94 wakaba 1.9 $self->{option}->{value_type}->{'*default'} = ['Message::Field::XMoe'];
95 wakaba 1.1 } elsif ($field_name eq 'accept') {
96 wakaba 1.7 $self->{option}->{is_quoted_string} = 0;
97 wakaba 1.13 $self->{option}->{remove_comment} = 0;
98 wakaba 1.9 $self->{option}->{value_type}->{'*default'} = ['Message::Field::ValueParams'];
99 wakaba 1.14 } elsif ($self->{option}->{field_ns} eq $Message::Header::NS_phname2uri{'x-rfc822-list'}) {
100 wakaba 1.12 $self->{option}->{is_quoted_string} = 0;
101     $self->{option}->{remove_comment} = 0;
102     $self->{option}->{value_type}->{'*default'} = ['Message::Field::URI'];
103 wakaba 1.13 } elsif ($field_name eq 'man' || $field_name eq 'opt') {
104     $self->{option}->{is_quoted_string} = 0;
105     $self->{option}->{remove_comment} = 0;
106     $self->{option}->{value_type}->{'*default'} = ['Message::Field::ValueParams'];
107 wakaba 1.12 } elsif ($field_name eq 'uri') {
108 wakaba 1.7 $self->{option}->{is_quoted_string} = 0;
109     $self->{option}->{remove_comment} = 0;
110 wakaba 1.9 $self->{option}->{value_type}->{'*default'} = ['Message::Field::URI'];
111 wakaba 1.1 } elsif ($field_name eq 'encrypted') {
112     $self->{option}->{max} = 2;
113     }
114 wakaba 1.7
115     if (ref $options{value} eq 'ARRAY') {
116     $self->add (@{$options{value}});
117     } elsif ($options{value}) {
118     $self->add ($options{value});
119     }
120 wakaba 1.1 $self;
121     }
122    
123 wakaba 1.7 =item $csv = Message::Field::CSV->new ([%options])
124 wakaba 1.1
125 wakaba 1.7 Constructs a new object. You might pass some options as parameters
126     to the constructor.
127 wakaba 1.1
128     =cut
129    
130 wakaba 1.7 ## Inherited
131 wakaba 1.1
132 wakaba 1.7 =item $csv = Message::Field::CSV->parse ($field-body, [%options])
133 wakaba 1.1
134 wakaba 1.7 Constructs a new object with given field body. You might pass
135     some options as parameters to the constructor.
136 wakaba 1.1
137     =cut
138    
139     sub parse ($$;%) {
140 wakaba 1.7 my $class = shift;
141     my $self = bless {}, $class;
142 wakaba 1.1 my $field_body = shift;
143 wakaba 1.7 $self->_init (@_);
144     $field_body = Message::Util::delete_comment ($field_body)
145 wakaba 1.12 if $self->{option}->{use_comment} && $self->{option}->{remove_comment};
146 wakaba 1.7 push @{$self->{value}}, $self->_parse_list ($field_body);
147 wakaba 1.1 $self;
148     }
149    
150 wakaba 1.7 ## Parses csv string and returns array
151 wakaba 1.1 sub _parse_list ($$) {
152 wakaba 1.15 use re 'eval';
153 wakaba 1.1 my $self = shift;
154     my $fb = shift;
155     my @ids;
156 wakaba 1.7 $fb =~ s{((?:$REG{quoted_string}|$REG{angle_quoted}|$REG{domain_literal}|$REG{comment}|[^\x22\x28\x2C\x3C\x5B])+)}{
157 wakaba 1.1 my $s = $1; $s =~ s/^$REG{WSP}+//; $s =~ s/$REG{WSP}+$//;
158 wakaba 1.7 if ($self->{option}->{is_quoted_string}) {
159 wakaba 1.9 $s = $self->_parse_value ('*default' =>
160     Message::Util::decode_quoted_string ($self, $s))
161 wakaba 1.7 if $self->{option}->{parse_all};
162     push @ids, Message::Util::decode_quoted_string ($self, $s);
163 wakaba 1.1 } else {
164 wakaba 1.9 $s = $self->_parse_value ('*default' => $s) if $self->{option}->{parse_all};
165 wakaba 1.7 push @ids, $s;
166 wakaba 1.1 }
167     }goex;
168     @ids;
169     }
170    
171 wakaba 1.7 =back
172    
173     =head1 METHODS
174    
175     =over 4
176    
177     =head2 $values = $csv->value ($index1, [$index2, $index3,...])
178    
179     Returns C<$index>'th value(s).
180    
181     =cut
182    
183 wakaba 1.15 sub value ($@) { shift->item (@_) }
184 wakaba 1.7
185     =item $number = $csv->count
186 wakaba 1.1
187 wakaba 1.7 Returns number of values.
188 wakaba 1.1
189     =cut
190    
191 wakaba 1.15 ## Inherited
192 wakaba 1.7
193     =iterm $csv->add ($value1, [$value2, $value3,...])
194    
195     Adds (appends) new value(s).
196 wakaba 1.1
197     =cut
198    
199 wakaba 1.10 sub _add_array_check ($$\%) {
200 wakaba 1.1 my $self = shift;
201 wakaba 1.10 my ($value, $option) = @_;
202     my $value_option = {};
203     if (ref $value eq 'ARRAY') {
204     ($value, %$value_option) = @$value;
205     }
206     (1, value => $value);
207 wakaba 1.1 }
208 wakaba 1.15 *_replace_array_check = \&_add_array_check;
209 wakaba 1.1
210 wakaba 1.7 =item $field-body = $csv->stringify ()
211    
212     Returns C<field-body> as a string.
213    
214     =cut
215    
216 wakaba 1.1 sub stringify ($;%) {
217     my $self = shift;
218 wakaba 1.7 my %o = @_;
219     my %option = %{$self->{option}};
220     for (grep {/^-/} keys %o) {$option{substr ($_, 1)} = $o{$_}}
221     $self->_delete_empty;
222 wakaba 1.1 $option{max}--;
223 wakaba 1.12 $option{max} = $#{$self->{value}} if $option{max} < 0;
224 wakaba 1.7 $option{max} = $#{$self->{value}} if $#{$self->{value}} < $option{max};
225 wakaba 1.4 $option{separator} = $option{separator_long}
226     if $option{max} >= $option{long_count};
227 wakaba 1.1 join $option{separator},
228 wakaba 1.10 map {$self->_stringify_item ($_, \%option)} @{$self->{value}}[0..$option{max}];
229     }
230     *as_string = \&stringify;
231    
232     sub _stringify_item ($$\%) {
233     my $self = shift;
234     my $item = shift;
235     my $option = shift;
236     if ($$option{is_quoted_string}) {
237     my %s = &{$$option{hook_encode_string}} ($self,
238     $item, type => 'phrase');
239 wakaba 1.7 Message::Util::quote_unsafe_string ($s{value},
240 wakaba 1.10 unsafe => $$option{value_unsafe_rule});
241 wakaba 1.3 } else {
242 wakaba 1.10 $item;
243 wakaba 1.3 }
244 wakaba 1.1 }
245 wakaba 1.7
246 wakaba 1.11 =item $option-value = $csv->option ($option-name)
247 wakaba 1.7
248     Gets option value.
249 wakaba 1.1
250 wakaba 1.7 =item $csv->option ($option-name, $option-value, ...)
251 wakaba 1.4
252 wakaba 1.7 Set option value(s). You can pass multiple option name-value pair
253     as parameter when setting.
254 wakaba 1.4
255     =cut
256    
257 wakaba 1.7 ## Inherited
258    
259     =item $type = $csv->value_type
260    
261     Gets value-type. Value-type is package name of module
262     used for value modification. A special value-type, ':none:'
263     is used to indicate values are non-structured (and no module
264     is automatically used).
265    
266     =item $csv->value_type ([$type])
267    
268     Set value-type.
269    
270     =item $clone = $ua->clone ()
271 wakaba 1.1
272 wakaba 1.7 Returns a copy of the object.
273 wakaba 1.1
274 wakaba 1.7 =cut
275 wakaba 1.1
276 wakaba 1.15 ## value_type, clone, method_available: Inherited
277 wakaba 1.1
278 wakaba 1.7 =back
279 wakaba 1.1
280     =cut
281    
282 wakaba 1.7 ## Internal functions
283 wakaba 1.1
284 wakaba 1.7 sub _delete_empty ($) {
285 wakaba 1.1 my $self = shift;
286 wakaba 1.7 $self->{value} = [grep {length $_} @{$self->{value}}];
287 wakaba 1.1 }
288    
289     =head1 LICENSE
290    
291     Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
292    
293     This program is free software; you can redistribute it and/or modify
294     it under the terms of the GNU General Public License as published by
295     the Free Software Foundation; either version 2 of the License, or
296     (at your option) any later version.
297    
298     This program is distributed in the hope that it will be useful,
299     but WITHOUT ANY WARRANTY; without even the implied warranty of
300     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
301     GNU General Public License for more details.
302    
303     You should have received a copy of the GNU General Public License
304     along with this program; see the file COPYING. If not, write to
305     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
306     Boston, MA 02111-1307, USA.
307    
308     =head1 CHANGE
309    
310     See F<ChangeLog>.
311 wakaba 1.15 $Date: 2002/07/07 00:46:07 $
312 wakaba 1.1
313     =cut
314    
315     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24