| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Class; |
|
2
|
|
|
|
|
|
|
|
|
3
|
15
|
|
|
15
|
|
784279
|
use strict; |
|
|
15
|
|
|
|
|
24
|
|
|
|
15
|
|
|
|
|
483
|
|
|
4
|
15
|
|
|
15
|
|
91
|
use warnings; |
|
|
15
|
|
|
|
|
34
|
|
|
|
15
|
|
|
|
|
642
|
|
|
5
|
15
|
|
|
15
|
|
3705
|
use version; |
|
|
15
|
|
|
|
|
17900
|
|
|
|
15
|
|
|
|
|
76
|
|
|
6
|
15
|
|
|
15
|
|
1050
|
use Exporter; |
|
|
15
|
|
|
|
|
33
|
|
|
|
15
|
|
|
|
|
740
|
|
|
7
|
15
|
|
|
15
|
|
633
|
use mro (); |
|
|
15
|
|
|
|
|
928
|
|
|
|
15
|
|
|
|
|
3746
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = qv('v0.1.1'); |
|
10
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:MANWAR'; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our @EXPORT = qw(extends with); |
|
13
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my %BUILD_METHODS_CACHE; |
|
16
|
|
|
|
|
|
|
my %METHOD_COPY_CACHE; |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Precomputed skip patterns for faster method filtering |
|
19
|
|
|
|
|
|
|
my %SKIP_METHODS = map { $_ => 1 } qw( |
|
20
|
|
|
|
|
|
|
BUILD new extends with does import AUTOLOAD DESTROY BEGIN END |
|
21
|
|
|
|
|
|
|
ISA VERSION EXPORT AUTHORITY INC |
|
22
|
|
|
|
|
|
|
); |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub new { |
|
25
|
34
|
|
|
34
|
1
|
7971
|
my $class = shift; |
|
26
|
34
|
|
|
|
|
72
|
my %attrs = @_; |
|
27
|
34
|
|
|
|
|
141
|
my $self = bless { %attrs }, $class; |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Use cached BUILD methods for maximum performance |
|
30
|
34
|
|
66
|
|
|
178
|
my $build_methods = $BUILD_METHODS_CACHE{$class} ||= _compute_build_methods($class); |
|
31
|
34
|
|
|
|
|
89
|
$_->($self, \%attrs) for @$build_methods; |
|
32
|
|
|
|
|
|
|
|
|
33
|
34
|
|
|
|
|
231
|
return $self; |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub _compute_build_methods { |
|
37
|
31
|
|
|
31
|
|
41
|
my $class = shift; |
|
38
|
|
|
|
|
|
|
|
|
39
|
31
|
|
|
|
|
57
|
my @build_order; |
|
40
|
|
|
|
|
|
|
my %visited; |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Depth-first traversal for true parent-first order |
|
43
|
31
|
|
|
|
|
109
|
_depth_first_traverse($class, \@build_order, \%visited); |
|
44
|
|
|
|
|
|
|
|
|
45
|
31
|
|
|
|
|
59
|
my @build_methods; |
|
46
|
31
|
|
|
|
|
45
|
foreach my $c (@build_order) { |
|
47
|
15
|
|
|
15
|
|
86
|
no strict 'refs'; |
|
|
15
|
|
|
|
|
46
|
|
|
|
15
|
|
|
|
|
2241
|
|
|
48
|
71
|
100
|
|
|
|
98
|
if (defined &{"${c}::BUILD"}) { |
|
|
71
|
|
|
|
|
236
|
|
|
49
|
21
|
|
|
|
|
25
|
push @build_methods, \&{"${c}::BUILD"}; |
|
|
21
|
|
|
|
|
52
|
|
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
31
|
|
|
|
|
124
|
return \@build_methods; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub _depth_first_traverse { |
|
57
|
73
|
|
|
73
|
|
153
|
my ($class, $order, $visited) = @_; |
|
58
|
|
|
|
|
|
|
|
|
59
|
73
|
100
|
|
|
|
235
|
return if $visited->{$class}++; |
|
60
|
|
|
|
|
|
|
|
|
61
|
15
|
|
|
15
|
|
86
|
no strict 'refs'; |
|
|
15
|
|
|
|
|
46
|
|
|
|
15
|
|
|
|
|
2249
|
|
|
62
|
71
|
|
|
|
|
89
|
my @parents = @{"${class}::ISA"}; |
|
|
71
|
|
|
|
|
329
|
|
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Process all parents first (depth-first) |
|
65
|
71
|
|
|
|
|
112
|
foreach my $parent (@parents) { |
|
66
|
42
|
|
|
|
|
170
|
_depth_first_traverse($parent, $order, $visited); |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Then add current class |
|
70
|
71
|
|
|
|
|
250
|
push @$order, $class; |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub extends { |
|
74
|
31
|
|
|
31
|
1
|
1268258
|
my ($maybe_class, @maybe_parents) = @_; |
|
75
|
31
|
|
|
|
|
88
|
my $child_class = caller; |
|
76
|
|
|
|
|
|
|
|
|
77
|
31
|
|
|
|
|
130
|
_delete_build_cache($child_class); |
|
78
|
|
|
|
|
|
|
|
|
79
|
31
|
100
|
|
|
|
123
|
my @parents = @maybe_parents ? ($maybe_class, @maybe_parents) : ($maybe_class); |
|
80
|
|
|
|
|
|
|
|
|
81
|
15
|
|
|
15
|
|
97
|
no strict 'refs'; |
|
|
15
|
|
|
|
|
34
|
|
|
|
15
|
|
|
|
|
4065
|
|
|
82
|
|
|
|
|
|
|
|
|
83
|
31
|
|
|
|
|
77
|
for my $parent_class (@parents) { |
|
84
|
34
|
100
|
|
|
|
126
|
die "Recursive inheritance detected: $child_class cannot extend itself" |
|
85
|
|
|
|
|
|
|
if $child_class eq $parent_class; |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# Efficient parent loading - only load from disk if necessary |
|
88
|
33
|
100
|
100
|
|
|
187
|
unless ($INC{"$parent_class.pm"} || defined &{"${parent_class}::new"}) { |
|
|
30
|
|
|
|
|
167
|
|
|
89
|
2
|
|
|
|
|
5
|
(my $parent_file = "$parent_class.pm") =~ s{::}{/}g; |
|
90
|
2
|
|
|
|
|
3
|
eval { require $parent_file }; |
|
|
2
|
|
|
|
|
508
|
|
|
91
|
|
|
|
|
|
|
# ignore errors - parent might be defined inline |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Link inheritance if not already linked |
|
95
|
33
|
50
|
|
|
|
45
|
unless (grep { $_ eq $parent_class } @{"${child_class}::ISA"}) { |
|
|
7
|
|
|
|
|
26
|
|
|
|
33
|
|
|
|
|
211
|
|
|
96
|
33
|
|
|
|
|
46
|
push @{"${child_class}::ISA"}, $parent_class; |
|
|
33
|
|
|
|
|
372
|
|
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# Copy public methods from parent to child for direct access |
|
100
|
33
|
|
|
|
|
96
|
_copy_public_methods($child_class, $parent_class); |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub _copy_public_methods { |
|
105
|
33
|
|
|
33
|
|
62
|
my ($child, $parent) = @_; |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# Use cache to avoid re-copying methods for same parent-child pair |
|
108
|
33
|
|
|
|
|
57
|
my $cache_key = "$child|$parent"; |
|
109
|
33
|
50
|
|
|
|
96
|
return if $METHOD_COPY_CACHE{$cache_key}; |
|
110
|
33
|
|
|
|
|
72
|
$METHOD_COPY_CACHE{$cache_key} = 1; |
|
111
|
|
|
|
|
|
|
|
|
112
|
15
|
|
|
15
|
|
124
|
no strict 'refs'; |
|
|
15
|
|
|
|
|
22
|
|
|
|
15
|
|
|
|
|
5262
|
|
|
113
|
33
|
|
|
|
|
40
|
my $parent_symtab = \%{"${parent}::"}; |
|
|
33
|
|
|
|
|
76
|
|
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Single pass with optimized checks |
|
116
|
33
|
|
|
|
|
228
|
for my $method (keys %$parent_symtab) { |
|
117
|
|
|
|
|
|
|
# Skip special methods and private methods quickly |
|
118
|
741
|
100
|
|
|
|
1089
|
next if $SKIP_METHODS{$method}; |
|
119
|
554
|
100
|
|
|
|
656
|
next if $method =~ /^_/; |
|
120
|
553
|
100
|
|
|
|
692
|
next if $method =~ /::$/; # Skip nested packages |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Skip if already defined in child or not a CODE ref in parent |
|
123
|
506
|
100
|
|
|
|
445
|
next if defined &{"${child}::${method}"}; |
|
|
506
|
|
|
|
|
1245
|
|
|
124
|
505
|
100
|
|
|
|
429
|
next unless defined &{"${parent}::${method}"}; |
|
|
505
|
|
|
|
|
956
|
|
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Copy the method |
|
127
|
485
|
|
|
|
|
457
|
*{"${child}::${method}"} = \&{"${parent}::${method}"}; |
|
|
485
|
|
|
|
|
919
|
|
|
|
485
|
|
|
|
|
600
|
|
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub _delete_build_cache { |
|
132
|
31
|
|
|
31
|
|
60
|
my ($class) = @_; |
|
133
|
31
|
|
|
|
|
134
|
delete $BUILD_METHODS_CACHE{$class}; |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Clear cache for all classes that inherit from this one |
|
136
|
31
|
|
|
|
|
83
|
for my $cached_class (keys %BUILD_METHODS_CACHE) { |
|
137
|
42
|
50
|
|
|
|
75
|
if (_inherits_from($cached_class, $class)) { |
|
138
|
0
|
|
|
|
|
0
|
delete $BUILD_METHODS_CACHE{$cached_class}; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# Also clear method copy cache for affected classes |
|
143
|
31
|
|
|
|
|
106
|
for my $cache_key (keys %METHOD_COPY_CACHE) { |
|
144
|
72
|
|
|
|
|
171
|
my ($child, $parent) = split(/\|/, $cache_key); |
|
145
|
72
|
100
|
66
|
|
|
206
|
if ($child eq $class || _inherits_from($child, $class)) { |
|
146
|
3
|
|
|
|
|
8
|
delete $METHOD_COPY_CACHE{$cache_key}; |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub _inherits_from { |
|
152
|
282
|
|
|
282
|
|
384
|
my ($class, $parent) = @_; |
|
153
|
|
|
|
|
|
|
|
|
154
|
15
|
|
|
15
|
|
85
|
no strict 'refs'; |
|
|
15
|
|
|
|
|
20
|
|
|
|
15
|
|
|
|
|
2726
|
|
|
155
|
282
|
|
|
|
|
287
|
my @isa = @{"${class}::ISA"}; |
|
|
282
|
|
|
|
|
775
|
|
|
156
|
|
|
|
|
|
|
|
|
157
|
282
|
50
|
|
|
|
403
|
return 1 if grep { $_ eq $parent } @isa; |
|
|
171
|
|
|
|
|
354
|
|
|
158
|
|
|
|
|
|
|
|
|
159
|
282
|
|
|
|
|
403
|
foreach my $direct_parent (@isa) { |
|
160
|
171
|
50
|
|
|
|
274
|
return 1 if _inherits_from($direct_parent, $parent); |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
282
|
|
|
|
|
644
|
return 0; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub import { |
|
167
|
82
|
|
|
82
|
|
148529
|
my ($class, @args) = @_; |
|
168
|
82
|
|
|
|
|
153
|
my $caller = caller; |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# Enable strict and warnings |
|
171
|
82
|
|
|
|
|
504
|
strict->import; |
|
172
|
82
|
|
|
|
|
1404
|
warnings->import; |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Load Role.pm if exists |
|
175
|
82
|
|
|
|
|
127
|
eval { require Role }; |
|
|
82
|
|
|
|
|
5412
|
|
|
176
|
82
|
50
|
|
|
|
190
|
if (!$@) { |
|
177
|
15
|
|
|
15
|
|
111
|
no strict 'refs'; |
|
|
15
|
|
|
|
|
24
|
|
|
|
15
|
|
|
|
|
1127
|
|
|
178
|
82
|
|
|
|
|
113
|
*{"${caller}::with"} = \&Role::with; |
|
|
82
|
|
|
|
|
346
|
|
|
179
|
82
|
|
|
|
|
104
|
*{"${caller}::does"} = \&Role::does; |
|
|
82
|
|
|
|
|
181
|
|
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# Install new and extends |
|
183
|
15
|
|
|
15
|
|
70
|
no strict 'refs'; |
|
|
15
|
|
|
|
|
31
|
|
|
|
15
|
|
|
|
|
2877
|
|
|
184
|
82
|
|
|
|
|
119
|
*{"${caller}::new"} = \&Class::new; |
|
|
82
|
|
|
|
|
226
|
|
|
185
|
82
|
|
|
|
|
121
|
*{"${caller}::extends"} = \&Class::extends; |
|
|
82
|
|
|
|
|
221
|
|
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# optional extends => Parent |
|
188
|
82
|
50
|
33
|
|
|
20239
|
if (@args && $args[0] eq 'extends') { |
|
189
|
0
|
|
|
|
|
|
$class->extends(@args[1..$#args]); |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head1 NAME |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Class - Lightweight Perl object system with parent-first BUILD and method copying |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head1 VERSION |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Version v0.1.1 |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
use Class; |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Simple class with attributes and BUILD |
|
206
|
|
|
|
|
|
|
package Person; |
|
207
|
|
|
|
|
|
|
use Class; |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub BUILD { |
|
210
|
|
|
|
|
|
|
my ($self, $attrs) = @_; |
|
211
|
|
|
|
|
|
|
$self->{full_name} = $attrs->{first} . ' ' . $attrs->{last}; |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
package Employee; |
|
215
|
|
|
|
|
|
|
use Class; |
|
216
|
|
|
|
|
|
|
extends 'Person'; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub BUILD { |
|
219
|
|
|
|
|
|
|
my ($self, $attrs) = @_; |
|
220
|
|
|
|
|
|
|
$self->{employee_id} = $attrs->{id}; |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Create an object |
|
224
|
|
|
|
|
|
|
my $emp = Employee->new(first => 'John', last => 'Doe', id => 123); |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
print $emp->{full_name}; # John Doe |
|
227
|
|
|
|
|
|
|
print $emp->{employee_id}; # 123 |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# Using roles if Role.pm is available |
|
230
|
|
|
|
|
|
|
package Manager; |
|
231
|
|
|
|
|
|
|
use Class; |
|
232
|
|
|
|
|
|
|
with 'SomeRole'; |
|
233
|
|
|
|
|
|
|
my $mgr = Manager->new(); |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
Class provides a lightweight Perl object system with: |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=over 4 |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=item * Parent-first constructor building via C methods. |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=item * Simple inheritance via C with method copying. |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item * Optional role consumption via C and C (if C module is available). |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=item * Automatic caching of BUILD order for efficient object creation. |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=item * Optimized method copying for better performance. |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=back |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
This module includes performance optimizations such as cached BUILD method resolution, |
|
254
|
|
|
|
|
|
|
efficient parent class loading, and optimized method copying with caching. |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=cut |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=head1 BUILD METHODS |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Classes can define a C method: |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub BUILD { |
|
263
|
|
|
|
|
|
|
my ($self, $attrs) = @_; |
|
264
|
|
|
|
|
|
|
# initialize object |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
All BUILD methods in the inheritance chain are called in parent-first order during C. The order is determined by depth-first traversal, ensuring that parent classes are always initialized before their children. |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
For diamond inheritance patterns: |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
A |
|
272
|
|
|
|
|
|
|
/ \ |
|
273
|
|
|
|
|
|
|
B C |
|
274
|
|
|
|
|
|
|
\ / |
|
275
|
|
|
|
|
|
|
D |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
BUILD methods are called in the order: A, B, C, D (true parent-first order) |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=head1 METHOD COPYING |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
This system copies public methods from parent classes to child classes. This design enables: |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=over 4 |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=item * Direct method access in child symbol tables |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=item * Proper functioning of object cloning |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=item * Better performance for frequently called methods |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=item * Compatibility with code that expects direct method access |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=back |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
The following methods are NOT copied: |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=over 4 |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=item * Special methods (BUILD, new, extends, with, does, import, AUTOLOAD, DESTROY) |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=item * Private methods (starting with underscore) |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=item * Package metadata (ISA, VERSION, EXPORT, etc.) |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=back |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=head1 ROLES |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
If a C module is available, you can consume roles via: |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
with 'RoleName'; |
|
312
|
|
|
|
|
|
|
does 'RoleName'; |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
This provides role-based composition for shared behavior. The Role module must be installed separately. |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head1 PERFORMANCE OPTIMISATIONS |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
This version includes significant performance improvements: |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=over 4 |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=item * Cached BUILD method resolution using depth-first parent-first order |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=item * Precomputed skip patterns for fast method filtering |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=item * Method copying cache to avoid duplicate operations |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=item * Efficient parent class loading with minimal overhead |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item * Optimized symbol table scanning |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=back |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=head1 CACHING |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
Class uses internal caches to optimise performance: |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=over 4 |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=item * C<%BUILD_METHODS_CACHE> - caches linearised parent-first build order |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=item * C<%METHOD_COPY_CACHE> - tracks which parent-child pairs have had methods copied |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=back |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Caches are automatically updated when inheritance changes via C. |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head1 ERROR HANDLING |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=over 4 |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=item * Recursive inheritance is detected and throws an exception. |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=item * Failure to load a parent class is non-fatal (parent might be defined inline). |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=back |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head1 EXAMPLES |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=head2 Basic Inheritance with Method Copying |
|
361
|
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
package Animal; |
|
363
|
|
|
|
|
|
|
use Class; |
|
364
|
|
|
|
|
|
|
sub speak { "animal sound" } |
|
365
|
|
|
|
|
|
|
sub eat { "eating" } |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
package Dog; |
|
368
|
|
|
|
|
|
|
use Class; |
|
369
|
|
|
|
|
|
|
extends 'Animal'; |
|
370
|
|
|
|
|
|
|
sub speak { "woof" } # Overrides parent method |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
my $dog = Dog->new; |
|
373
|
|
|
|
|
|
|
print $dog->speak; # "woof" (from Dog) |
|
374
|
|
|
|
|
|
|
print $dog->eat; # "eating" (copied from Animal) |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# Method is copied to Dog's symbol table |
|
377
|
|
|
|
|
|
|
no strict 'refs'; |
|
378
|
|
|
|
|
|
|
print defined &Dog::eat ? "copied" : "not copied"; # "copied" |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=head2 Diamond Inheritance |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
package A; |
|
383
|
|
|
|
|
|
|
use Class; |
|
384
|
|
|
|
|
|
|
sub BUILD { print "A BUILD\n" } |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
package B; |
|
387
|
|
|
|
|
|
|
use Class; |
|
388
|
|
|
|
|
|
|
extends 'A'; |
|
389
|
|
|
|
|
|
|
sub BUILD { print "B BUILD\n" } |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
package C; |
|
392
|
|
|
|
|
|
|
use Class; |
|
393
|
|
|
|
|
|
|
extends 'A'; |
|
394
|
|
|
|
|
|
|
sub BUILD { print "C BUILD\n" } |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
package D; |
|
397
|
|
|
|
|
|
|
use Class; |
|
398
|
|
|
|
|
|
|
extends 'B', 'C'; |
|
399
|
|
|
|
|
|
|
sub BUILD { print "D BUILD\n" } |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
my $d = D->new; |
|
402
|
|
|
|
|
|
|
# Output: A BUILD, B BUILD, C BUILD, D BUILD |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head2 Object Cloning with Method Copying |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
package Base; |
|
407
|
|
|
|
|
|
|
use Class; |
|
408
|
|
|
|
|
|
|
sub clone_method { "works" } |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
package Child; |
|
411
|
|
|
|
|
|
|
use Class; |
|
412
|
|
|
|
|
|
|
extends 'Base'; |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
my $original = Child->new; |
|
415
|
|
|
|
|
|
|
my $cloned = bless { %$original }, ref($original); |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
# Works because methods are copied to Child |
|
418
|
|
|
|
|
|
|
print $cloned->clone_method; # "works" |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=head1 METHODS |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=head2 new |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
my $obj = Class->new(%attributes); |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Constructs a new object of the class, calling all C methods from parent classes in parent-first order. All attributes are passed to C as a hashref. |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
The constructor uses cached BUILD method references for optimal performance, especially in deep inheritance hierarchies. |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=cut |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head2 _compute_build_methods |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
my $build_methods = _compute_build_methods($class); |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
Internal method that computes the BUILD methods in parent-first order using depth-first traversal. |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
This ensures BUILD methods are called from the root parent down to the child class, which is essential for proper initialisation in inheritance hierarchies. |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=cut |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head2 _depth_first_traverse |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
_depth_first_traverse($class, \@order, \%visited); |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
Internal recursive method that performs depth-first traversal of the inheritance hierarchy. |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
This method ensures that parent classes are always processed before their children, which is crucial for correct BUILD method ordering. |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
=cut |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=head2 extends |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
extends 'ParentClass'; |
|
455
|
|
|
|
|
|
|
extends 'Parent1', 'Parent2'; |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Adds one or more parent classes to the calling class. This method: |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=over 4 |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=item * Automatically loads parent classes if not already loaded |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=item * Prevents recursive inheritance |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=item * Copies public methods from parents to children |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=item * Maintains inheritance via C<@ISA> |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=item * Clears relevant caches to ensure consistency |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=back |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
Method copying is performed to ensure that inherited methods are directly available in the child class's symbol table, which enables features like object cloning to work correctly. |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=cut |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head2 _copy_public_methods |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
_copy_public_methods($child_class, $parent_class); |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
Internal method that copies public methods from parent to child class. This method: |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=over 4 |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=item * Skips special methods (BUILD, new, extends, etc.) |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=item * Skips private methods (starting with underscore) |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=item * Uses caching to avoid duplicate copying |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=item * Only copies methods not already defined in child |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=back |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
This optimised implementation uses precomputed skip patterns and caching for better performance. |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=cut |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head2 _delete_build_cache |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
_delete_build_cache($class); |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
Internal method that clears the BUILD methods cache for a class and all classes that inherit from it. |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
This ensures cache consistency when inheritance relationships change. Also clears method copy caches for affected classes. |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=cut |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=head2 _inherits_from |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
_inherits_from($class, $parent); |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
Internal recursive method that checks if a class inherits from another class, either directly or indirectly. |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
Returns true if C<$class> inherits from C<$parent>, false otherwise. |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=cut |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=head1 IMPORT |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
use Class; |
|
522
|
|
|
|
|
|
|
use Class 'extends' => 'Parent'; |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
When imported, Class automatically installs the following functions into the caller's namespace: |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=over 4 |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=item * C - constructor |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=item * C - inheritance helper |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=item * C and C - if Role.pm is available |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=back |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
Optionally, you can specify C in the import statement to immediately set a parent class: |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
use Class 'extends' => 'Parent'; |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
The import method also enables L and L in the calling package. |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=cut |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=head1 AUTHOR |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
Mohammad Sajid Anwar, C<< >> |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=head1 REPOSITORY |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
L |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
=head1 BUGS |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
Please report any bugs or feature requests through the web interface at L. |
|
555
|
|
|
|
|
|
|
I will be notified and then you'll automatically be notified of progress on your bug as I make changes. |
|
556
|
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
=head1 SUPPORT |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
perldoc Class |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
You can also look for information at: |
|
564
|
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=over 4 |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=item * BUG Report |
|
568
|
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
L |
|
570
|
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=back |
|
572
|
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
574
|
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
Copyright (C) 2025 Mohammad Sajid Anwar. |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
This program is free software; you can redistribute it and / or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at: |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
L |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. |
|
586
|
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=cut |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
1; # End of Class |