| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Class::More; |
|
2
|
|
|
|
|
|
|
|
|
3
|
22
|
|
|
22
|
|
854184
|
use strict; |
|
|
22
|
|
|
|
|
39
|
|
|
|
22
|
|
|
|
|
766
|
|
|
4
|
22
|
|
|
22
|
|
93
|
use warnings; |
|
|
22
|
|
|
|
|
42
|
|
|
|
22
|
|
|
|
|
1048
|
|
|
5
|
22
|
|
|
22
|
|
3677
|
use version; |
|
|
22
|
|
|
|
|
16869
|
|
|
|
22
|
|
|
|
|
129
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = qv('v0.1.1'); |
|
8
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:MANWAR'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
my %ACCESSOR_CACHE; |
|
11
|
|
|
|
|
|
|
my %BUILD_ORDER_CACHE; |
|
12
|
|
|
|
|
|
|
my %PARENT_LOADED_CACHE; |
|
13
|
|
|
|
|
|
|
my %ALL_ATTRIBUTES_CACHE; |
|
14
|
|
|
|
|
|
|
our %ATTRIBUTES; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub _generate_fast_accessor { |
|
17
|
80
|
|
|
80
|
|
124
|
my ($attr_name) = @_; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
return $ACCESSOR_CACHE{$attr_name} ||= sub { |
|
20
|
90
|
100
|
|
90
|
|
3223
|
$_[0]{$attr_name} = $_[1] if @_ > 1; |
|
21
|
90
|
|
|
|
|
323
|
return $_[0]{$attr_name}; |
|
22
|
80
|
|
66
|
|
|
702
|
}; |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub import { |
|
26
|
59
|
|
|
59
|
|
423
|
my ($class, @args) = @_; |
|
27
|
59
|
|
|
|
|
112
|
my $caller = caller; |
|
28
|
|
|
|
|
|
|
|
|
29
|
59
|
|
|
|
|
586
|
strict->import; |
|
30
|
59
|
|
|
|
|
1031
|
warnings->import; |
|
31
|
|
|
|
|
|
|
|
|
32
|
22
|
|
|
22
|
|
5067
|
no strict 'refs'; |
|
|
22
|
|
|
|
|
50
|
|
|
|
22
|
|
|
|
|
14620
|
|
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Install optimised new method |
|
35
|
59
|
|
|
|
|
121
|
*{"${caller}::new"} = _generate_optimised_constructor($caller); |
|
|
59
|
|
|
|
|
263
|
|
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# Install has method |
|
38
|
59
|
|
|
|
|
90
|
*{"${caller}::has"} = \&_has; |
|
|
59
|
|
|
|
|
154
|
|
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# Install extends method |
|
41
|
59
|
|
|
|
|
93
|
*{"${caller}::extends"} = \&_extends; |
|
|
59
|
|
|
|
|
195
|
|
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# Load Role.pm if available |
|
44
|
59
|
|
|
|
|
97
|
eval { require Role }; |
|
|
59
|
|
|
|
|
4932
|
|
|
45
|
59
|
50
|
|
|
|
160
|
if (!$@) { |
|
46
|
59
|
|
|
|
|
74
|
*{"${caller}::with"} = \&Role::with; |
|
|
59
|
|
|
|
|
218
|
|
|
47
|
59
|
|
|
|
|
70
|
*{"${caller}::does"} = \&Role::does; |
|
|
59
|
|
|
|
|
172
|
|
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
59
|
50
|
33
|
|
|
31535
|
if (@args && $args[0] eq 'extends') { |
|
51
|
0
|
|
|
|
|
0
|
_extends($caller, @args[1..$#args]); |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub _generate_optimised_constructor { |
|
56
|
59
|
|
|
59
|
|
83
|
my $class = shift; |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
return sub { |
|
59
|
58
|
|
|
58
|
|
8338
|
my $class = shift; |
|
60
|
58
|
|
|
|
|
110
|
my %args = @_; |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# Fast path: bless hashref directly for maximum speed |
|
63
|
58
|
|
|
|
|
99
|
my $self = bless {}, $class; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Get cached attributes |
|
66
|
58
|
|
|
|
|
110
|
my $class_attrs = _get_all_attributes_fast($class); |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# Ultra-fast path: no attributes, no BUILD methods |
|
69
|
58
|
100
|
|
|
|
120
|
unless (%$class_attrs) { |
|
70
|
3
|
|
33
|
|
|
11
|
my $build_methods = $BUILD_ORDER_CACHE{$class} ||= _compute_build_methods_fast($class); |
|
71
|
3
|
100
|
|
|
|
7
|
unless (@$build_methods) { |
|
72
|
|
|
|
|
|
|
# Absolute fastest path: just copy args and return |
|
73
|
2
|
|
|
|
|
7
|
%$self = %args; |
|
74
|
2
|
|
|
|
|
6
|
return $self; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# Make args copy for defaults |
|
79
|
56
|
|
|
|
|
102
|
my %args_copy = %args; |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Process attributes efficiently |
|
82
|
56
|
|
|
|
|
134
|
_process_attributes_ultra_fast($class, $self, \%args, \%args_copy, $class_attrs); |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Copy remaining args |
|
85
|
47
|
|
|
|
|
151
|
while (my ($key, $value) = each %args) { |
|
86
|
3
|
50
|
|
|
|
17
|
$self->{$key} = $value unless exists $self->{$key}; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# Call BUILD methods if any |
|
90
|
47
|
|
66
|
|
|
184
|
my $build_methods = $BUILD_ORDER_CACHE{$class} ||= _compute_build_methods_fast($class); |
|
91
|
47
|
100
|
|
|
|
75
|
if (@$build_methods) { |
|
92
|
3
|
|
|
|
|
14
|
$_->($self, \%args_copy) for @$build_methods; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
47
|
|
|
|
|
156
|
return $self; |
|
96
|
59
|
|
|
|
|
436
|
}; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub _process_attributes_ultra_fast { |
|
100
|
56
|
|
|
56
|
|
108
|
my ($class, $self, $args, $args_copy, $class_attrs) = @_; |
|
101
|
|
|
|
|
|
|
|
|
102
|
56
|
|
|
|
|
63
|
my @required_check; |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# PASS 1: Constructor values with minimal operations |
|
105
|
56
|
|
|
|
|
102
|
foreach my $attr_name (keys %$class_attrs) { |
|
106
|
133
|
|
|
|
|
144
|
my $spec = $class_attrs->{$attr_name}; |
|
107
|
|
|
|
|
|
|
|
|
108
|
133
|
100
|
|
|
|
180
|
if (exists $args->{$attr_name}) { |
|
109
|
35
|
|
|
|
|
95
|
$self->{$attr_name} = $args->{$attr_name}; |
|
110
|
35
|
|
|
|
|
42
|
delete $args->{$attr_name}; |
|
111
|
35
|
|
|
|
|
50
|
next; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
|
|
114
|
98
|
100
|
|
|
|
245
|
push @required_check, $attr_name if $spec->{required}; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# PASS 2: Defaults |
|
118
|
56
|
|
|
|
|
90
|
foreach my $attr_name (keys %$class_attrs) { |
|
119
|
133
|
100
|
|
|
|
324
|
next if exists $self->{$attr_name}; |
|
120
|
|
|
|
|
|
|
|
|
121
|
98
|
|
|
|
|
101
|
my $spec = $class_attrs->{$attr_name}; |
|
122
|
98
|
100
|
|
|
|
148
|
if (exists $spec->{default}) { |
|
123
|
78
|
|
|
|
|
85
|
my $default = $spec->{default}; |
|
124
|
78
|
100
|
|
|
|
214
|
$self->{$attr_name} = ref $default eq 'CODE' |
|
125
|
|
|
|
|
|
|
? $default->($self, $args_copy) |
|
126
|
|
|
|
|
|
|
: $default; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# PASS 3: Required attributes (only if any exist) |
|
131
|
56
|
100
|
|
|
|
134
|
if (@required_check) { |
|
132
|
10
|
|
|
|
|
16
|
foreach my $attr_name (@required_check) { |
|
133
|
11
|
100
|
|
|
|
31
|
unless (defined $self->{$attr_name}) { |
|
134
|
9
|
|
|
|
|
124
|
die "Required attribute '$attr_name' not provided for class $class"; |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub _get_all_attributes_fast { |
|
141
|
60
|
|
|
60
|
|
96
|
my ($class) = @_; |
|
142
|
|
|
|
|
|
|
|
|
143
|
60
|
100
|
|
|
|
142
|
return $ALL_ATTRIBUTES_CACHE{$class} if exists $ALL_ATTRIBUTES_CACHE{$class}; |
|
144
|
|
|
|
|
|
|
|
|
145
|
40
|
|
|
|
|
56
|
my %all_attrs; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# Current class |
|
148
|
40
|
100
|
|
|
|
93
|
if (my $current_attrs = $ATTRIBUTES{$class}) { |
|
149
|
35
|
|
|
|
|
102
|
%all_attrs = %$current_attrs; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Parents |
|
153
|
22
|
|
|
22
|
|
164
|
no strict 'refs'; |
|
|
22
|
|
|
|
|
30
|
|
|
|
22
|
|
|
|
|
3660
|
|
|
154
|
40
|
|
|
|
|
49
|
my @isa = @{"${class}::ISA"}; |
|
|
40
|
|
|
|
|
169
|
|
|
155
|
40
|
|
|
|
|
51
|
foreach my $parent (@isa) { |
|
156
|
23
|
50
|
33
|
|
|
145
|
next if $parent eq 'Class::More' || $parent eq 'UNIVERSAL'; |
|
157
|
23
|
100
|
|
|
|
102
|
if (my $parent_attrs = $ATTRIBUTES{$parent}) { |
|
158
|
10
|
|
|
|
|
48
|
%all_attrs = (%$parent_attrs, %all_attrs); |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
40
|
|
|
|
|
98
|
return $ALL_ATTRIBUTES_CACHE{$class} = \%all_attrs; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _compute_build_methods_fast { |
|
166
|
40
|
|
|
40
|
|
100
|
my ($class) = @_; |
|
167
|
|
|
|
|
|
|
|
|
168
|
40
|
|
|
|
|
81
|
my @inheritance_tree = _get_inheritance_tree_dfs($class); |
|
169
|
40
|
|
|
|
|
41
|
my @build_methods; |
|
170
|
|
|
|
|
|
|
|
|
171
|
40
|
|
|
|
|
48
|
foreach my $c (@inheritance_tree) { |
|
172
|
22
|
|
|
22
|
|
112
|
no strict 'refs'; |
|
|
22
|
|
|
|
|
35
|
|
|
|
22
|
|
|
|
|
2903
|
|
|
173
|
65
|
100
|
|
|
|
57
|
if (defined &{"${c}::BUILD"}) { |
|
|
65
|
|
|
|
|
228
|
|
|
174
|
6
|
|
|
|
|
5
|
push @build_methods, \&{"${c}::BUILD"}; |
|
|
6
|
|
|
|
|
12
|
|
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
40
|
|
|
|
|
98
|
return \@build_methods; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# Efficient DFS |
|
182
|
|
|
|
|
|
|
sub _get_inheritance_tree_dfs { |
|
183
|
65
|
|
|
65
|
|
86
|
my ($class, $visited) = @_; |
|
184
|
65
|
|
100
|
|
|
192
|
$visited ||= {}; |
|
185
|
|
|
|
|
|
|
|
|
186
|
65
|
50
|
33
|
|
|
201
|
return () if $visited->{$class} || !defined $class; |
|
187
|
65
|
|
|
|
|
99
|
$visited->{$class} = 1; |
|
188
|
|
|
|
|
|
|
|
|
189
|
65
|
|
|
|
|
104
|
my @order; |
|
190
|
|
|
|
|
|
|
|
|
191
|
22
|
|
|
22
|
|
105
|
no strict 'refs'; |
|
|
22
|
|
|
|
|
35
|
|
|
|
22
|
|
|
|
|
3728
|
|
|
192
|
65
|
|
|
|
|
85
|
my @isa = @{"${class}::ISA"}; |
|
|
65
|
|
|
|
|
173
|
|
|
193
|
|
|
|
|
|
|
|
|
194
|
65
|
|
|
|
|
84
|
foreach my $parent (@isa) { |
|
195
|
25
|
50
|
33
|
|
|
191
|
next if !defined $parent || $parent eq 'Class::More' || $parent eq 'UNIVERSAL' || $parent eq ''; |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
196
|
25
|
|
|
|
|
79
|
push @order, _get_inheritance_tree_dfs($parent, $visited); |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
|
|
199
|
65
|
|
|
|
|
89
|
push @order, $class; |
|
200
|
65
|
|
|
|
|
187
|
return @order; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub _has { |
|
204
|
80
|
|
|
80
|
|
1452137
|
my ($attr_name, %spec) = @_; |
|
205
|
80
|
|
|
|
|
163
|
my $current_class = caller; |
|
206
|
|
|
|
|
|
|
|
|
207
|
80
|
|
|
|
|
689
|
_clear_attributes_cache($current_class); |
|
208
|
|
|
|
|
|
|
|
|
209
|
80
|
100
|
|
|
|
204
|
$ATTRIBUTES{$current_class} = {} unless exists $ATTRIBUTES{$current_class}; |
|
210
|
80
|
|
|
|
|
213
|
$ATTRIBUTES{$current_class}{$attr_name} = \%spec; |
|
211
|
|
|
|
|
|
|
|
|
212
|
22
|
|
|
22
|
|
145
|
no strict 'refs'; |
|
|
22
|
|
|
|
|
48
|
|
|
|
22
|
|
|
|
|
4659
|
|
|
213
|
80
|
50
|
|
|
|
87
|
if (!defined &{"${current_class}::${attr_name}"}) { |
|
|
80
|
|
|
|
|
414
|
|
|
214
|
80
|
|
|
|
|
159
|
*{"${current_class}::${attr_name}"} = _generate_fast_accessor($attr_name); |
|
|
80
|
|
|
|
|
307
|
|
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub _extends { |
|
219
|
10
|
|
|
10
|
|
945
|
my $caller = caller; |
|
220
|
10
|
|
|
|
|
62
|
my @parents = @_; |
|
221
|
|
|
|
|
|
|
|
|
222
|
10
|
|
|
|
|
23
|
_delete_build_cache($caller); |
|
223
|
10
|
|
|
|
|
24
|
_clear_attributes_cache($caller); |
|
224
|
|
|
|
|
|
|
|
|
225
|
10
|
|
|
|
|
18
|
for my $parent_class (@parents) { |
|
226
|
12
|
50
|
|
|
|
27
|
die "Recursive inheritance detected: $caller cannot extend itself" |
|
227
|
|
|
|
|
|
|
if $caller eq $parent_class; |
|
228
|
|
|
|
|
|
|
|
|
229
|
12
|
50
|
|
|
|
29
|
unless ($PARENT_LOADED_CACHE{$parent_class}) { |
|
230
|
12
|
|
|
|
|
18
|
my $parent_file = "$parent_class.pm"; |
|
231
|
12
|
|
|
|
|
41
|
$parent_file =~ s{::}{/}g; |
|
232
|
|
|
|
|
|
|
|
|
233
|
12
|
50
|
|
|
|
33
|
unless ($INC{$parent_file}) { |
|
234
|
12
|
|
|
|
|
14
|
eval { require $parent_file }; |
|
|
12
|
|
|
|
|
4979
|
|
|
235
|
|
|
|
|
|
|
} |
|
236
|
12
|
|
|
|
|
42
|
$PARENT_LOADED_CACHE{$parent_class} = 1; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
22
|
|
|
22
|
|
111
|
no strict 'refs'; |
|
|
22
|
|
|
|
|
37
|
|
|
|
22
|
|
|
|
|
5235
|
|
|
240
|
12
|
50
|
|
|
|
14
|
unless (grep { $_ eq $parent_class } @{"${caller}::ISA"}) { |
|
|
2
|
|
|
|
|
6
|
|
|
|
12
|
|
|
|
|
83
|
|
|
241
|
12
|
|
|
|
|
15
|
push @{"${caller}::ISA"}, $parent_class; |
|
|
12
|
|
|
|
|
120
|
|
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub _delete_build_cache { |
|
247
|
10
|
|
|
10
|
|
16
|
my ($class) = @_; |
|
248
|
10
|
|
|
|
|
14
|
delete $BUILD_ORDER_CACHE{$class}; |
|
249
|
10
|
|
|
|
|
23
|
for my $cached_class (keys %BUILD_ORDER_CACHE) { |
|
250
|
30
|
50
|
|
|
|
35
|
if (_inherits_from_fast($cached_class, $class)) { |
|
251
|
0
|
|
|
|
|
0
|
delete $BUILD_ORDER_CACHE{$cached_class}; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
} |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub _inherits_from_fast { |
|
257
|
399
|
|
|
399
|
|
351
|
my ($class, $parent) = @_; |
|
258
|
22
|
|
|
22
|
|
130
|
no strict 'refs'; |
|
|
22
|
|
|
|
|
34
|
|
|
|
22
|
|
|
|
|
7528
|
|
|
259
|
399
|
|
|
|
|
278
|
my @isa = @{"${class}::ISA"}; |
|
|
399
|
|
|
|
|
684
|
|
|
260
|
399
|
50
|
|
|
|
413
|
return 1 if grep { $_ eq $parent } @isa; |
|
|
99
|
|
|
|
|
174
|
|
|
261
|
399
|
|
|
|
|
318
|
foreach my $direct_parent (@isa) { |
|
262
|
99
|
50
|
|
|
|
104
|
return 1 if _inherits_from_fast($direct_parent, $parent); |
|
263
|
|
|
|
|
|
|
} |
|
264
|
399
|
|
|
|
|
590
|
return 0; |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub _clear_attributes_cache { |
|
268
|
90
|
|
|
90
|
|
109
|
my ($class) = @_; |
|
269
|
90
|
|
|
|
|
101
|
delete $ALL_ATTRIBUTES_CACHE{$class}; |
|
270
|
90
|
|
|
|
|
191
|
for my $cached_class (keys %ALL_ATTRIBUTES_CACHE) { |
|
271
|
270
|
50
|
|
|
|
270
|
if (_inherits_from_fast($cached_class, $class)) { |
|
272
|
0
|
|
|
|
|
0
|
delete $ALL_ATTRIBUTES_CACHE{$cached_class}; |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
|
|
277
|
0
|
|
|
0
|
1
|
0
|
sub can_handle_attributes { 1 } |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub meta { |
|
280
|
0
|
|
|
0
|
1
|
0
|
my $class = shift; |
|
281
|
|
|
|
|
|
|
return { |
|
282
|
|
|
|
|
|
|
can_handle_attributes => 1, |
|
283
|
0
|
|
0
|
|
|
0
|
attributes => $ATTRIBUTES{$class} || {}, |
|
284
|
|
|
|
|
|
|
}; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub get_all_attributes { |
|
288
|
0
|
|
|
0
|
0
|
0
|
my ($class) = @_; |
|
289
|
0
|
|
|
|
|
0
|
return _get_all_attributes_fast($class); |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub _get_all_attributes { |
|
293
|
2
|
|
|
2
|
|
56
|
my ($class) = @_; |
|
294
|
2
|
|
|
|
|
4
|
return _get_all_attributes_fast($class); |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=head1 NAME |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
Class::More - A fast, lightweight class builder for Perl |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head1 VERSION |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
Version v0.1.1 |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
package My::Class; |
|
308
|
|
|
|
|
|
|
use Class::More; |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# Define attributes |
|
311
|
|
|
|
|
|
|
has 'name' => ( required => 1 ); |
|
312
|
|
|
|
|
|
|
has 'age' => ( default => 0 ); |
|
313
|
|
|
|
|
|
|
has 'tags' => ( default => sub { [] } ); |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# Set up inheritance |
|
316
|
|
|
|
|
|
|
extends 'My::Parent'; |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Custom constructor logic |
|
319
|
|
|
|
|
|
|
sub BUILD { |
|
320
|
|
|
|
|
|
|
my ($self, $args) = @_; |
|
321
|
|
|
|
|
|
|
$self->{initialized} = time; |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub greet { |
|
325
|
|
|
|
|
|
|
my $self = shift; |
|
326
|
|
|
|
|
|
|
return "Hello, " . $self->name; |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
1; |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
# Usage |
|
332
|
|
|
|
|
|
|
my $obj = My::Class->new( |
|
333
|
|
|
|
|
|
|
name => 'Alice', |
|
334
|
|
|
|
|
|
|
age => 30 |
|
335
|
|
|
|
|
|
|
); |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
print $obj->name; # Alice |
|
338
|
|
|
|
|
|
|
print $obj->age; # 30 |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Class::More provides a fast, lightweight class building system for Perl with |
|
343
|
|
|
|
|
|
|
attribute support, inheritance, and constructor building. It's designed for |
|
344
|
|
|
|
|
|
|
performance and simplicity while providing essential object-oriented features. |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
The module focuses on speed with optimized method generation, caching, and |
|
347
|
|
|
|
|
|
|
minimal runtime overhead. |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=head1 FEATURES |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=head2 Core Features |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=over 4 |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=item * B: Simple attributes with required flags and defaults |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=item * B: Automatically generates getter/setter methods |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=item * B: Multiple inheritance with proper method resolution |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=item * B: Constructor-time initialisation hooks |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=item * B: Extensive caching and optimised code paths |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=item * B: Works seamlessly with L when available |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=back |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head2 Performance Features |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=over 4 |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=item * Pre-generated accessors for maximum speed |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=item * Method resolution order caching |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=item * Attribute specification caching |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=item * Fast inheritance checks |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=item * Batch accessor installation |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=back |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head1 METHODS |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=head2 Class Definition Methods |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
These methods are exported to your class when you C |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head3 has |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
has 'attribute_name'; |
|
394
|
|
|
|
|
|
|
has 'count' => ( default => 0 ); |
|
395
|
|
|
|
|
|
|
has 'items' => ( default => sub { [] } ); |
|
396
|
|
|
|
|
|
|
has 'name' => ( required => 1 ); |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
Defines an attribute in your class. Creates an accessor method that can get |
|
399
|
|
|
|
|
|
|
and set the attribute value. |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
Supported options: |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=over 4 |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=item * C - Default value or code reference that returns default value |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=item * C - Boolean indicating if attribute must be provided to constructor |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=back |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=head3 extends |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
extends 'Parent::Class'; |
|
414
|
|
|
|
|
|
|
extends 'Parent1', 'Parent2'; |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
Sets up inheritance for your class. Can specify multiple parents for multiple |
|
417
|
|
|
|
|
|
|
inheritance. Automatically loads parent classes if needed. |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head3 new |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
my $obj = My::Class->new(%attributes); |
|
422
|
|
|
|
|
|
|
my $obj = My::Class->new( name => 'test', count => 42 ); |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
The constructor method. Automatically provided by Class::More. Handles: |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=over 4 |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=item * Attribute initialisation with defaults |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=item * Required attribute validation |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=item * BUILD method calling in proper inheritance order |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=back |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=head2 Special Methods |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head3 BUILD |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub BUILD { |
|
441
|
|
|
|
|
|
|
my ($self, $args) = @_; |
|
442
|
|
|
|
|
|
|
# Custom initialization logic |
|
443
|
|
|
|
|
|
|
$self->{internal_field} = process($args->{external_field}); |
|
444
|
|
|
|
|
|
|
} |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
Optional method called after object construction but before returning from C. |
|
447
|
|
|
|
|
|
|
Receives the object and the hashref of constructor arguments. |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
BUILD methods are called in inheritance order (parent classes first). |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=head3 meta |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
my $meta = My::Class->meta; |
|
454
|
|
|
|
|
|
|
print $meta->{can_handle_attributes}; # 1 |
|
455
|
|
|
|
|
|
|
print keys %{$meta->{attributes}}; # name, age, tags |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Returns metadata about the class. Currently provides: |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=over 4 |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=item * C - Always true |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=item * C - Hashref of attribute specifications |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=back |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=head1 ATTRIBUTE SYSTEM |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=head2 Basic Usage |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
package User; |
|
472
|
|
|
|
|
|
|
use Class::More; |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
has 'username' => ( required => 1 ); |
|
475
|
|
|
|
|
|
|
has 'email' => ( required => 1 ); |
|
476
|
|
|
|
|
|
|
has 'status' => ( default => 'active' ); |
|
477
|
|
|
|
|
|
|
has 'created' => ( default => sub { time } ); |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
Attributes defined with C automatically get accessor methods: |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
my $user = User->new( |
|
482
|
|
|
|
|
|
|
username => 'alice', |
|
483
|
|
|
|
|
|
|
email => 'alice@example.com' |
|
484
|
|
|
|
|
|
|
); |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
# Getter |
|
487
|
|
|
|
|
|
|
print $user->username; # alice |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
# Setter |
|
490
|
|
|
|
|
|
|
$user->status('inactive'); |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head2 Required Attributes |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
has 'critical_data' => ( required => 1 ); |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
If a required attribute is not provided to the constructor, an exception is thrown: |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# Dies: "Required attribute 'critical_data' not provided for class User" |
|
499
|
|
|
|
|
|
|
User->new( username => 'test' ); |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=head2 Default Values |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
has 'counter' => ( default => 0 ); |
|
504
|
|
|
|
|
|
|
has 'list' => ( default => sub { [] } ); |
|
505
|
|
|
|
|
|
|
has 'complex' => ( default => sub { |
|
506
|
|
|
|
|
|
|
return { computed => time } |
|
507
|
|
|
|
|
|
|
}); |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
Defaults can be simple values or code references. Code references are executed |
|
510
|
|
|
|
|
|
|
at construction time and receive the object and constructor arguments. |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=head2 Inheritance and Attributes |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
package Parent; |
|
515
|
|
|
|
|
|
|
use Class::More; |
|
516
|
|
|
|
|
|
|
has 'parent_attr' => ( default => 'from_parent' ); |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
package Child; |
|
519
|
|
|
|
|
|
|
use Class::More; |
|
520
|
|
|
|
|
|
|
extends 'Parent'; |
|
521
|
|
|
|
|
|
|
has 'child_attr' => ( default => 'from_child' ); |
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
Child classes inherit parent attributes. If both parent and child define the |
|
524
|
|
|
|
|
|
|
same attribute, the child's specification takes precedence. |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=head1 PERFORMANCE OPTIMISATIONS |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
Class::More includes several performance optimisations: |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=over 4 |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=item * B: Simple accessors are pre-compiled and reused |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=item * B: Combined attribute specifications are cached per class |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=item * B: BUILD method call order is computed once per class |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
=item * B: Optimised inheritance tree traversal |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=item * B: Multiple accessors installed in batch when possible |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=back |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=head1 EXAMPLES |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=head2 Simple Class |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
package Person; |
|
549
|
|
|
|
|
|
|
use Class::More; |
|
550
|
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
has 'name' => ( required => 1 ); |
|
552
|
|
|
|
|
|
|
has 'age' => ( default => 0 ); |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
sub introduce { |
|
555
|
|
|
|
|
|
|
my $self = shift; |
|
556
|
|
|
|
|
|
|
return "I'm " . $self->name . ", age " . $self->age; |
|
557
|
|
|
|
|
|
|
} |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
1; |
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=head2 Class with Inheritance |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
package Animal; |
|
564
|
|
|
|
|
|
|
use Class::More; |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
has 'species' => ( required => 1 ); |
|
567
|
|
|
|
|
|
|
has 'sound' => ( required => 1 ); |
|
568
|
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
sub speak { |
|
570
|
|
|
|
|
|
|
my $self = shift; |
|
571
|
|
|
|
|
|
|
return $self->sound; |
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
package Dog; |
|
575
|
|
|
|
|
|
|
use Class::More; |
|
576
|
|
|
|
|
|
|
extends 'Animal'; |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
sub BUILD { |
|
579
|
|
|
|
|
|
|
my ($self, $args) = @_; |
|
580
|
|
|
|
|
|
|
$self->{species} = 'Canine' unless $args->{species}; |
|
581
|
|
|
|
|
|
|
$self->{sound} = 'Woof!' unless $args->{sound}; |
|
582
|
|
|
|
|
|
|
} |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
sub fetch { |
|
585
|
|
|
|
|
|
|
my $self = shift; |
|
586
|
|
|
|
|
|
|
return $self->name . " fetches the ball!"; |
|
587
|
|
|
|
|
|
|
} |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=head2 Class with Complex Attributes |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
package Configuration; |
|
592
|
|
|
|
|
|
|
use Class::More; |
|
593
|
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
has 'settings' => ( default => sub { {} } ); |
|
595
|
|
|
|
|
|
|
has 'counters' => ( default => sub { { success => 0, failure => 0 } } ); |
|
596
|
|
|
|
|
|
|
has 'log_file' => ( required => 1 ); |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
sub BUILD { |
|
599
|
|
|
|
|
|
|
my ($self, $args) = @_; |
|
600
|
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
# Initialize complex data structures |
|
602
|
|
|
|
|
|
|
$self->{internal_cache} = {}; |
|
603
|
|
|
|
|
|
|
$self->{start_time} = time; |
|
604
|
|
|
|
|
|
|
} |
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
sub increment { |
|
607
|
|
|
|
|
|
|
my ($self, $counter) = @_; |
|
608
|
|
|
|
|
|
|
$self->counters->{$counter}++; |
|
609
|
|
|
|
|
|
|
} |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
=head1 INTEGRATION WITH Role |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
When L is available, Class::More automatically exports: |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=head3 with |
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
package My::Class; |
|
618
|
|
|
|
|
|
|
use Class::More; |
|
619
|
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
with 'Role::Printable', 'Role::Serialisable'; |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
Composes roles into your class. See L for complete documentation. |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head3 does |
|
625
|
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
if ($obj->does('Role::Printable')) { |
|
627
|
|
|
|
|
|
|
$obj->print; |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
Checks if an object consumes a specific role. |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head1 LIMITATIONS |
|
633
|
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
=head2 Attribute System Limitations |
|
635
|
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
=over 4 |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=item * B: Attributes don't support type checking |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
=item * B: All attributes are readable and writable |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
=item * B: No automatic value transformation |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=item * B: No callbacks when attributes change |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
=item * B: Defaults are applied immediately at construction |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
=item * B: All attributes are publicly accessible via accessors |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=back |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=head2 Inheritance Limitations |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=over 4 |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=item * B: No compile-time method requirement checking |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
=item * B: Basic metadata only |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
=item * B: No trait-based composition |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=item * B: Multiple inheritance may have ambiguous method resolution |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=back |
|
665
|
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=head2 General Limitations |
|
667
|
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=over 4 |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=item * B: Can't make classes immutable for performance |
|
671
|
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=item * B: No built-in serialisation/deserialisation |
|
673
|
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=item * B: No ORM-like features |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=item * B: No custom exception classes |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=back |
|
679
|
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=head2 Compatibility Notes |
|
681
|
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=over 4 |
|
683
|
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=item * Designed for simplicity and speed over feature completeness |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=item * Uses standard Perl OO internals (blessed hashrefs) |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=item * Compatible with most CPAN modules that expect blessed hashrefs |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
=item * Not compatible with Moose/Mouse object systems |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=item * Role integration requires separate L module |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=back |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=head1 DIAGNOSTICS |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
=head2 Common Errors |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=over 4 |
|
701
|
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=item * C<"Required attribute 'attribute_name' not provided for class Class::Name"> |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
A required attribute was not passed to the constructor. |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=item * C<"Recursive inheritance detected: ClassA cannot extend itself"> |
|
707
|
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
A class tries to inherit from itself, directly or indirectly. |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=item * C<"Invalid attribute option 'option_name' for 'attribute_name' in Class::Name"> |
|
711
|
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
An unsupported attribute option was used. |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=item * C<"Can't locate Parent/Class.pm in @INC"> |
|
715
|
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
A parent class specified in C couldn't be loaded. |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=back |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=head2 Performance Tips |
|
721
|
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=over 4 |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=item * Use simple defaults when possible (avoid sub refs for static values) |
|
725
|
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=item * Define all attributes before calling C for optimal caching |
|
727
|
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
=item * Keep BUILD methods lightweight |
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=item * Use the provided C method rather than overriding it |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
=back |
|
733
|
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
735
|
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
=over 4 |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
=item * L - Companion role system for Class::More |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=item * L - Lightweight Moose-like OO system |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=item * L - Minimalistic base class for Mojolicious |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
=item * L - Extremely lightweight class builder |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=item * L - Simple class builder with accessors |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=item * L - Full-featured object system |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=back |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=head1 AUTHOR |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
Mohammad Sajid Anwar, C<< >> |
|
755
|
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=head1 REPOSITORY |
|
757
|
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
L |
|
759
|
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
=head1 BUGS |
|
761
|
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
Please report any bugs or feature requests through the web interface at L. |
|
763
|
|
|
|
|
|
|
I will be notified and then you'll automatically be notified of progress on your bug as I make changes. |
|
764
|
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
=head1 SUPPORT |
|
766
|
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
|
768
|
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
perldoc Class::More |
|
770
|
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
You can also look for information at: |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=over 4 |
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
=item * BUG Report |
|
776
|
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
L |
|
778
|
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
=back |
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
782
|
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
Copyright (C) 2025 Mohammad Sajid Anwar. |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
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: |
|
786
|
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
L |
|
788
|
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
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. |
|
790
|
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
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. |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. |
|
794
|
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
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. |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
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. |
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
=cut |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
1; # End of Class::More |