29 |
sub _init ($;%) { |
sub _init ($;%) { |
30 |
my $self = shift; |
my $self = shift; |
31 |
my %options = @_; |
my %options = @_; |
32 |
$self->{option} = { |
$self->{option} = Message::Util::make_clone ({ |
33 |
encoding_after_encode => '*default', |
_ARRAY_NAME => '', |
34 |
encoding_before_decode => '*default', |
_HASH_NAME => '', |
35 |
field_name => 'x-structured', |
dont_croak => 0, ## Don't die unless very very fatal error |
36 |
field_name_case_sensible => 0, |
encoding_after_encode => '*default', |
37 |
format => 'mail-rfc2822', |
encoding_before_decode => '*default', |
38 |
hook_encode_string => #sub {shift; (value => shift, @_)}, |
field_param_name => '', |
39 |
\&Message::Util::encode_header_string, |
field_name => 'x-structured', |
40 |
hook_decode_string => #sub {shift; (value => shift, @_)}, |
format => 'mail-rfc2822', |
41 |
\&Message::Util::decode_header_string, |
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 |
$self->{field_body} = ''; |
$self->{field_body} = ''; |
52 |
|
|
53 |
for my $name (keys %options) { |
for my $name (keys %options) { |
91 |
|
|
92 |
=back |
=back |
93 |
|
|
94 |
|
=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 |
=head1 METHODS |
=head1 METHODS |
351 |
|
|
352 |
=over 4 |
=over 4 |
411 |
} |
} |
412 |
} |
} |
413 |
|
|
414 |
|
## 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 |
=item $self->clone () |
=item $self->clone () |
433 |
|
|
434 |
Returns a copy of Message::Field::Structured object. |
Returns a copy of Message::Field::Structured object. |
438 |
sub clone ($) { |
sub clone ($) { |
439 |
my $self = shift; |
my $self = shift; |
440 |
my $clone = ref($self)->new; |
my $clone = ref($self)->new; |
441 |
for my $name (%{$self->{option}}) { |
$clone->_delete_empty; |
442 |
if (ref $self->{option}->{$name} eq 'HASH') { |
$clone->{option} = Message::Util::make_clone ($self->{option}); |
443 |
$clone->{option}->{$name} = {%{$self->{option}->{$name}}}; |
$clone->{field_body} = Message::Util::make_clone ($self->{field_body}); |
|
} elsif (ref $self->{option}->{$name} eq 'ARRAY') { |
|
|
$clone->{option}->{$name} = [@{$self->{option}->{$name}}]; |
|
|
} else { |
|
|
$clone->{option}->{$name} = $self->{option}->{$name}; |
|
|
} |
|
|
} |
|
|
$clone->{field_body} = ref $self->{field_body}? |
|
|
$self->{field_body}->clone: |
|
|
$self->{field_body}; |
|
444 |
## Common hash value (not used in this module) |
## Common hash value (not used in this module) |
445 |
if (ref $self->{value} eq 'HASH') { |
$clone->{value} = Message::Util::make_clone ($self->{value}); |
446 |
$clone->{value} = {map {ref $_? $_->clone: $_} %{$self->{value}}}; |
$clone->{comment} = Message::Util::make_clone ($self->{comment}); |
|
} elsif (ref $self->{value} eq 'ARRAY') { |
|
|
$clone->{value} = [map {ref $_? $_->clone: $_} @{$self->{value}}]; |
|
|
} elsif (ref $self->{value}) { |
|
|
$clone->{value} = $self->{value}->clone; |
|
|
} else { |
|
|
$clone->{value} = $self->{value}; |
|
|
} |
|
|
for my $i (@{$self->{comment}}) { |
|
|
if (ref $self->{comment}->[$i] eq 'HASH') { |
|
|
$clone->{comment}->[$i] = {%{$self->{comment}->[$i]}}; |
|
|
} elsif (ref $self->{comment}->[$i] eq 'ARRAY') { |
|
|
$clone->{comment}->[$i] = [@{$self->{comment}->[$i]}]; |
|
|
} else { |
|
|
$clone->{comment}->[$i] = $self->{comment}->[$i]; |
|
|
} |
|
|
} |
|
447 |
$clone; |
$clone; |
448 |
} |
} |
449 |
|
|
450 |
sub _n11n_field_name ($$) { |
sub _n11n_field_name ($$) { |
451 |
my $self = shift; |
my $self = shift; |
452 |
my $s = shift; |
my $s = shift; |
453 |
$s = lc $s unless $self->{option}->{field_name_case_sensible}; |
$s = lc $s ;#unless $self->{option}->{field_name_case_sensible}; |
454 |
$s; |
$s; |
455 |
} |
} |
456 |
|
|