line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Fukurama::Class::Abstract; |
2
|
4
|
|
|
4
|
|
23440
|
use Fukurama::Class::Version(0.01); |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
31
|
|
3
|
4
|
|
|
4
|
|
24
|
use Fukurama::Class::Rigid; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
22
|
|
4
|
4
|
|
|
4
|
|
27
|
use Fukurama::Class::Carp; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
48
|
|
5
|
4
|
|
|
4
|
|
665
|
use Fukurama::Class::Tree(); |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
1381
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
my $CLASS = {}; |
8
|
|
|
|
|
|
|
my $DECORATED_SUBS = {}; |
9
|
|
|
|
|
|
|
our $DISABLE = 0; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Fukurama::Class::Abstract - Pragma to provide abstract classes |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 VERSION |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Version 0.01 (beta) |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
package MyClass; |
22
|
|
|
|
|
|
|
use Fukurama::Class::Abstract; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 DESCRIPTION |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
This pragma-like module provides functions to check the usage of all class-methods. All calls from childs, |
27
|
|
|
|
|
|
|
which inherits from this class are ok, all other will croak at runtime. |
28
|
|
|
|
|
|
|
Use Fukurama::Class instead, to get all the features for OO. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 CONFIG |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
You can disable the whole behavior of this class by setting |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
$Fukurama::Class::Abstract::DISABLE = 1; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 EXPORT |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
All methods of your abstract class would be decorated with a caller-check method. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 METHODS |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=over 4 |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item abstract( abstract_class:STRING ) return:VOID |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Set the given class as abstract. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=item run_check( ) return:VOID |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
Helper method for static perl (see Fukurama::Class > BUGS) |
51
|
|
|
|
|
|
|
This method decorates all non-special subroutines in the registered, abstract classes |
52
|
|
|
|
|
|
|
that all calls would be checked. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=back |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 AUTHOR, BUGS, SUPPORT, ACKNOWLEDGEMENTS, COPYRIGHT & LICENSE |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
see perldoc of L |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=cut |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# AUTOMAGIC void |
63
|
|
|
|
|
|
|
sub import { |
64
|
1
|
|
|
1
|
|
11
|
my $class = $_[0]; |
65
|
|
|
|
|
|
|
|
66
|
1
|
|
|
|
|
5
|
my ($caller_class) = caller(0); |
67
|
1
|
|
|
|
|
4
|
$class->abstract($caller_class); |
68
|
1
|
|
|
|
|
124
|
return undef; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
# STATIC void |
71
|
|
|
|
|
|
|
sub abstract { |
72
|
3
|
|
|
3
|
1
|
7
|
my $class = $_[0]; |
73
|
3
|
|
|
|
|
7
|
my $caller_class = $_[1]; |
74
|
|
|
|
|
|
|
|
75
|
3
|
|
|
|
|
9
|
$CLASS->{$caller_class} = undef; |
76
|
3
|
|
|
|
|
9
|
return 1; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
# STATIC void |
79
|
|
|
|
|
|
|
sub run_check { |
80
|
5
|
|
|
5
|
1
|
17
|
my $class = $_[0]; |
81
|
|
|
|
|
|
|
|
82
|
5
|
50
|
|
|
|
25
|
return if($DISABLE); |
83
|
5
|
|
|
|
|
20
|
foreach my $obj_class (keys(%$CLASS)) { |
84
|
4
|
|
|
|
|
7
|
foreach my $identifier (@{$class->_get_subs($obj_class)}) { |
|
4
|
|
|
|
|
17
|
|
85
|
10
|
|
|
|
|
33
|
$class->_decorate_sub($obj_class, $identifier); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
} |
88
|
5
|
|
|
|
|
62
|
return; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
# STATIC void |
91
|
|
|
|
|
|
|
sub _decorate_sub { |
92
|
10
|
|
|
10
|
|
17
|
my $class = $_[0]; |
93
|
10
|
|
|
|
|
14
|
my $obj_class = $_[1]; |
94
|
10
|
|
|
|
|
15
|
my $identifier = $_[2]; |
95
|
|
|
|
|
|
|
|
96
|
10
|
100
|
|
|
|
34
|
return if(exists($DECORATED_SUBS->{$identifier})); |
97
|
9
|
|
|
|
|
63
|
my ($subname) = $identifier =~ m/([^:]+)$/; |
98
|
9
|
100
|
|
|
|
40
|
return if(Fukurama::Class::Tree->is_special_sub($subname)); |
99
|
|
|
|
|
|
|
|
100
|
4
|
|
|
4
|
|
27
|
no strict 'refs'; |
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
147
|
|
101
|
4
|
|
|
4
|
|
20
|
no warnings 'redefine'; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
1083
|
|
102
|
|
|
|
|
|
|
|
103
|
5
|
|
|
|
|
8
|
my $old = *{$identifier}{CODE}; |
|
5
|
|
|
|
|
17
|
|
104
|
5
|
|
|
|
|
28
|
*{$identifier} = sub { |
105
|
10
|
|
33
|
10
|
|
4955
|
my $used_obj = ref($_[0]) || $_[0]; |
106
|
|
|
|
|
|
|
|
107
|
10
|
100
|
100
|
|
|
171
|
if(!$used_obj || $used_obj eq $obj_class || !UNIVERSAL::isa($used_obj, $obj_class)) { |
|
|
|
66
|
|
|
|
|
108
|
6
|
|
|
|
|
29
|
$class->_throw_error($used_obj, $obj_class, $identifier); |
109
|
|
|
|
|
|
|
} |
110
|
4
|
|
|
|
|
20
|
goto $old; |
111
|
5
|
|
|
|
|
47
|
}; |
112
|
|
|
|
|
|
|
|
113
|
5
|
|
|
|
|
17
|
$DECORATED_SUBS->{$identifier} = undef; |
114
|
5
|
|
|
|
|
15
|
return; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
# STATIC void |
117
|
|
|
|
|
|
|
sub _throw_error { |
118
|
6
|
|
|
6
|
|
11
|
my $class = $_[0]; |
119
|
6
|
|
|
|
|
11
|
my $obj_class = $_[1]; |
120
|
6
|
|
|
|
|
10
|
my $caller_class = $_[2]; |
121
|
6
|
|
|
|
|
11
|
my $identifier = $_[3]; |
122
|
|
|
|
|
|
|
|
123
|
6
|
100
|
|
|
|
19
|
$obj_class = '' if(!defined($obj_class)); |
124
|
6
|
|
|
|
|
44
|
_croak("Abstract class '$obj_class' used in class '$caller_class'. Sub '$identifier' called.", 2); |
125
|
0
|
|
|
|
|
0
|
return; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
# STATIC array |
128
|
|
|
|
|
|
|
sub _get_subs { |
129
|
4
|
|
|
4
|
|
10
|
my $class = $_[0]; |
130
|
4
|
|
|
|
|
7
|
my $obj_class = $_[1]; |
131
|
|
|
|
|
|
|
|
132
|
4
|
|
|
4
|
|
24
|
no strict 'refs'; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
390
|
|
133
|
|
|
|
|
|
|
|
134
|
4
|
|
|
|
|
8
|
my $subs = []; |
135
|
4
|
|
|
|
|
8
|
foreach my $name (%{$obj_class . '::'}) { |
|
4
|
|
|
|
|
22
|
|
136
|
46
|
|
|
|
|
120
|
my $identifier = $obj_class . '::' . $name; |
137
|
46
|
100
|
|
|
|
65
|
next if(!*{$identifier}{'CODE'}); |
|
46
|
|
|
|
|
245
|
|
138
|
10
|
|
|
|
|
28
|
push(@$subs, $identifier); |
139
|
|
|
|
|
|
|
} |
140
|
4
|
|
|
|
|
16
|
return $subs; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
4
|
|
|
4
|
|
21
|
no warnings 'void'; # avoid 'Too late to run CHECK/INIT block' |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
249
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# AUTOMAGIC void |
146
|
|
|
|
|
|
|
CHECK { |
147
|
4
|
|
|
4
|
|
1015
|
__PACKAGE__->run_check(); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
1; |