line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Hash::AutoHash::Record; |
2
|
|
|
|
|
|
|
our $VERSION='1.17_01'; |
3
|
|
|
|
|
|
|
$VERSION=eval $VERSION; # I think this is the accepted idiom.. |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
################################################################################# |
6
|
|
|
|
|
|
|
# |
7
|
|
|
|
|
|
|
# Author: Nat Goodman |
8
|
|
|
|
|
|
|
# Created: 09-03-05 |
9
|
|
|
|
|
|
|
# $Id: |
10
|
|
|
|
|
|
|
# |
11
|
|
|
|
|
|
|
# Flat and hierarchical record structures of the type encountered in Data::Pipeline |
12
|
|
|
|
|
|
|
# |
13
|
|
|
|
|
|
|
################################################################################# |
14
|
13
|
|
|
13
|
|
129648
|
use strict; |
|
13
|
|
|
|
|
17
|
|
|
13
|
|
|
|
|
304
|
|
15
|
13
|
|
|
13
|
|
46
|
use Carp; |
|
13
|
|
|
|
|
14
|
|
|
13
|
|
|
|
|
543
|
|
16
|
13
|
|
|
13
|
|
5851
|
use Hash::AutoHash; |
|
13
|
|
|
|
|
150439
|
|
|
13
|
|
|
|
|
65
|
|
17
|
13
|
|
|
13
|
|
2278
|
use base qw(Hash::AutoHash); |
|
13
|
|
|
|
|
20
|
|
|
13
|
|
|
|
|
2039
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our @NORMAL_EXPORT_OK=@Hash::AutoHash::EXPORT_OK; |
20
|
|
|
|
|
|
|
my $helper_class=__PACKAGE__.'::helper'; |
21
|
|
|
|
|
|
|
our @EXPORT_OK=$helper_class->EXPORT_OK; |
22
|
|
|
|
|
|
|
our @SUBCLASS_EXPORT_OK=$helper_class->SUBCLASS_EXPORT_OK; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
################################################################################# |
25
|
|
|
|
|
|
|
# helper package exists to avoid polluting Hash::AutoHash::Args namespace with |
26
|
|
|
|
|
|
|
# subs that would mask accessor/mutator AUTOLOADs |
27
|
|
|
|
|
|
|
# functions herein (except _new) are exportable by Hash::AutoHash::Args |
28
|
|
|
|
|
|
|
################################################################################# |
29
|
|
|
|
|
|
|
package Hash::AutoHash::Record::helper; |
30
|
|
|
|
|
|
|
our $VERSION=$Hash::AutoHash::Record::VERSION; |
31
|
13
|
|
|
13
|
|
60
|
use strict; |
|
13
|
|
|
|
|
22
|
|
|
13
|
|
|
|
|
240
|
|
32
|
13
|
|
|
13
|
|
43
|
use Carp; |
|
13
|
|
|
|
|
16
|
|
|
13
|
|
|
|
|
693
|
|
33
|
|
|
|
|
|
|
BEGIN { |
34
|
13
|
|
|
13
|
|
285
|
our @ISA=qw(Hash::AutoHash::helper); |
35
|
|
|
|
|
|
|
} |
36
|
13
|
|
|
13
|
|
50
|
use Hash::AutoHash qw(autohash_tie); |
|
13
|
|
|
|
|
13
|
|
|
13
|
|
|
|
|
37
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub _new { |
39
|
800
|
|
|
800
|
|
386079
|
my($helper_class,$class,@args)=@_; |
40
|
800
|
|
|
|
|
2717
|
my $self=autohash_tie Hash::AutoHash::Record::tie,@args; |
41
|
800
|
|
|
|
|
3441
|
bless $self,$class; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
# Override autohash_clear to allow clearing of specific keys |
44
|
|
|
|
|
|
|
sub autohash_clear { |
45
|
5
|
|
|
5
|
|
845
|
my $record=shift; |
46
|
5
|
|
|
|
|
23
|
tied(%$record)->CLEAR(@_); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
################################################################################# |
50
|
|
|
|
|
|
|
# Tied hash which implements Hash::AutoHash::Record |
51
|
|
|
|
|
|
|
################################################################################# |
52
|
|
|
|
|
|
|
package Hash::AutoHash::Record::tie; |
53
|
|
|
|
|
|
|
our $VERSION=$Hash::AutoHash::Record::VERSION; |
54
|
13
|
|
|
13
|
|
1918
|
use strict; |
|
13
|
|
|
|
|
16
|
|
|
13
|
|
|
|
|
229
|
|
55
|
13
|
|
|
13
|
|
43
|
use Carp; |
|
13
|
|
|
|
|
12
|
|
|
13
|
|
|
|
|
649
|
|
56
|
13
|
|
|
13
|
|
52
|
use Tie::Hash; |
|
13
|
|
|
|
|
13
|
|
|
13
|
|
|
|
|
267
|
|
57
|
13
|
|
|
13
|
|
41
|
use Scalar::Util qw(reftype); |
|
13
|
|
|
|
|
14
|
|
|
13
|
|
|
|
|
510
|
|
58
|
13
|
|
|
13
|
|
46
|
use List::MoreUtils qw(uniq); |
|
13
|
|
|
|
|
13
|
|
|
13
|
|
|
|
|
79
|
|
59
|
13
|
|
|
13
|
|
11629
|
use Storable qw(dclone); |
|
13
|
|
|
|
|
32834
|
|
|
13
|
|
|
|
|
808
|
|
60
|
13
|
|
|
13
|
|
72
|
use Hash::AutoHash qw(autohash_alias); |
|
13
|
|
|
|
|
16
|
|
|
13
|
|
|
|
|
85
|
|
61
|
13
|
|
|
13
|
|
7260
|
use Hash::AutoHash::AVPairsSingle; |
|
13
|
|
|
|
|
16952
|
|
|
13
|
|
|
|
|
840
|
|
62
|
13
|
|
|
13
|
|
7050
|
use Hash::AutoHash::AVPairsMulti; |
|
13
|
|
|
|
|
46940
|
|
|
13
|
|
|
|
|
81
|
|
63
|
|
|
|
|
|
|
our @ISA=qw(Tie::ExtraHash); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $i=0; |
66
|
13
|
|
|
13
|
|
1040
|
use constant STORAGE=>$i++; |
|
13
|
|
|
|
|
21
|
|
|
13
|
|
|
|
|
623
|
|
67
|
13
|
|
|
13
|
|
51
|
use constant DEFAULTS=>$i++; |
|
13
|
|
|
|
|
15
|
|
|
13
|
|
|
|
|
535
|
|
68
|
13
|
|
|
13
|
|
52
|
use constant DEFAULT_TYPE_SCALAR=>$i++; |
|
13
|
|
|
|
|
17
|
|
|
13
|
|
|
|
|
549
|
|
69
|
13
|
|
|
13
|
|
47
|
use constant DEFAULT_TYPE_ARRAY=>$i++; |
|
13
|
|
|
|
|
14
|
|
|
13
|
|
|
|
|
524
|
|
70
|
13
|
|
|
13
|
|
47
|
use constant DEFAULT_TYPE_HASH=>$i++; |
|
13
|
|
|
|
|
17
|
|
|
13
|
|
|
|
|
522
|
|
71
|
13
|
|
|
13
|
|
52
|
use constant UNIQUE=>$i++; |
|
13
|
|
|
|
|
13
|
|
|
13
|
|
|
|
|
523
|
|
72
|
13
|
|
|
13
|
|
48
|
use constant FILTER=>$i++; |
|
13
|
|
|
|
|
15
|
|
|
13
|
|
|
|
|
17355
|
|
73
|
|
|
|
|
|
|
# use constant FIELDS=>$i++; |
74
|
|
|
|
|
|
|
# use constant TYPES=>$i++; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# # undef means no type conversion |
77
|
|
|
|
|
|
|
# our $default_type_scalar; # no type conversion |
78
|
|
|
|
|
|
|
# our $default_type_array; # no type conversion |
79
|
|
|
|
|
|
|
# our $default_type_hash='Hash::AutoHash'; |
80
|
|
|
|
|
|
|
# our $default_type_refhash='Hash::AutoHash::AVPairsMulti'; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub TIEHASH { |
83
|
800
|
|
|
800
|
|
6695
|
my($class,@hash)=@_; |
84
|
800
|
|
|
|
|
1514
|
my $self=bless [],$class; |
85
|
|
|
|
|
|
|
# use initial values (possibly flattened) as defaults |
86
|
800
|
|
|
|
|
2280
|
my $defaults=$self->defaults(_flatten(@hash)); |
87
|
800
|
100
|
|
|
|
26453
|
$self->[STORAGE]=$defaults? dclone($defaults): {}; |
88
|
800
|
|
|
|
|
2421
|
$self; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
sub FETCH { |
91
|
24996
|
|
|
24996
|
|
10090436
|
my($self,$key)=@_; |
92
|
24996
|
|
|
|
|
23161
|
my $storage=$self->[STORAGE]; |
93
|
24996
|
|
|
|
|
22404
|
my $value=$storage->{$key}; |
94
|
24996
|
100
|
|
|
|
35983
|
if (wantarray) { |
95
|
|
|
|
|
|
|
# NG 09-10-12: line below was holdover from MultiValued. Not correct here |
96
|
|
|
|
|
|
|
# return () unless defined $value; |
97
|
4529
|
100
|
|
|
|
16022
|
return @$value if 'ARRAY' eq reftype($value); |
98
|
2117
|
100
|
|
|
|
7289
|
return %$value if 'HASH' eq reftype($value); |
99
|
571
|
|
|
|
|
1622
|
return ($value); |
100
|
|
|
|
|
|
|
} |
101
|
20467
|
|
|
|
|
34196
|
$value; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
# FUTURE possibility: check whether hash locked & key exists |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub STORE { |
106
|
1691
|
|
|
1691
|
|
330589
|
my($self,$key,@values)=@_; |
107
|
1691
|
|
|
|
|
2106
|
my $storage=$self->[STORAGE]; |
108
|
1691
|
|
|
|
|
3638
|
$self->_store($storage,$key,@values); |
109
|
1687
|
|
|
|
|
3598
|
$self->FETCH($key); |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
sub CLEAR { |
112
|
214
|
|
|
214
|
|
51846
|
my($self,@keys)=@_; |
113
|
214
|
|
|
|
|
640
|
my $defaults=$self->defaults; |
114
|
214
|
100
|
|
|
|
485
|
unless (@keys) { |
115
|
211
|
100
|
|
|
|
8976
|
$self->[STORAGE]=$defaults? dclone($defaults): {} |
116
|
|
|
|
|
|
|
} else { # clear specific keys |
117
|
3
|
|
|
|
|
7
|
my $storage=$self->[STORAGE]; |
118
|
3
|
|
|
|
|
5
|
my $defaults=$self->[DEFAULTS]; |
119
|
3
|
|
|
|
|
9
|
for my $key (@keys) { |
120
|
4
|
|
|
|
|
5
|
my $default=$defaults->{$key}; |
121
|
4
|
|
|
|
|
15
|
my $new=$self->_convert_initial_value($default); |
122
|
4
|
|
|
|
|
15
|
$storage->{$key}=$default; |
123
|
|
|
|
|
|
|
}} |
124
|
214
|
|
|
|
|
830
|
my $unique=$self->unique; |
125
|
214
|
100
|
|
|
|
834
|
$self->_unique($unique) if $unique; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
*clear=\&CLEAR; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# default values. |
130
|
|
|
|
|
|
|
# can be set from initial values suppled to TIEHASH, or explicitly |
131
|
|
|
|
|
|
|
sub defaults { |
132
|
1120
|
|
|
1120
|
|
31956
|
my $self=shift; |
133
|
1120
|
|
|
|
|
1218
|
my $defaults; |
134
|
1120
|
100
|
|
|
|
2336
|
if (@_) { # set new value |
135
|
553
|
100
|
100
|
|
|
3621
|
my @hash=(@_==1 && 'ARRAY' eq ref $_[0])? @{$_[0]}: (@_==1 && 'HASH' eq ref $_[0])? %{$_[0]}: |
|
2
|
100
|
66
|
|
|
3
|
|
|
8
|
|
|
|
|
27
|
|
136
|
|
|
|
|
|
|
@_; |
137
|
553
|
|
|
|
|
820
|
$defaults={}; |
138
|
553
|
|
|
|
|
1476
|
while (@hash>1) { # store initial values |
139
|
1622
|
|
|
|
|
2064
|
my($key,$value)=splice @hash,0,2; # shift 1st two elements |
140
|
1622
|
|
|
|
|
2530
|
$self->_store($defaults,$key,$value); |
141
|
|
|
|
|
|
|
} |
142
|
553
|
|
|
|
|
930
|
$self->[DEFAULTS]=$defaults; # set object attribute |
143
|
|
|
|
|
|
|
} else { # get defaults from object |
144
|
567
|
|
|
|
|
954
|
$defaults=$self->[DEFAULTS]; |
145
|
|
|
|
|
|
|
} |
146
|
1120
|
50
|
|
|
|
2090
|
wantarray? %{$defaults || {}}: $defaults; |
|
78
|
100
|
|
|
|
383
|
|
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# forcibly assign value or set to undef |
150
|
|
|
|
|
|
|
sub force { |
151
|
250
|
|
|
250
|
|
7082
|
my($self,$key)=splice @_,0,2; # shift 1st 2 elements |
152
|
250
|
|
|
|
|
193
|
my $storage=$self->[STORAGE]; |
153
|
250
|
|
|
|
|
273
|
$storage->{$key}=undef; # once field is undef, _store can do the rest |
154
|
250
|
100
|
|
|
|
499
|
$self->_store($storage,$key,@_) if @_; |
155
|
250
|
|
|
|
|
263
|
$self->FETCH($key); |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# code adapted from Hash::AutoHash::MultiValued |
159
|
|
|
|
|
|
|
sub unique { |
160
|
3098
|
|
|
3098
|
|
17699
|
my $self=shift; |
161
|
3098
|
100
|
|
|
|
7945
|
return $self->[UNIQUE] unless @_; |
162
|
586
|
|
|
|
|
1218
|
my $unique=$self->[UNIQUE]=shift; |
163
|
586
|
100
|
100
|
117
|
|
3050
|
$unique=$self->[UNIQUE]=sub {$_[0] eq $_[1]} if $unique && 'CODE' ne ref $unique; |
|
117
|
|
|
|
|
516
|
|
164
|
586
|
100
|
|
|
|
1871
|
$self->_unique($unique) if $unique; |
165
|
586
|
|
|
|
|
945
|
$unique; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
sub _unique { |
168
|
495
|
|
|
495
|
|
647
|
my($self,$unique)=@_; |
169
|
495
|
|
|
|
|
677
|
my $storage=$self->[STORAGE]; |
170
|
495
|
50
|
|
|
|
966
|
my @values=grep {defined $_ && 'ARRAY' eq reftype($_)} values %$storage; |
|
1464
|
|
|
|
|
5413
|
|
171
|
495
|
|
|
|
|
934
|
for my $values (@values) { |
172
|
805
|
100
|
|
|
|
2043
|
next unless @$values; |
173
|
|
|
|
|
|
|
# leave 1st value in @$values. put rest in @new_values |
174
|
225
|
|
|
|
|
390
|
my @new_values=splice(@$values,1); |
175
|
225
|
|
|
|
|
266
|
my($a,$b); |
176
|
225
|
|
|
|
|
447
|
for $a (@new_values) { |
177
|
79
|
100
|
|
|
|
171
|
push(@$values,$a) unless grep {$b=$_; &$unique($a,$b)} @$values; |
|
89
|
|
|
|
|
108
|
|
|
89
|
|
|
|
|
176
|
|
178
|
|
|
|
|
|
|
}} |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
# code adapted from Hash::AutoHash::MultiValued |
181
|
|
|
|
|
|
|
sub filter { |
182
|
76
|
|
|
76
|
|
2119
|
my $self=shift; |
183
|
76
|
100
|
|
|
|
253
|
my $filter=@_? $self->[FILTER]=shift: $self->[FILTER]; |
184
|
76
|
100
|
|
|
|
206
|
if ($filter) { # apply to existing values -- ARRAYs only |
185
|
52
|
100
|
|
|
|
206
|
$filter=$self->[FILTER]=\&uniq unless 'CODE' eq ref $filter; |
186
|
52
|
|
|
|
|
70
|
my $storage=$self->[STORAGE]; |
187
|
52
|
50
|
|
|
|
177
|
my @values=grep {defined $_ && 'ARRAY' eq reftype($_)} values %$storage; |
|
98
|
|
|
|
|
501
|
|
188
|
52
|
|
|
|
|
77
|
map {@$_=&$filter(@$_)} @values; # updates each list in-place |
|
86
|
|
|
|
|
522
|
|
189
|
|
|
|
|
|
|
} |
190
|
76
|
|
|
|
|
344
|
$filter; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# sub _default_type_scalar {shift->_default_type('scalar',@_);} |
194
|
|
|
|
|
|
|
# sub _default_type_array {shift->_default_type('array',@_);} |
195
|
|
|
|
|
|
|
# sub _default_type_hash {shift->_default_type('hash',@_);} |
196
|
|
|
|
|
|
|
# sub _default_type_refhash {shift->_default_type('refhash',@_);} |
197
|
|
|
|
|
|
|
# sub _default_type { |
198
|
|
|
|
|
|
|
# my($self,$type)=splice @_,0,2; |
199
|
|
|
|
|
|
|
# my $default; |
200
|
|
|
|
|
|
|
# if (@_) { # set new value in object |
201
|
|
|
|
|
|
|
# $default=$self->[uc "default_type_$type"]=$_[0]; |
202
|
|
|
|
|
|
|
# } else { # get defaults from object if possible, else from class |
203
|
|
|
|
|
|
|
# $default=$self->[uc "default_type_$type"]; |
204
|
|
|
|
|
|
|
# unless (defined $default) { # now look in class |
205
|
|
|
|
|
|
|
# my $class=ref $self; |
206
|
|
|
|
|
|
|
# no strict 'refs'; |
207
|
|
|
|
|
|
|
# my $class_var=$class."::default_type_$type"; |
208
|
|
|
|
|
|
|
# $default=${$class_var}; |
209
|
|
|
|
|
|
|
# }} |
210
|
|
|
|
|
|
|
# $default; |
211
|
|
|
|
|
|
|
# } |
212
|
|
|
|
|
|
|
# sub _convert_initial_value { |
213
|
|
|
|
|
|
|
# my($self,$value)=@_; |
214
|
|
|
|
|
|
|
# my $type= |
215
|
|
|
|
|
|
|
# (!ref $value)? 'scalar': |
216
|
|
|
|
|
|
|
# ('ARRAY' eq ref $value)? 'array': |
217
|
|
|
|
|
|
|
# ('HASH' eq ref $value)? 'hash': |
218
|
|
|
|
|
|
|
# ('REF' eq ref $value && 'HASH' eq ref $$value)? 'refhash': |
219
|
|
|
|
|
|
|
# undef; |
220
|
|
|
|
|
|
|
# my $class=$self->_default_type($type) if $type; |
221
|
|
|
|
|
|
|
# $value=$class? new $class $value: $value; |
222
|
|
|
|
|
|
|
# $value; |
223
|
|
|
|
|
|
|
# } |
224
|
|
|
|
|
|
|
sub _convert_initial_value { |
225
|
1224
|
|
|
1224
|
|
1116
|
my($self,$value)=@_; |
226
|
1224
|
100
|
100
|
|
|
4122
|
if ('HASH' eq ref $value) { |
|
|
100
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# attribute-single-value pair if no refs |
228
|
|
|
|
|
|
|
# else attribute-multi-value pair if only refs are ARRAY |
229
|
|
|
|
|
|
|
# else use as is |
230
|
311
|
|
|
|
|
498
|
my @values=values %$value; |
231
|
|
|
|
|
|
|
# CAUTION: doing grep below w/o map seems to stringify refs to things like ARRAY(0x1163510) |
232
|
311
|
|
|
|
|
465
|
my @refs=grep {$_} map {ref $_} @values; |
|
68
|
|
|
|
|
105
|
|
|
68
|
|
|
|
|
114
|
|
233
|
311
|
100
|
|
|
|
587
|
if (!@refs) { |
|
|
100
|
|
|
|
|
|
234
|
263
|
|
|
|
|
721
|
$value=new Hash::AutoHash::AVPairsSingle $value; |
235
|
|
|
|
|
|
|
} elsif (!grep !/^ARRAY$/,@refs) { |
236
|
21
|
|
|
|
|
85
|
$value=new Hash::AutoHash::AVPairsMulti $value; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
} elsif ('REF' eq ref $value && 'HASH' eq ref $$value) { |
239
|
247
|
|
|
|
|
625
|
my @values=values %$$value; |
240
|
|
|
|
|
|
|
# CAUTION: doing grep below w/o map seems to stringify refs to things like ARRAY(0x1163510) |
241
|
247
|
|
|
|
|
429
|
my @refs=grep {$_} map {ref $_} @values; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
10
|
|
242
|
247
|
50
|
|
|
|
619
|
if (!grep !/^ARRAY$/,@refs) { |
243
|
247
|
|
|
|
|
796
|
$value=new Hash::AutoHash::AVPairsMulti $$value; |
244
|
|
|
|
|
|
|
}} |
245
|
1224
|
|
|
|
|
15768
|
$value; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# logic: check type of old value and new value |
249
|
|
|
|
|
|
|
# old undef. anything goes. new value replaces old w/ initial value conversion |
250
|
|
|
|
|
|
|
# old scalar && new scalar. new value replaces old |
251
|
|
|
|
|
|
|
# old ARRAY && new any value. multi-valued field. new pushed onto old & possibly uniqued |
252
|
|
|
|
|
|
|
# old Hash::AutoHash. new must be HASH or ARRAY or list of key=>value pairs. |
253
|
|
|
|
|
|
|
# new elements set in old using method notation |
254
|
|
|
|
|
|
|
# old anything else. new value replaces old |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub _store { |
257
|
6056
|
|
|
6056
|
|
7575
|
my($self,$storage,$key,@new)=@_; |
258
|
6056
|
100
|
|
|
|
10386
|
return unless @new; |
259
|
4853
|
|
|
|
|
4612
|
my $old=$storage->{$key}; |
260
|
4853
|
100
|
|
|
|
9980
|
if (!defined $old) { # old undef. anything goes. new replaces old. |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
261
|
2495
|
100
|
66
|
|
|
8805
|
if (@new==1 && 'ARRAY' eq ref $new[0]) { # new multi-valued field |
262
|
1292
|
|
|
|
|
1988
|
$storage->{$key}=[]; # initialize to empty ARRAY. recursion will do the rest |
263
|
|
|
|
|
|
|
} else { |
264
|
1203
|
|
|
|
|
1146
|
my $new1=shift @new; |
265
|
1203
|
|
|
|
|
1823
|
$new1=$self->_convert_initial_value($new1); |
266
|
1203
|
|
|
|
|
1634
|
$storage->{$key}=$new1; |
267
|
|
|
|
|
|
|
} |
268
|
2495
|
|
|
|
|
3746
|
$self->_store($storage,$key,@new); # recurse |
269
|
|
|
|
|
|
|
} elsif (!ref $old) { # old scalar. new replaces old. must be scalar |
270
|
17
|
|
|
|
|
25
|
my $new=shift @new; |
271
|
17
|
|
|
|
|
43
|
$new=$self->_convert_initial_value($new); |
272
|
17
|
100
|
|
|
|
202
|
confess "Trying to store multiple values in single-valued field $key" if @new; |
273
|
16
|
50
|
|
|
|
35
|
confess "Trying to store reference in single-valued field $key" if ref $new; |
274
|
16
|
|
|
|
|
32
|
$storage->{$key}=$new; |
275
|
|
|
|
|
|
|
} elsif ('ARRAY' eq ref $old) { # old ARRAY. push new onto old. must be scalar |
276
|
|
|
|
|
|
|
# $self->_store_multi($old,@new); |
277
|
|
|
|
|
|
|
# code adapted from Hash::AutoHash::MultiValued |
278
|
2296
|
100
|
100
|
|
|
8756
|
@new=@{$new[0]} if @new==1 && 'ARRAY' eq ref $new[0]; |
|
2271
|
|
|
|
|
3372
|
|
279
|
2296
|
100
|
|
|
|
3516
|
confess "Trying to store reference in multi-valued field $key" if grep {ref($_)} @new; |
|
1126
|
|
|
|
|
2597
|
|
280
|
2295
|
100
|
|
|
|
3792
|
if (my $unique=$self->unique) { |
281
|
586
|
|
|
|
|
569
|
my($a,$b); |
282
|
586
|
|
|
|
|
1078
|
for $a (@new) { |
283
|
251
|
100
|
|
|
|
665
|
push(@$old,$a) unless grep {$b=$_; &$unique($a,$b)} @$old; |
|
283
|
|
|
|
|
379
|
|
|
283
|
|
|
|
|
556
|
|
284
|
|
|
|
|
|
|
}} else { |
285
|
1709
|
|
|
|
|
3628
|
push(@$old,@new); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
} elsif (UNIVERSAL::isa($old,'Hash::AutoHash')) { # old Hash::AutoHash |
288
|
42
|
|
|
|
|
69
|
@new=_flatten(@new); |
289
|
42
|
|
|
|
|
96
|
while (@new>1) { # store initial values |
290
|
52
|
|
|
|
|
295
|
my($key,$value)=splice @new,0,2; # shift 1st two elements |
291
|
52
|
|
|
|
|
273
|
$old->$key($value); # store using hash notation |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
} else { # old anything else. |
294
|
3
|
|
|
|
|
10
|
$storage->{$key}=$new[0]; # new replaces old |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
# # store into multi-valued field, or store multi-value into undef field |
298
|
|
|
|
|
|
|
# sub _store_multi { |
299
|
|
|
|
|
|
|
# my($self,$old,@new)=@_; |
300
|
|
|
|
|
|
|
# # code adapted from Hash::AutoHash::MultiValued |
301
|
|
|
|
|
|
|
# @new=@{$new[0]} if @new==1 && 'ARRAY' eq ref $new[0]; |
302
|
|
|
|
|
|
|
# if (my $unique=$self->unique) { |
303
|
|
|
|
|
|
|
# my($a,$b); |
304
|
|
|
|
|
|
|
# for $a (@new) { |
305
|
|
|
|
|
|
|
# push(@$old,$a) unless grep {$b=$_; &$unique($a,$b)} @$old; |
306
|
|
|
|
|
|
|
# }} else { |
307
|
|
|
|
|
|
|
# push(@$old,@new); |
308
|
|
|
|
|
|
|
# } |
309
|
|
|
|
|
|
|
# } |
310
|
|
|
|
|
|
|
sub _flatten { |
311
|
842
|
100
|
|
842
|
|
2269
|
if (@_==1) { |
312
|
595
|
100
|
|
|
|
2433
|
return ('ARRAY' eq ref $_[0])? @{$_[0]}: ('HASH' eq ref $_[0])? %{$_[0]}: @_; |
|
5
|
100
|
|
|
|
17
|
|
|
587
|
|
|
|
|
2501
|
|
313
|
|
|
|
|
|
|
} |
314
|
247
|
|
|
|
|
636
|
@_; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
1; |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
__END__ |