line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Class::Monadic; |
2
|
|
|
|
|
|
|
|
3
|
10
|
|
|
10
|
|
584387
|
use 5.008_001; |
|
10
|
|
|
|
|
39
|
|
|
10
|
|
|
|
|
436
|
|
4
|
10
|
|
|
10
|
|
58
|
use strict; |
|
10
|
|
|
|
|
20
|
|
|
10
|
|
|
|
|
370
|
|
5
|
10
|
|
|
10
|
|
59
|
use warnings; |
|
10
|
|
|
|
|
24
|
|
|
10
|
|
|
|
|
563
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.04'; |
8
|
|
|
|
|
|
|
|
9
|
10
|
|
|
10
|
|
53
|
use Exporter qw(import); |
|
10
|
|
|
|
|
20
|
|
|
10
|
|
|
|
|
782
|
|
10
|
|
|
|
|
|
|
our @EXPORT_OK = qw(monadic); |
11
|
|
|
|
|
|
|
our %EXPORT_TAGS = (all => \@EXPORT_OK); |
12
|
|
|
|
|
|
|
|
13
|
10
|
|
|
10
|
|
59
|
use Carp (); |
|
10
|
|
|
|
|
18
|
|
|
10
|
|
|
|
|
171
|
|
14
|
10
|
|
|
10
|
|
11422
|
use Data::Util (); |
|
10
|
|
|
|
|
12154
|
|
|
10
|
|
|
|
|
246
|
|
15
|
10
|
|
|
10
|
|
104
|
use Scalar::Util (); |
|
10
|
|
|
|
|
28
|
|
|
10
|
|
|
|
|
297
|
|
16
|
10
|
|
|
10
|
|
11224
|
use Hash::FieldHash (); |
|
10
|
|
|
|
|
30041
|
|
|
10
|
|
|
|
|
3807
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
#use Class::Method::Modifiers::Fast (); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
Hash::FieldHash::fieldhash my %Meta; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub _cannot_initialize{ |
23
|
3
|
|
|
3
|
|
47
|
Carp::croak 'Cannot initialize a monadic object without object references'; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub monadic{ |
27
|
27
|
|
|
27
|
1
|
7005
|
my($object) = @_; |
28
|
27
|
100
|
|
|
|
99
|
ref($object) or _cannot_initialize(); |
29
|
|
|
|
|
|
|
|
30
|
26
|
|
66
|
|
|
355
|
return $Meta{$object} ||= __PACKAGE__->_new($object); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub initialize{ |
34
|
22
|
|
|
22
|
1
|
83969
|
my($class, $object) = @_; |
35
|
22
|
100
|
|
|
|
4011
|
ref($object) or _cannot_initialize(); |
36
|
|
|
|
|
|
|
|
37
|
21
|
|
66
|
|
|
4050
|
return $Meta{$object} ||= $class->_new($object); |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub _new{ |
42
|
32
|
|
|
32
|
|
3592
|
my($metaclass, $object) = @_; |
43
|
|
|
|
|
|
|
|
44
|
32
|
50
|
|
|
|
3753
|
if(Data::Util::is_glob_ref($object)){ |
45
|
0
|
|
|
|
|
0
|
$object = *{$object}{IO}; |
|
0
|
|
|
|
|
0
|
|
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
32
|
100
|
|
|
|
3900
|
my $class = Scalar::Util::blessed($object) or _cannot_initialize(); |
49
|
|
|
|
|
|
|
|
50
|
31
|
|
|
|
|
3982
|
$class =~ s/ ::0x[a-f0-9]+ \z//xms; # remove its monadic identity (in cloning) |
51
|
|
|
|
|
|
|
|
52
|
31
|
|
|
|
|
4115
|
my $meta = bless { |
53
|
|
|
|
|
|
|
class => $class, |
54
|
|
|
|
|
|
|
id => sprintf('0x%x', Scalar::Util::refaddr($object)), |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
object => $object, |
57
|
|
|
|
|
|
|
isa => undef, |
58
|
|
|
|
|
|
|
sclass => undef, |
59
|
|
|
|
|
|
|
methods => undef, |
60
|
|
|
|
|
|
|
modifiers => undef, |
61
|
|
|
|
|
|
|
fields => undef, |
62
|
|
|
|
|
|
|
field_map => undef, |
63
|
|
|
|
|
|
|
}, $metaclass; |
64
|
31
|
|
|
|
|
3511
|
Scalar::Util::weaken( $meta->{object} ); |
65
|
|
|
|
|
|
|
|
66
|
31
|
|
|
|
|
8268
|
&Internals::SvREADONLY($meta, 1); # lock_keys(%{$meta}) |
67
|
|
|
|
|
|
|
|
68
|
31
|
|
|
|
|
3520
|
my $sclass = $class . '::' . $meta->{id}; |
69
|
10
|
|
|
10
|
|
72
|
my $sclass_isa = do{ no strict 'refs'; \@{$sclass . '::ISA'} }; |
|
10
|
|
|
|
|
19
|
|
|
10
|
|
|
|
|
15000
|
|
|
31
|
|
|
|
|
9320
|
|
|
31
|
|
|
|
|
3744
|
|
|
31
|
|
|
|
|
11441
|
|
70
|
|
|
|
|
|
|
|
71
|
31
|
|
|
|
|
3473
|
$meta->{sclass} = $sclass; |
72
|
31
|
|
|
|
|
3384
|
$meta->{isa} = $sclass_isa; |
73
|
|
|
|
|
|
|
|
74
|
31
|
|
|
|
|
3613
|
my $base = $metaclass . '::Object'; |
75
|
31
|
100
|
|
|
|
3852
|
if($class->can('clone')){ |
76
|
4
|
|
|
|
|
10
|
$base .= '::Clonable'; |
77
|
|
|
|
|
|
|
} |
78
|
31
|
|
|
|
|
3319
|
@{$sclass_isa} = ($base, $class); |
|
31
|
|
|
|
|
7684
|
|
79
|
|
|
|
|
|
|
|
80
|
31
|
|
|
|
|
3859
|
bless $object, $sclass; # re-bless |
81
|
31
|
|
|
|
|
11320
|
return $meta; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub name{ |
86
|
4
|
|
|
4
|
1
|
7
|
my($meta) = @_; |
87
|
|
|
|
|
|
|
|
88
|
4
|
|
|
|
|
23
|
return $meta->{class}; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub id{ |
92
|
0
|
|
|
0
|
1
|
0
|
my($meta) = @_; |
93
|
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
0
|
return $meta->{id}; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
*add_methods = \&add_method; # alias |
98
|
|
|
|
|
|
|
sub add_method{ |
99
|
21
|
|
|
21
|
1
|
1180
|
my $meta = shift; |
100
|
|
|
|
|
|
|
|
101
|
21
|
|
|
3
|
|
1556
|
Data::Util::install_subroutine($meta->{sclass}, @_); # dies on fail |
|
3
|
|
|
|
|
3112
|
|
|
3
|
|
|
|
|
1295
|
|
|
3
|
|
|
|
|
32
|
|
102
|
|
|
|
|
|
|
|
103
|
19
|
|
100
|
|
|
1359
|
push @{$meta->{methods} ||= []}, @_; |
|
19
|
|
|
|
|
2509
|
|
104
|
19
|
|
|
|
|
2528
|
return; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
*add_fields = \&add_field; # alias |
108
|
|
|
|
|
|
|
sub add_field{ |
109
|
13
|
|
|
13
|
1
|
958
|
my $meta = shift; |
110
|
|
|
|
|
|
|
|
111
|
13
|
|
|
|
|
1212
|
my $fields_ref = Data::Util::mkopt_hash(\@_, 'add_field', [qw(Regexp ARRAY CODE)]); |
112
|
|
|
|
|
|
|
|
113
|
11
|
|
50
|
|
|
1157
|
my $field_map_ref = $meta->{field_map} ||= {}; |
114
|
|
|
|
|
|
|
|
115
|
11
|
|
50
|
|
|
1133
|
my $fields = $meta->{fields} ||= []; |
116
|
|
|
|
|
|
|
|
117
|
11
|
|
|
|
|
1101
|
while(my($name, $validator) = each %{$fields_ref}){ |
|
24
|
|
|
|
|
4597
|
|
118
|
13
|
|
|
|
|
933
|
my $slot; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
my $validate_sub; |
121
|
|
|
|
|
|
|
|
122
|
13
|
100
|
|
|
|
1061
|
if($validator){ |
123
|
10
|
100
|
|
|
|
11351
|
if(Data::Util::is_regex_ref $validator){ |
|
|
100
|
|
|
|
|
|
124
|
2
|
|
|
4
|
|
14
|
$validate_sub = sub{ $_[0] =~ /$validator/ }; |
|
4
|
|
|
|
|
92
|
|
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
elsif(Data::Util::is_array_ref $validator){ |
127
|
5
|
|
|
|
|
1277
|
my %words; |
128
|
5
|
|
|
|
|
1041
|
@words{@{$validator}} = (); |
|
5
|
|
|
|
|
2256
|
|
129
|
5
|
|
|
7
|
|
3954
|
$validate_sub = sub{ exists $words{ $_[0] } }; |
|
7
|
|
|
|
|
2343
|
|
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
else{ # CODE reference |
132
|
3
|
|
|
|
|
10
|
$validate_sub = $validator; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Data::Util::install_subroutine($meta->{sclass}, |
137
|
|
|
|
|
|
|
"get_$name" => sub{ |
138
|
9
|
100
|
|
9
|
|
10509
|
if(@_ > 1){ |
139
|
1
|
|
|
|
|
19
|
Carp::croak "Too many arguments for get_$name"; |
140
|
|
|
|
|
|
|
} |
141
|
8
|
|
|
|
|
38
|
return $slot; |
142
|
|
|
|
|
|
|
}, |
143
|
|
|
|
|
|
|
"set_$name" => sub{ |
144
|
17
|
100
|
|
17
|
|
4432
|
if(@_ > 2){ |
145
|
1
|
|
|
|
|
16
|
Carp::croak "Cannot set multiple values for set_$name"; |
146
|
|
|
|
|
|
|
} |
147
|
16
|
100
|
|
|
|
3831
|
if(defined $validate_sub){ |
148
|
13
|
|
|
|
|
3032
|
my $value = $_[1]; |
149
|
13
|
100
|
|
|
|
1761
|
$validate_sub->($value) |
150
|
|
|
|
|
|
|
or Carp::croak 'Invalid value ', Data::Util::neat($value), " for set_$name"; |
151
|
10
|
|
|
|
|
2256
|
$slot = $value; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
else{ |
154
|
3
|
|
|
|
|
5
|
$slot = $_[1]; |
155
|
|
|
|
|
|
|
} |
156
|
13
|
|
|
|
|
4914
|
return $_[0]; |
157
|
|
|
|
|
|
|
}, |
158
|
13
|
|
|
|
|
2603
|
); |
159
|
|
|
|
|
|
|
|
160
|
13
|
|
|
|
|
1371
|
$field_map_ref->{$name} = \$slot; |
161
|
13
|
|
|
|
|
1302
|
push @{$fields}, $name => $validate_sub; |
|
13
|
|
|
|
|
3733
|
|
162
|
|
|
|
|
|
|
} |
163
|
11
|
|
|
|
|
2555
|
return; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub add_modifier{ |
167
|
3
|
|
|
3
|
1
|
5
|
my $meta = shift; |
168
|
|
|
|
|
|
|
|
169
|
3
|
|
|
|
|
1335
|
require Class::Method::Modifiers::Fast; |
170
|
|
|
|
|
|
|
|
171
|
3
|
|
|
|
|
1217
|
Class::Method::Modifiers::Fast::_install_modifier($meta->{sclass}, @_); |
172
|
3
|
|
100
|
|
|
123
|
push @{$meta->{modifiers} ||= []}, @_; |
|
3
|
|
|
|
|
18
|
|
173
|
3
|
|
|
|
|
7
|
return; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub inject_base{ |
177
|
9
|
|
|
9
|
1
|
7378
|
my($meta, @components) = @_; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# NOTE: In 5.10.0, do{unshift @ISA, @classes} may cause 'uninitialized' warnings. |
180
|
|
|
|
|
|
|
|
181
|
9
|
|
|
|
|
6006
|
@{$meta->{isa}} = ( |
|
15
|
|
|
|
|
10179
|
|
182
|
9
|
|
|
|
|
3827
|
(grep{ not $meta->{object}->isa($_) } @components), |
183
|
9
|
|
|
|
|
4829
|
@{$meta->{isa}}, |
184
|
|
|
|
|
|
|
); |
185
|
9
|
|
|
|
|
14155
|
return; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub bless{ |
189
|
3
|
|
|
3
|
1
|
29
|
my($meta, $object) = @_; |
190
|
|
|
|
|
|
|
|
191
|
3
|
|
|
|
|
23
|
my $newmeta = ref($meta)->initialize($object); |
192
|
|
|
|
|
|
|
|
193
|
3
|
50
|
|
|
|
17
|
$newmeta->add_methods( @{ $meta->{methods} } ) |
|
3
|
|
|
|
|
14
|
|
194
|
|
|
|
|
|
|
if exists $meta->{methods}; |
195
|
|
|
|
|
|
|
|
196
|
3
|
50
|
|
|
|
13
|
if(exists $meta->{fields}){ |
197
|
3
|
|
|
|
|
5
|
$newmeta->add_fields(@{$meta->{fields}}); |
|
3
|
|
|
|
|
14
|
|
198
|
|
|
|
|
|
|
|
199
|
3
|
|
|
|
|
10
|
my $src_map_ref = $meta->{field_map}; |
200
|
3
|
|
|
|
|
7
|
my $new_map_ref = $newmeta->{field_map}; |
201
|
3
|
|
|
|
|
6
|
while(my($key, $val_ref) = each %{$src_map_ref}){ |
|
5
|
|
|
|
|
25
|
|
202
|
2
|
|
|
|
|
3
|
${$new_map_ref->{$key}} = ${$val_ref}; |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
12
|
|
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
2
|
|
|
|
|
13
|
$newmeta->inject_base(@{$meta->{isa}}[0 .. $#{$meta->{isa}}-2]) |
|
2
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
58
|
|
207
|
3
|
100
|
|
|
|
6
|
if @{$meta->{isa}} > 2; # other than Monadic::Object and its original class |
208
|
|
|
|
|
|
|
|
209
|
3
|
|
|
|
|
18
|
return $object; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub DESTROY{ |
213
|
30
|
|
|
30
|
|
15659
|
my($meta) = @_; |
214
|
30
|
|
|
|
|
5776
|
my $original_stash = Data::Util::get_stash($meta->{class}); |
215
|
|
|
|
|
|
|
|
216
|
30
|
|
|
|
|
5366
|
my $sclass_stashgv = delete $original_stash->{$meta->{id} . '::'}; |
217
|
|
|
|
|
|
|
|
218
|
30
|
|
|
|
|
4219
|
@{$meta->{isa}} = (); |
|
30
|
|
|
|
|
7968
|
|
219
|
30
|
|
|
|
|
4728
|
%{$sclass_stashgv} = (); |
|
30
|
|
|
|
|
7957
|
|
220
|
|
|
|
|
|
|
|
221
|
30
|
|
|
|
|
14426
|
return; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
package Class::Monadic::Object; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub STORABLE_freeze{ |
227
|
2
|
|
|
2
|
|
105
|
my($object, $cloning) = @_; |
228
|
|
|
|
|
|
|
|
229
|
2
|
100
|
|
|
|
107
|
return if $cloning; |
230
|
1
|
|
|
|
|
43
|
Carp::croak sprintf 'Cannot serialize monadic object (%s)', Data::Util::neat($object); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
package Class::Monadic::Object::Clonable; |
234
|
|
|
|
|
|
|
our @ISA = qw(Class::Monadic::Object); |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub clone{ |
237
|
2
|
|
|
2
|
|
27
|
my($object) = @_; |
238
|
2
|
|
|
|
|
6
|
my $meta = $Meta{$object}; |
239
|
|
|
|
|
|
|
|
240
|
2
|
50
|
|
|
|
19
|
my $clone = $meta->{class}->can('clone') or Carp::croak(qq{Cannot find "clone" method for $meta->{class}}); |
241
|
2
|
|
|
|
|
11
|
return $meta->bless( $clone->($object) ); |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
1; |
246
|
|
|
|
|
|
|
__END__ |