line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
3
|
|
|
3
|
|
82582
|
use warnings; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
111
|
|
3
|
3
|
|
|
3
|
|
16
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
243
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Data::Polymorph; |
6
|
|
|
|
|
|
|
|
7
|
3
|
|
|
3
|
|
17
|
use Carp; |
|
3
|
|
|
|
|
10
|
|
|
3
|
|
|
|
|
302
|
|
8
|
3
|
|
|
3
|
|
18
|
use Scalar::Util qw( blessed looks_like_number ); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
355
|
|
9
|
3
|
|
|
3
|
|
4383
|
use UNIVERSAL qw( isa can ); |
|
3
|
|
|
|
|
45
|
|
|
3
|
|
|
|
|
16
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Data::Polymorph - Yet another approach for polymorphism. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 VERSION |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Version 0.01 |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=cut |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
my $poly = Data::Polymorph->new; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
## defining external method 'freeze' |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
$poly->define( 'FileHandle' => freeze => sub{ |
30
|
|
|
|
|
|
|
"do{ require Symbol; bless Symbol::gensym(), '".ref($_[0])."'}" |
31
|
|
|
|
|
|
|
} ); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
$poly->define( "UNIVERSAL" => freeze => sub{ |
34
|
|
|
|
|
|
|
use Data::Dumper; |
35
|
|
|
|
|
|
|
sprintf( 'do{ my %s }', Dumper $_[0]); |
36
|
|
|
|
|
|
|
}); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
## it returns `undef' |
39
|
|
|
|
|
|
|
FileHandle->can('freeze'); |
40
|
|
|
|
|
|
|
UNIVERSAL->('freeze'); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
### |
43
|
|
|
|
|
|
|
### applying defined method. |
44
|
|
|
|
|
|
|
### |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
## returns "do{ requier Symbol; bless Symbol::gensym(), 'FileHandle'}" |
47
|
|
|
|
|
|
|
$poly->apply( FileHandle->new , 'freeze' ); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head1 DESCRIPTION |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
This module provides gentle way of polymorphic behaviors definition |
52
|
|
|
|
|
|
|
for special cases that aren't original concerns. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Applying this solution dissipates necessity for making an original |
55
|
|
|
|
|
|
|
namespace dirty. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=over 4 |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=item C |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
## |
64
|
|
|
|
|
|
|
## If external method "foo" is not defined into the $poly... |
65
|
|
|
|
|
|
|
## |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
$poly->runs_native(1); |
68
|
|
|
|
|
|
|
$poly->apply($obj, foo => $bar ); # ... same as $obj->foo($bar) |
69
|
|
|
|
|
|
|
$poly->runs_native(0); |
70
|
|
|
|
|
|
|
$poly->apply($obj, foo => $bar ); # ... die |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
If this value is true and the object uses C |
73
|
|
|
|
|
|
|
when the method is not defined. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item C |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
The dictionary of class methods. |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=item C |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
The dictionary of type methods. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=back |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head1 METHODS |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=over 4 |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item C |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
$poly = Data::Polymorph->new(); |
92
|
|
|
|
|
|
|
$poly = Data::Polymorph->new( runs_native => 0 ); |
93
|
|
|
|
|
|
|
$poly = Data::Polymorph->new( runs_native => 1 ); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
Constructs and returns a new instance of this class. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=cut |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
{ |
102
|
|
|
|
|
|
|
my @Template = |
103
|
|
|
|
|
|
|
( |
104
|
|
|
|
|
|
|
[ class_methods => sub{{}} ], |
105
|
|
|
|
|
|
|
[ type_methods => sub{ |
106
|
|
|
|
|
|
|
return |
107
|
|
|
|
|
|
|
[ |
108
|
|
|
|
|
|
|
[Undef => sub{ !defined( $_[1] ); },{},'Any'], |
109
|
|
|
|
|
|
|
[ScalarRef => sub{ isa( $_[1], 'SCALAR' ) },{},'Ref'], |
110
|
|
|
|
|
|
|
[CodeRef => sub{ isa( $_[1], 'CODE' ) },{},'Ref'], |
111
|
|
|
|
|
|
|
[ArrayRef => sub{ isa( $_[1], 'ARRAY' ) },{},'Ref'], |
112
|
|
|
|
|
|
|
[HashRef => sub{ isa( $_[1], 'HASH' ) },{},'Ref'], |
113
|
|
|
|
|
|
|
[GlobRef => sub{ isa( $_[1], 'GLOB' ) },{},'Ref'], |
114
|
|
|
|
|
|
|
[RefRef => sub{ isa( $_[1], 'REF' ) },{},'Ref'], |
115
|
|
|
|
|
|
|
[Ref => sub{ ref( $_[1] ) and 1 },{},'Defined'], |
116
|
|
|
|
|
|
|
[Num => sub{ looks_like_number( $_[1] ) },{},'Value'], |
117
|
|
|
|
|
|
|
[Glob => sub{ isa(\$_[1],'GLOB' ) },{},'Value'], |
118
|
|
|
|
|
|
|
[Str => sub{ isa(\$_[1],'SCALAR'); },{},'Value'], |
119
|
|
|
|
|
|
|
[Value => sub{ 1 },{},'Defined'], |
120
|
|
|
|
|
|
|
[Defined => sub{ 1 },{},'Any'], |
121
|
|
|
|
|
|
|
[Any => sub{ 1 },{},undef], |
122
|
|
|
|
|
|
|
] |
123
|
|
|
|
|
|
|
}], |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
[ _dic => sub{ |
126
|
|
|
|
|
|
|
my $self = shift; |
127
|
|
|
|
|
|
|
return { map{ ($_->[0] , $_)} @{$self->type_methods} }; |
128
|
|
|
|
|
|
|
}], |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
[ runs_native => sub{0} ], |
131
|
|
|
|
|
|
|
); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub{ |
134
|
|
|
|
|
|
|
my ( $caller ) = caller; |
135
|
|
|
|
|
|
|
foreach (@_){ |
136
|
|
|
|
|
|
|
my $field = $_; |
137
|
3
|
|
|
3
|
|
5538
|
my $glob = do{ no strict 'refs'; \*{"${caller}::$field"} }; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
4174
|
|
138
|
|
|
|
|
|
|
*{$glob} = sub ($;$){ |
139
|
186
|
|
|
186
|
|
184
|
my $self = shift; |
140
|
186
|
50
|
|
|
|
1176
|
return $self->{$field} unless @_; |
141
|
0
|
|
|
|
|
0
|
$self->{$field} = shift; |
142
|
|
|
|
|
|
|
}; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
}->( map { $_->[0]} @Template ); |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub new { |
147
|
3
|
|
|
3
|
1
|
556
|
my ($self, %args) = @_; |
148
|
3
|
|
33
|
|
|
34
|
$self = bless {} , (blessed $self) || $self; |
149
|
3
|
|
|
|
|
37
|
foreach my $spec ( @Template ){ |
150
|
12
|
|
|
|
|
39
|
$self->{$spec->[0]} = $spec->[1]->($self); |
151
|
|
|
|
|
|
|
} |
152
|
3
|
50
|
|
|
|
17
|
$self->runs_native(1) if $args{runs_native}; |
153
|
3
|
|
|
|
|
10
|
$self; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item C |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
$type = $poly->type( 123 ); # returns 'Num' |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Returns the type name of the given object. Types are below. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Any |
166
|
|
|
|
|
|
|
Undef |
167
|
|
|
|
|
|
|
Defined |
168
|
|
|
|
|
|
|
Value |
169
|
|
|
|
|
|
|
Num |
170
|
|
|
|
|
|
|
Str |
171
|
|
|
|
|
|
|
Glob |
172
|
|
|
|
|
|
|
Ref |
173
|
|
|
|
|
|
|
ScalarRef |
174
|
|
|
|
|
|
|
HashRef |
175
|
|
|
|
|
|
|
ArrayRef |
176
|
|
|
|
|
|
|
CodeRef |
177
|
|
|
|
|
|
|
RefRef |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
They seem like L Types. |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Actually, I designed these types based on the man pages from |
182
|
|
|
|
|
|
|
L. |
183
|
|
|
|
|
|
|
Because these were not designed for constraint, they never relate with |
184
|
|
|
|
|
|
|
L types. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item C |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$poly->is_type('Any') ; # => 1 |
189
|
|
|
|
|
|
|
$poly->is_type('Str') ; # => 1 |
190
|
|
|
|
|
|
|
$poly->is_type('UNIVERSAL') ; # => 0 |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Returns true if given name is a defined type name. Otherwise, |
193
|
|
|
|
|
|
|
returns false. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item C |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
$type = $poly->super_type('Str'); # => Value |
198
|
|
|
|
|
|
|
$type = $poly->super_type('Undef'); # => Any |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
Returns name of the type which is the super type of the given type name. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=item C |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
$type = $poly->class( $obj ); |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Returns class name or type name of the given object. |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=cut |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub type { |
211
|
50
|
|
|
50
|
1
|
5970
|
my ( $self, $obj ) = @_; |
212
|
50
|
|
|
|
|
60
|
foreach my $slot ( @{$self->type_methods} ) { |
|
50
|
|
|
|
|
74
|
|
213
|
258
|
100
|
|
|
|
354
|
return $slot->[0] if $slot->[1]->($self, $obj) ; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub is_type { |
218
|
37
|
|
|
37
|
1
|
39
|
my ($self, $type) = @_; |
219
|
37
|
100
|
|
|
|
53
|
(exists $self->_dic->{$type}) ? 1 : 0; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub super_type { |
223
|
1
|
|
|
1
|
1
|
19
|
my ($self, $type) = @_; |
224
|
1
|
50
|
|
|
|
12
|
confess "$type is not a type" unless $self->is_type( $type ); |
225
|
0
|
|
0
|
|
|
0
|
($self->_dic->{$type} || [])->[3]; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub class { |
229
|
2
|
|
|
2
|
1
|
3
|
my ( $self, $obj ) = @_; |
230
|
2
|
50
|
|
|
|
262
|
blessed( $obj ) or $self->type( $obj ); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=item C |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
$poly->define_type_method('ArrayRef' => 'values' => sub{ @$_[0]}); |
236
|
|
|
|
|
|
|
$poly->define_type_method('HashRef' => 'values' => sub{ values %$_[0]}); |
237
|
|
|
|
|
|
|
$poly->define_type_method('Any' => 'values' => sub{ $_[0] }); |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
Defines a method for the given type. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=item C |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
$poly->define_class_method( 'Class::Name' => 'method' => sub{ |
244
|
|
|
|
|
|
|
# code reference |
245
|
|
|
|
|
|
|
} ); |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Defines an external method for a given class which can be appliabled |
248
|
|
|
|
|
|
|
by the instance of this class. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item C |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
$poly->define('Class::Name' => 'method' => sub{ ... } ); |
253
|
|
|
|
|
|
|
$poly->define('Undef' => 'method' => sub{ ... } ); |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Defines a method for a type or a class. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=cut |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub define_type_method { |
260
|
10
|
|
|
10
|
1
|
1038
|
my ( $self, $class, $method , $code ) = @_; |
261
|
10
|
|
|
|
|
30
|
foreach my $slot ( @{$self->type_methods}) { |
|
10
|
|
|
|
|
13
|
|
262
|
85
|
100
|
|
|
|
686
|
next unless $slot->[0] eq $class; |
263
|
9
|
|
|
|
|
26
|
return $slot->[2]->{$method} = $code; |
264
|
|
|
|
|
|
|
} |
265
|
1
|
|
|
|
|
110
|
confess "unknown type: $class"; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub define_class_method { |
269
|
7
|
|
|
7
|
1
|
741
|
my ( $self, $class, $method , $code ) = @_; |
270
|
7
|
|
100
|
|
|
15
|
my $slot = ($self->class_methods->{$method} ||= []); |
271
|
7
|
|
|
|
|
8
|
my $i = 0; |
272
|
7
|
|
|
|
|
20
|
for(; $i < scalar @$slot ; $i++){ |
273
|
13
|
|
|
|
|
14
|
my $klass = $slot->[$i]->[0]; |
274
|
|
|
|
|
|
|
|
275
|
13
|
50
|
|
|
|
16
|
if( $klass eq $class ){ |
276
|
0
|
|
|
|
|
0
|
$slot->[$i]->[1] = $code; |
277
|
0
|
|
|
|
|
0
|
return; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
13
|
100
|
|
|
|
58
|
last if isa $class => $klass; |
281
|
|
|
|
|
|
|
} |
282
|
7
|
|
|
|
|
26
|
splice @$slot, $i, 0, [$class => $code]; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub define { |
286
|
15
|
|
|
15
|
1
|
499
|
my ( $self, $class, $method, $code ) = @_; |
287
|
15
|
100
|
|
|
|
27
|
goto ( $self->is_type( $class ) |
288
|
|
|
|
|
|
|
? \&define_type_method |
289
|
|
|
|
|
|
|
: \&define_class_method ); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=item C |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
$meth = $poly->type_method( 'ArrayRef' => 'values' ); |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
Returns a CODE reference which is invoked as the method of given type. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=item C |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
$meth = $poly->super_type_method( 'ArrayRef' => 'values' ); |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
Returns a CODE reference which is invoked as the super method of given type. |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=cut |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub type_method { |
308
|
13
|
|
|
13
|
1
|
731
|
my ( $self, $type, $method ) = @_; |
309
|
13
|
100
|
|
|
|
26
|
confess "$type is not a type" unless $self->is_type( $type ); |
310
|
12
|
|
|
|
|
25
|
while ( $type ){ |
311
|
22
|
|
|
|
|
35
|
my $slot = $self->_dic->{$type}; |
312
|
22
|
|
|
|
|
40
|
my $code = $slot->[2]->{$method}; |
313
|
22
|
100
|
|
|
|
81
|
return $code if $code; |
314
|
11
|
|
|
|
|
24
|
$type = $slot->[3]; |
315
|
|
|
|
|
|
|
} |
316
|
1
|
|
|
|
|
9
|
undef; |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub super_type_method { |
320
|
8
|
|
|
8
|
1
|
712
|
my ($self, $type, $method ) = @_; |
321
|
8
|
100
|
|
|
|
16
|
confess "$type is not a type" unless $self->is_type( $type ); |
322
|
7
|
|
|
|
|
10
|
my $count = 0; |
323
|
7
|
|
|
|
|
17
|
for (my $slot; $type ; $type = $slot->[3] ){ |
324
|
20
|
|
|
|
|
36
|
$slot = $self->_dic->{$type}; |
325
|
20
|
|
|
|
|
31
|
my $code = $slot->[2]->{$method}; |
326
|
20
|
100
|
|
|
|
46
|
next unless $code; |
327
|
12
|
100
|
|
|
|
38
|
return $code if $count; |
328
|
6
|
|
|
|
|
13
|
$count++; |
329
|
|
|
|
|
|
|
} |
330
|
1
|
|
|
|
|
12
|
undef; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=item C |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
$meth = $poly->class_method( 'A::Class' => 'method' ); |
336
|
|
|
|
|
|
|
($poly->apply( 'A::Class' => $method ) or |
337
|
|
|
|
|
|
|
sub{ confess "method $method is not defined" } )->( $args .... ); |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Returns a CODE reference which is invoked as the method of given class. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=item C |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
$super = $poly->super_class_method( 'A::Class' => 'method' ); |
344
|
|
|
|
|
|
|
($poly->apply( 'A::Class' => $method ) or |
345
|
|
|
|
|
|
|
sub{ confess "method $method is not defined" } )->( $args .... ); |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
Returns a CODE reference which is invoked as the super method of given class. |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=cut |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub class_method { |
352
|
23
|
|
|
23
|
1
|
30
|
my ( $self, $class, $method ) = @_; |
353
|
23
|
|
100
|
|
|
38
|
my $slot = ($self->class_methods->{$method} ||= []); |
354
|
23
|
|
|
|
|
43
|
foreach my $meth ( @$slot ){ |
355
|
99
|
100
|
|
|
|
330
|
next unless isa( $class, $meth->[0] ); |
356
|
20
|
|
|
|
|
69
|
return $meth->[1]; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub super_class_method { |
361
|
11
|
|
|
11
|
1
|
14
|
my ( $self, $class, $method ) = @_; |
362
|
11
|
|
50
|
|
|
19
|
my $slot = ($self->class_methods->{$method} ||= []); |
363
|
11
|
|
|
|
|
12
|
my $count = 0; |
364
|
11
|
|
|
|
|
17
|
foreach my $meth ( @$slot ){ |
365
|
51
|
100
|
|
|
|
160
|
next unless isa( $class, $meth->[0] ); |
366
|
20
|
100
|
|
|
|
47
|
return $meth->[1] if $count; |
367
|
11
|
|
|
|
|
16
|
$count++; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=item C |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
$code = $poly->method( [] => 'values' ); |
374
|
|
|
|
|
|
|
$code = $poly->method( qr{foo} => 'values' ); |
375
|
|
|
|
|
|
|
$code = $poly->method( FileHandle->new => 'values' ); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Returns a CODE reference which is invoked as the method of given object. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=item C |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
$code = $poly->super_method( [] => 'values' ); |
382
|
|
|
|
|
|
|
$code = $poly->super_method( qr{foo} => 'values' ); |
383
|
|
|
|
|
|
|
$code = $poly->super_method( FileHandle->new => 'values' ); |
384
|
|
|
|
|
|
|
$code = $poly->super_method( 'Any' => 'values' ); # always undef |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
Returns a CODE reference which is invoked as the super method of given object. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=cut |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
sub method { |
391
|
19
|
|
|
19
|
1
|
23
|
my ( $self, $obj, $method ) = @_; |
392
|
19
|
|
|
|
|
44
|
my $class = blessed( $obj ); |
393
|
19
|
|
|
|
|
41
|
my $type = $self->type( $obj ); |
394
|
19
|
100
|
66
|
|
|
72
|
($class |
395
|
|
|
|
|
|
|
? ( $self->class_method( $class, $method ) or |
396
|
|
|
|
|
|
|
$self->type_method( $type, $method ) or |
397
|
|
|
|
|
|
|
( $self->runs_native and UNIVERSAL::can( $obj , $method ) )) |
398
|
|
|
|
|
|
|
: $self->type_method( $type, $method )); |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
sub _native_super { |
402
|
|
|
|
|
|
|
|
403
|
0
|
|
|
0
|
|
0
|
my ( $class, $method ) = @_; |
404
|
3
|
|
|
3
|
|
20
|
my $glob = do{ no strict 'refs'; \*{"$class::$method"} }; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
1342
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
405
|
3
|
|
|
3
|
|
18
|
my @isa = do{ no strict 'refs'; @{"${class}::ISA"} }; |
|
3
|
|
|
|
|
14
|
|
|
3
|
|
|
|
|
1490
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
406
|
|
|
|
|
|
|
|
407
|
0
|
0
|
|
|
|
0
|
if( *{$glob}{CODE} ){ |
|
0
|
|
|
|
|
0
|
|
408
|
0
|
|
|
|
|
0
|
foreach my $parent ( @isa ){ |
409
|
0
|
|
|
|
|
0
|
my $code = UNIVERSAL::can( $parent, $method ); |
410
|
0
|
0
|
|
|
|
0
|
return $code if $code; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
else { |
414
|
0
|
|
|
|
|
0
|
foreach my $parent ( @isa ){ |
415
|
0
|
|
|
|
|
0
|
my $code = _native_super( $parent, $method ); |
416
|
0
|
0
|
|
|
|
0
|
return $code if $code; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub super_method { |
422
|
18
|
|
|
18
|
1
|
26
|
my ( $self, $obj, $method ) = @_; |
423
|
18
|
|
|
|
|
44
|
my $class = blessed( $obj ); |
424
|
18
|
|
|
|
|
39
|
my $type = $self->type( $obj ); |
425
|
|
|
|
|
|
|
|
426
|
18
|
100
|
|
|
|
44
|
if ( $class ){ |
427
|
12
|
|
|
|
|
27
|
my $uni = $self->class_method( UNIVERSAL => $method ); |
428
|
12
|
100
|
|
|
|
25
|
if( $class eq 'UNIVERSAL' ) { |
429
|
|
|
|
|
|
|
|
430
|
1
|
50
|
|
|
|
5
|
return $self->type_method( $type => $method ) if $uni; |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
else { |
434
|
|
|
|
|
|
|
|
435
|
11
|
|
|
|
|
24
|
my $code = $self->super_class_method( $class, $method ); |
436
|
11
|
100
|
|
|
|
53
|
return $code if $code; |
437
|
|
|
|
|
|
|
|
438
|
2
|
50
|
|
|
|
7
|
if( $self->runs_native ) { |
439
|
0
|
|
|
|
|
0
|
$code = _native_super( $class, $method ); |
440
|
0
|
0
|
|
|
|
0
|
return $code if $code; |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
2
|
100
|
|
|
|
9
|
return $self->type_method( $type => $method ) if $uni; |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
7
|
|
|
|
|
17
|
$self->super_type_method( $type => $method ); |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=item C |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
$poly->apply( $obj => 'method' => $arg1, $arg1 , $arg3 .... ); |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Invokes a method which was defined. |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=item C |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
$poly->super( $obj => 'method' => $arg1, $arg1 , $arg3 .... ); |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
Invokes a super method which was defined.. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=back |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=cut |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub apply { |
469
|
19
|
|
|
19
|
1
|
7834
|
my $self = shift; |
470
|
19
|
|
|
|
|
26
|
my $obj = $_[0]; |
471
|
19
|
|
|
|
|
29
|
my $method = splice @_, 1, 1; |
472
|
|
|
|
|
|
|
goto ( $self->method( $obj => $method ) or |
473
|
1
|
|
|
1
|
|
4
|
sub{ confess sprintf( 'method "%s" is not defined in %s', |
474
|
|
|
|
|
|
|
$method, |
475
|
19
|
|
100
|
|
|
67
|
$self->class($obj)) }); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub super { |
479
|
18
|
|
|
18
|
1
|
7360
|
my $self = shift; |
480
|
18
|
|
|
|
|
56
|
my $obj = $_[0]; |
481
|
18
|
|
|
|
|
26
|
my $method = splice @_, 1, 1; |
482
|
|
|
|
|
|
|
goto ( $self->super_method( $obj => $method ) or |
483
|
1
|
|
|
1
|
|
8
|
sub{ confess sprintf( 'method "SUPER::%s" is not defined in %s', |
484
|
|
|
|
|
|
|
$method, |
485
|
18
|
|
100
|
|
|
38
|
$self->class($obj)) }); |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
1; # End of Data::Polymorph |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
__END__ |