| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package MooseX::amine; |
|
2
|
|
|
|
|
|
|
# ABSTRACT: Examine Yr Moose |
|
3
|
|
|
|
|
|
|
$MooseX::amine::VERSION = '0.7'; |
|
4
|
14
|
|
|
14
|
|
954313
|
use Moose; |
|
|
14
|
|
|
|
|
6295036
|
|
|
|
14
|
|
|
|
|
98
|
|
|
5
|
14
|
|
|
14
|
|
97211
|
use Moose::Meta::Class; |
|
|
14
|
|
|
|
|
30
|
|
|
|
14
|
|
|
|
|
321
|
|
|
6
|
14
|
|
|
14
|
|
71
|
use Moose::Meta::Role; |
|
|
14
|
|
|
|
|
26
|
|
|
|
14
|
|
|
|
|
431
|
|
|
7
|
14
|
|
|
14
|
|
84
|
use Moose::Util::TypeConstraints; |
|
|
14
|
|
|
|
|
27
|
|
|
|
14
|
|
|
|
|
146
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
14
|
|
|
14
|
|
29097
|
use 5.010; |
|
|
14
|
|
|
|
|
47
|
|
|
10
|
14
|
|
|
14
|
|
9038
|
use autodie qw(open close); |
|
|
14
|
|
|
|
|
213200
|
|
|
|
14
|
|
|
|
|
74
|
|
|
11
|
14
|
|
|
14
|
|
14340
|
use PPI; |
|
|
14
|
|
|
|
|
1450723
|
|
|
|
14
|
|
|
|
|
655
|
|
|
12
|
14
|
|
|
14
|
|
6202
|
use Test::Deep::NoTest qw/eq_deeply/; |
|
|
14
|
|
|
|
|
123024
|
|
|
|
14
|
|
|
|
|
110
|
|
|
13
|
14
|
|
|
14
|
|
2853
|
use Try::Tiny; |
|
|
14
|
|
|
|
|
34
|
|
|
|
14
|
|
|
|
|
32572
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
has 'include_accessors_in_method_list' => ( |
|
17
|
|
|
|
|
|
|
is => 'ro' , |
|
18
|
|
|
|
|
|
|
isa => 'Bool' , |
|
19
|
|
|
|
|
|
|
default => 0 , |
|
20
|
|
|
|
|
|
|
); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
has 'include_moose_in_isa' => ( |
|
23
|
|
|
|
|
|
|
is => 'ro' , |
|
24
|
|
|
|
|
|
|
isa => 'Bool' , |
|
25
|
|
|
|
|
|
|
default => 0 , |
|
26
|
|
|
|
|
|
|
); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
has 'include_private_attributes' => => ( |
|
29
|
|
|
|
|
|
|
is => 'ro' , |
|
30
|
|
|
|
|
|
|
isa => 'Bool' , |
|
31
|
|
|
|
|
|
|
default => 0 , |
|
32
|
|
|
|
|
|
|
); |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
has 'include_private_methods' => => ( |
|
35
|
|
|
|
|
|
|
is => 'ro' , |
|
36
|
|
|
|
|
|
|
isa => 'Bool' , |
|
37
|
|
|
|
|
|
|
default => 0 , |
|
38
|
|
|
|
|
|
|
); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
has 'include_standard_methods' => ( |
|
41
|
|
|
|
|
|
|
is => 'ro' , |
|
42
|
|
|
|
|
|
|
isa => 'Bool' , |
|
43
|
|
|
|
|
|
|
default => 0 , |
|
44
|
|
|
|
|
|
|
); |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
has 'module' => ( is => 'ro' , isa => 'Str' ); |
|
47
|
|
|
|
|
|
|
has 'path' => ( is => 'ro' , isa => 'Str' ); |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
has '_attributes' => ( |
|
50
|
|
|
|
|
|
|
is => 'ro' , |
|
51
|
|
|
|
|
|
|
isa => 'HashRef' , |
|
52
|
|
|
|
|
|
|
traits => [ 'Hash' ] , |
|
53
|
|
|
|
|
|
|
handles => { |
|
54
|
|
|
|
|
|
|
_get_attribute => 'get' , |
|
55
|
|
|
|
|
|
|
_store_attribute => 'set' , |
|
56
|
|
|
|
|
|
|
_check_for_stored_attribute => 'exists' , |
|
57
|
|
|
|
|
|
|
}, |
|
58
|
|
|
|
|
|
|
); |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
has '_exclusions' => ( |
|
61
|
|
|
|
|
|
|
is => 'ro' , |
|
62
|
|
|
|
|
|
|
isa => 'HashRef' , |
|
63
|
|
|
|
|
|
|
handles => { |
|
64
|
51
|
|
|
51
|
|
117
|
_add_exclusion => sub { my( $self , $ex ) = @_; $self->{_exclusions}{$ex}++ } , |
|
|
51
|
|
|
|
|
173
|
|
|
65
|
143
|
|
|
143
|
|
249
|
_check_exclusion => sub { my( $self , $ex ) = @_; return $self->{_exclusions}{$ex} } , |
|
|
143
|
|
|
|
|
430
|
|
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
); |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
has '_metaobj' => ( |
|
70
|
|
|
|
|
|
|
is => 'ro' , |
|
71
|
|
|
|
|
|
|
isa => 'Object' , |
|
72
|
|
|
|
|
|
|
lazy => 1 , |
|
73
|
|
|
|
|
|
|
builder => '_build_metaobj' , |
|
74
|
|
|
|
|
|
|
); |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _build_metaobj { |
|
77
|
14
|
|
|
14
|
|
29
|
my $self = shift; |
|
78
|
|
|
|
|
|
|
return $self->{module}->meta |
|
79
|
14
|
|
50
|
|
|
85
|
|| die "Can't get meta object for module!" ; |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
has '_methods' => ( |
|
83
|
|
|
|
|
|
|
is => 'ro' , |
|
84
|
|
|
|
|
|
|
isa => 'HashRef' , |
|
85
|
|
|
|
|
|
|
traits => [ 'Hash' ] , |
|
86
|
|
|
|
|
|
|
handles => { |
|
87
|
|
|
|
|
|
|
_store_method => 'set' , |
|
88
|
|
|
|
|
|
|
}, |
|
89
|
|
|
|
|
|
|
); |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
has '_sub_nodes' => ( |
|
92
|
|
|
|
|
|
|
is => 'ro' , |
|
93
|
|
|
|
|
|
|
isa => 'HashRef' , |
|
94
|
|
|
|
|
|
|
traits => [ 'Hash' ] , |
|
95
|
|
|
|
|
|
|
handles => { |
|
96
|
|
|
|
|
|
|
_get_sub_node => 'get' , |
|
97
|
|
|
|
|
|
|
_store_sub_node => 'set' , |
|
98
|
|
|
|
|
|
|
}, |
|
99
|
|
|
|
|
|
|
); |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub BUILDARGS { |
|
102
|
18
|
|
|
18
|
1
|
18133
|
my $class = shift; |
|
103
|
|
|
|
|
|
|
|
|
104
|
18
|
|
|
|
|
81
|
my $args = _convert_to_hashref_if_needed( @_ ); |
|
105
|
|
|
|
|
|
|
|
|
106
|
18
|
100
|
|
|
|
77
|
if ( $args->{module}) { |
|
|
|
100
|
|
|
|
|
|
|
107
|
13
|
|
|
|
|
886
|
eval "require $args->{module};"; |
|
108
|
13
|
100
|
|
|
|
647015
|
die $@ if $@; |
|
109
|
|
|
|
|
|
|
|
|
110
|
12
|
|
|
|
|
65
|
my $path = $args->{module} . '.pm'; |
|
111
|
12
|
|
|
|
|
65
|
$path =~ s|::|/|g; |
|
112
|
12
|
|
|
|
|
57
|
$args->{path} = $INC{$path}; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
elsif ( $args->{path} ) { |
|
115
|
4
|
|
|
|
|
32
|
open( my $IN , '<' , $args->{path} ); |
|
116
|
3
|
|
|
|
|
2440
|
while (<$IN>) { |
|
117
|
4
|
100
|
|
|
|
33
|
if ( /^package ([^;]+);/ ) { |
|
118
|
3
|
|
|
|
|
14
|
my $module = $1; |
|
119
|
3
|
|
|
|
|
12
|
$args->{module} = _load_module_from_path( $module , $args->{path} ); |
|
120
|
2
|
|
|
|
|
6
|
last; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
} |
|
123
|
2
|
|
|
|
|
9
|
close( $IN ); |
|
124
|
|
|
|
|
|
|
} |
|
125
|
1
|
|
|
|
|
10
|
else { die "Need to provide 'module' or 'path'" } |
|
126
|
14
|
|
|
|
|
1327
|
return $args; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub examine { |
|
131
|
14
|
|
|
14
|
1
|
56667
|
my $self = shift; |
|
132
|
14
|
|
|
|
|
454
|
my $meta = $self->_metaobj; |
|
133
|
|
|
|
|
|
|
|
|
134
|
14
|
100
|
|
|
|
98
|
if ( $meta->isa( 'Moose::Meta::Role' )) { |
|
135
|
1
|
|
|
|
|
3
|
$self->_dissect_role( $meta ); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
else { |
|
138
|
13
|
|
|
|
|
61
|
foreach my $class ( reverse $meta->linearized_isa ) { |
|
139
|
33
|
100
|
|
|
|
9631
|
if ( $class =~ /^Moose::/) { |
|
140
|
13
|
100
|
|
|
|
430
|
next unless $self->include_moose_in_isa; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
21
|
|
|
|
|
102
|
$self->_dissect_class( $class ); |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# Now that we've dissected everything, load the extracted sub nodes into the |
|
147
|
|
|
|
|
|
|
# appropriate methods |
|
148
|
14
|
|
|
|
|
8849
|
foreach ( keys %{ $self->{_methods} } ) { |
|
|
14
|
|
|
|
|
79
|
|
|
149
|
42
|
|
|
|
|
1396
|
$self->{_methods}{$_}{code} = $self->_get_sub_node( $_ ); |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
return { |
|
153
|
|
|
|
|
|
|
attributes => $self->{_attributes} , |
|
154
|
|
|
|
|
|
|
methods => $self->{_methods} , |
|
155
|
|
|
|
|
|
|
} |
|
156
|
14
|
|
|
|
|
158
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# given two attribute data structures, compare them. returns the older one if |
|
159
|
|
|
|
|
|
|
# they're the same; the newer one if they're not. |
|
160
|
|
|
|
|
|
|
# |
|
161
|
|
|
|
|
|
|
# ignores the value of the 'from' key, since the point here is to check if two |
|
162
|
|
|
|
|
|
|
# attributes from different packages are otherwise identical. |
|
163
|
|
|
|
|
|
|
sub _compare_attributes { |
|
164
|
14
|
|
|
14
|
|
34
|
my( $new_attr , $old_attr ) = @_; |
|
165
|
|
|
|
|
|
|
|
|
166
|
14
|
|
|
|
|
37
|
my $new_from = delete $new_attr->{from}; |
|
167
|
14
|
|
|
|
|
31
|
my $old_from = delete $old_attr->{from}; |
|
168
|
|
|
|
|
|
|
|
|
169
|
14
|
100
|
|
|
|
77
|
if ( eq_deeply( $new_attr , $old_attr )) { |
|
170
|
10
|
|
|
|
|
62947
|
$old_attr->{from} = $old_from; |
|
171
|
10
|
|
|
|
|
40
|
return $old_attr; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
else { |
|
174
|
4
|
|
|
|
|
25845
|
$new_attr->{from} = $new_from; |
|
175
|
4
|
|
|
|
|
14
|
return $new_attr; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# given a list of args that may or may not be a hashref, do whatever munging |
|
180
|
|
|
|
|
|
|
# is needed to return a hashref. |
|
181
|
|
|
|
|
|
|
sub _convert_to_hashref_if_needed { |
|
182
|
18
|
|
|
18
|
|
56
|
my( @list_of_args ) = @_; |
|
183
|
|
|
|
|
|
|
|
|
184
|
18
|
100
|
|
|
|
76
|
return $_[0] if ref $_[0]; |
|
185
|
|
|
|
|
|
|
|
|
186
|
14
|
100
|
|
|
|
77
|
return { module => $_[0] } if @_ == 1; |
|
187
|
|
|
|
|
|
|
|
|
188
|
2
|
|
|
|
|
5
|
my %hash = @_; |
|
189
|
2
|
|
|
|
|
8
|
return \%hash; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# given a meta object and an attribute name (that is an attribute of that meta |
|
193
|
|
|
|
|
|
|
# object), extract a bunch of info about it and store it in the _attributes |
|
194
|
|
|
|
|
|
|
# attr. |
|
195
|
|
|
|
|
|
|
sub _dissect_attribute { |
|
196
|
54
|
|
|
54
|
|
125
|
my( $self , $meta , $attribute_name ) = @_; |
|
197
|
|
|
|
|
|
|
|
|
198
|
54
|
100
|
|
|
|
180
|
if ( $attribute_name =~ /^_/ ) { |
|
199
|
4
|
100
|
|
|
|
130
|
return unless $self->include_private_attributes; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
51
|
|
|
|
|
221
|
my $meta_attr = $meta->get_attribute( $attribute_name ); |
|
203
|
|
|
|
|
|
|
|
|
204
|
51
|
|
|
|
|
392
|
my $return; |
|
205
|
51
|
|
|
|
|
139
|
my $ref = ref $meta_attr; |
|
206
|
51
|
100
|
|
|
|
140
|
if ( $ref eq 'Moose::Meta::Role::Attribute' ) { |
|
207
|
11
|
|
|
|
|
61
|
$return = $meta_attr->original_role->name; |
|
208
|
11
|
|
|
|
|
792
|
$meta_attr = $meta_attr->attribute_for_class(); |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
else { |
|
211
|
40
|
|
|
|
|
187
|
$return = $meta_attr->associated_class->name |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
|
|
214
|
51
|
|
|
|
|
8264
|
my $extracted_attribute = $self->_extract_attribute_metainfo( $meta_attr ); |
|
215
|
51
|
|
|
|
|
147
|
$extracted_attribute->{from} = $return; |
|
216
|
|
|
|
|
|
|
|
|
217
|
51
|
100
|
|
|
|
1649
|
if ( $self->_check_for_stored_attribute( $attribute_name )) { |
|
218
|
14
|
|
|
|
|
404
|
$extracted_attribute = _compare_attributes( |
|
219
|
|
|
|
|
|
|
$extracted_attribute , $self->_get_attribute( $attribute_name ) |
|
220
|
|
|
|
|
|
|
); |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
|
|
223
|
51
|
|
|
|
|
1815
|
$self->_store_attribute( $attribute_name => $extracted_attribute ); |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# given a class name, extract and store info about it and any roles that it |
|
227
|
|
|
|
|
|
|
# has consumed. |
|
228
|
|
|
|
|
|
|
sub _dissect_class { |
|
229
|
21
|
|
|
21
|
|
59
|
my( $self , $class ) = @_; |
|
230
|
21
|
|
|
|
|
138
|
my $meta = $class->meta; |
|
231
|
|
|
|
|
|
|
|
|
232
|
21
|
50
|
|
|
|
628
|
map { $self->_dissect_role($_) } @{ $meta->roles } if ( $meta->can( 'roles' )); |
|
|
9
|
|
|
|
|
106
|
|
|
|
21
|
|
|
|
|
722
|
|
|
233
|
21
|
|
|
|
|
4242
|
map { $self->_dissect_attribute( $meta , $_ ) } $meta->get_attribute_list; |
|
|
43
|
|
|
|
|
320
|
|
|
234
|
21
|
|
|
|
|
290
|
map { $self->_dissect_method( $meta , $_ ) } $meta->get_method_list; |
|
|
147
|
|
|
|
|
18051
|
|
|
235
|
|
|
|
|
|
|
|
|
236
|
21
|
|
|
|
|
140
|
$self->_extract_sub_nodes( $meta->name ); |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# given a meta object and a method name (that is a method of that meta |
|
240
|
|
|
|
|
|
|
# object), extract and store info about the method. |
|
241
|
|
|
|
|
|
|
sub _dissect_method { |
|
242
|
167
|
|
|
167
|
|
389
|
my( $self , $meta , $method_name ) = @_; |
|
243
|
|
|
|
|
|
|
|
|
244
|
167
|
100
|
|
|
|
403
|
if ( $method_name =~ /^_/ ) { |
|
245
|
8
|
100
|
|
|
|
253
|
return unless $self->include_private_methods; |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
|
|
248
|
161
|
|
|
|
|
450
|
my $meta_method = $meta->get_method( $method_name ); |
|
249
|
|
|
|
|
|
|
|
|
250
|
161
|
|
|
|
|
5182
|
my $src = $meta_method->original_package_name; |
|
251
|
|
|
|
|
|
|
|
|
252
|
161
|
100
|
|
|
|
5882
|
unless ( $self->include_accessors_in_method_list ) { |
|
253
|
143
|
100
|
|
|
|
305
|
return if $self->_check_exclusion( $method_name ); |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
125
|
100
|
|
|
|
2999
|
unless ( $self->include_standard_methods ) { |
|
257
|
107
|
|
|
|
|
265
|
my @STOCK = qw/ DESTROY meta new /; |
|
258
|
107
|
|
|
|
|
200
|
foreach ( @STOCK ) { |
|
259
|
255
|
100
|
|
|
|
554
|
return if $method_name eq $_; |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
|
|
263
|
59
|
|
|
|
|
166
|
my $extracted_method = $self->_extract_method_metainfo( $meta_method ); |
|
264
|
59
|
|
|
|
|
2311
|
$self->_store_method( $method_name => $extracted_method ); |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# extract and store information from a particular role |
|
268
|
|
|
|
|
|
|
sub _dissect_role { |
|
269
|
10
|
|
|
10
|
|
31
|
my( $self , $meta ) = @_; |
|
270
|
|
|
|
|
|
|
|
|
271
|
10
|
|
|
|
|
54
|
map { $self->_dissect_attribute( $meta , $_ ) } $meta->get_attribute_list; |
|
|
11
|
|
|
|
|
124
|
|
|
272
|
10
|
|
|
|
|
106
|
map { $self->_dissect_method( $meta , $_ ) } $meta->get_method_list; |
|
|
20
|
|
|
|
|
995
|
|
|
273
|
|
|
|
|
|
|
|
|
274
|
10
|
|
|
|
|
87
|
my @names = split '\|' , $meta->name; |
|
275
|
10
|
|
|
|
|
36
|
foreach my $name ( @names ) { |
|
276
|
11
|
50
|
|
|
|
398
|
next if $name =~ /Moose::Meta::Role::__ANON/; |
|
277
|
11
|
|
|
|
|
35
|
$self->_extract_sub_nodes( $name ); |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# given a meta attribute, extract a bunch of meta info and return a data |
|
282
|
|
|
|
|
|
|
# structure summarizing it. |
|
283
|
|
|
|
|
|
|
sub _extract_attribute_metainfo { |
|
284
|
51
|
|
|
51
|
|
111
|
my( $self , $meta_attr ) = @_; |
|
285
|
|
|
|
|
|
|
|
|
286
|
51
|
|
|
|
|
95
|
my $return = {}; |
|
287
|
|
|
|
|
|
|
|
|
288
|
51
|
|
|
|
|
122
|
foreach ( qw/ reader writer accessor / ) { |
|
289
|
153
|
100
|
|
|
|
652
|
next unless my $fxn = $meta_attr->$_; |
|
290
|
51
|
|
|
|
|
185
|
$self->_add_exclusion( $fxn ); |
|
291
|
51
|
|
|
|
|
146
|
$return->{$_} = $fxn; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
|
|
294
|
51
|
100
|
|
|
|
2145
|
$return->{meta}{documentation} = $meta_attr->documentation |
|
295
|
|
|
|
|
|
|
if ( $meta_attr->has_documentation ); |
|
296
|
|
|
|
|
|
|
|
|
297
|
51
|
100
|
|
|
|
2853
|
$return->{meta}{constraint} = $meta_attr->type_constraint->name |
|
298
|
|
|
|
|
|
|
if ( $meta_attr->has_type_constraint ); |
|
299
|
|
|
|
|
|
|
|
|
300
|
51
|
100
|
|
|
|
4635
|
$return->{meta}{traits} = $meta_attr->applied_traits |
|
301
|
|
|
|
|
|
|
if ( $meta_attr->has_applied_traits ); |
|
302
|
|
|
|
|
|
|
|
|
303
|
51
|
|
|
|
|
648
|
foreach ( qw/ |
|
304
|
|
|
|
|
|
|
is_weak_ref is_required is_lazy is_lazy_build should_coerce |
|
305
|
|
|
|
|
|
|
should_auto_deref has_trigger has_handles |
|
306
|
|
|
|
|
|
|
/ ) { |
|
307
|
408
|
100
|
|
|
|
14833
|
$return->{meta}{$_}++ if $meta_attr->$_ ; |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
### FIXME should look at delegated methods and install exclusions for them |
|
311
|
|
|
|
|
|
|
|
|
312
|
51
|
|
|
|
|
313
|
return $return; |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# given a meta method, extract a bunch of info and return a data structure |
|
317
|
|
|
|
|
|
|
# summarizing it. |
|
318
|
|
|
|
|
|
|
sub _extract_method_metainfo { |
|
319
|
59
|
|
|
59
|
|
113
|
my( $self , $meta_method ) = @_; |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
return { |
|
322
|
59
|
|
|
|
|
209
|
from => $meta_method->original_package_name , |
|
323
|
|
|
|
|
|
|
}; |
|
324
|
|
|
|
|
|
|
} |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# given a module name, use PPI to extract the 'sub' nodes and store them. |
|
327
|
|
|
|
|
|
|
sub _extract_sub_nodes { |
|
328
|
32
|
|
|
32
|
|
86
|
my( $self , $name ) = @_; |
|
329
|
|
|
|
|
|
|
|
|
330
|
32
|
|
|
|
|
94
|
my $path = $name . '.pm'; |
|
331
|
32
|
|
|
|
|
144
|
$path =~ s|::|/|g; |
|
332
|
32
|
50
|
|
|
|
166
|
if ( $path = $INC{$path} ){ |
|
333
|
|
|
|
|
|
|
try { |
|
334
|
32
|
50
|
|
32
|
|
1154
|
my $ppi = PPI::Document->new( $path ) |
|
335
|
|
|
|
|
|
|
or die "Can't load PPI for $path ($!)"; |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
my $sub_nodes = $ppi->find( |
|
338
|
3886
|
100
|
|
|
|
41552
|
sub{ $_[1]->isa( 'PPI::Statement::Sub' ) && $_[1]->name } |
|
339
|
32
|
|
|
|
|
441810
|
); |
|
340
|
|
|
|
|
|
|
|
|
341
|
32
|
|
|
|
|
531
|
foreach my $sub_node ( @$sub_nodes ) { |
|
342
|
46
|
|
|
|
|
158
|
my $name = $sub_node->name; |
|
343
|
46
|
|
|
|
|
997
|
$self->_store_sub_node( $name => $sub_node->content ); |
|
344
|
|
|
|
|
|
|
} |
|
345
|
32
|
|
|
|
|
311
|
}; |
|
346
|
|
|
|
|
|
|
# FIXME should probably do something about errors here... |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
} |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
# given a module name and a path to that module, dynamically load the |
|
352
|
|
|
|
|
|
|
# module. figures out the appropriate 'use lib' statement based on the path. |
|
353
|
|
|
|
|
|
|
sub _load_module_from_path { |
|
354
|
3
|
|
|
3
|
|
12
|
my( $module , $path ) = @_; |
|
355
|
|
|
|
|
|
|
|
|
356
|
3
|
|
|
|
|
18
|
$path =~ s/.pm$//; |
|
357
|
3
|
|
|
|
|
20
|
my @path_parts = split '/' , $path; |
|
358
|
3
|
|
|
|
|
14
|
my @module_parts = split /::/ , $module; |
|
359
|
3
|
|
|
|
|
7
|
my @inc_path = (); |
|
360
|
|
|
|
|
|
|
|
|
361
|
3
|
|
|
|
|
10
|
while ( @path_parts ) { |
|
362
|
14
|
|
|
|
|
31
|
my $path = join '/' , @path_parts; |
|
363
|
14
|
|
|
|
|
23
|
my $mod = join '/' , @module_parts; |
|
364
|
14
|
100
|
|
|
|
32
|
last if $path eq $mod; |
|
365
|
12
|
|
|
|
|
28
|
push @inc_path , shift @path_parts; |
|
366
|
|
|
|
|
|
|
} |
|
367
|
3
|
|
|
|
|
11
|
my $inc_path = join '/' , @inc_path; |
|
368
|
|
|
|
|
|
|
|
|
369
|
3
|
|
|
2
|
|
325
|
eval "use lib '$inc_path'; require $module"; |
|
|
2
|
|
|
1
|
|
19
|
|
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
15
|
|
|
|
1
|
|
|
|
|
18
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
11
|
|
|
370
|
3
|
100
|
|
|
|
51275
|
die $@ if $@; |
|
371
|
|
|
|
|
|
|
|
|
372
|
2
|
|
|
|
|
15
|
return $module; |
|
373
|
|
|
|
|
|
|
} |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
#__PACKAGE__->meta->make_immutable; |
|
377
|
|
|
|
|
|
|
1; |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
__END__ |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=pod |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=encoding UTF-8 |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head1 NAME |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
MooseX::amine - Examine Yr Moose |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=head1 VERSION |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
version 0.7 |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
my $mex = MooseX::amine->new( 'MooseX::amine' ); |
|
396
|
|
|
|
|
|
|
my $data = $mex->examine; |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
my $attributes = $data->{attributes}; |
|
399
|
|
|
|
|
|
|
my $methods = $data->{methods}; |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=head1 METHODS |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=head2 new |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# these two are the same |
|
406
|
|
|
|
|
|
|
my $mex = MooseX::amine->new( 'Module' ); |
|
407
|
|
|
|
|
|
|
my $mex = MooseX::amine->new({ module => 'Module' }); |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# or you can go from the path to the file |
|
410
|
|
|
|
|
|
|
my $mex = MooseX::amine->new({ path = 'path/to/Module.pm' }); |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# there are a number of options that all pretty much do what they say. |
|
413
|
|
|
|
|
|
|
# they all default to off |
|
414
|
|
|
|
|
|
|
my $mex = MooseX::amine->new({ |
|
415
|
|
|
|
|
|
|
module => 'Module' , |
|
416
|
|
|
|
|
|
|
include_accessors_in_method_list => 1, |
|
417
|
|
|
|
|
|
|
include_moose_in_isa => 1, |
|
418
|
|
|
|
|
|
|
include_private_attributes => 1, |
|
419
|
|
|
|
|
|
|
include_private_methods => 1, |
|
420
|
|
|
|
|
|
|
include_standard_methods => 1, |
|
421
|
|
|
|
|
|
|
}); |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=head2 examine |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
my $mex = MooseX::amine( 'Module' ); |
|
426
|
|
|
|
|
|
|
my $data = $mex->examine(); |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Returns a multi-level hash-based data structure, with two top-level keys, |
|
429
|
|
|
|
|
|
|
C<attributes> and C<methods>. C<attributes> points to a hash where the keys |
|
430
|
|
|
|
|
|
|
are attribute names and the values are data structures that describe the |
|
431
|
|
|
|
|
|
|
attributes. Similarly, C<methods> points to a hash where the keys are method |
|
432
|
|
|
|
|
|
|
names and the values are data structures describing the method. |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
A sample attribute entry: |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
simple_attribute => { |
|
437
|
|
|
|
|
|
|
accessor => 'simple_attribute', |
|
438
|
|
|
|
|
|
|
from => 'Module', |
|
439
|
|
|
|
|
|
|
meta => { |
|
440
|
|
|
|
|
|
|
constraint => 'Str' |
|
441
|
|
|
|
|
|
|
} |
|
442
|
|
|
|
|
|
|
} |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
The prescence of an C<accessor> key indicates that this attribute was defined |
|
445
|
|
|
|
|
|
|
with C<is => 'rw'>. A read-only attribute will have a C<reader> key. A |
|
446
|
|
|
|
|
|
|
C<writer> key may also be present if a specific writer method was given when |
|
447
|
|
|
|
|
|
|
creating the attribute. |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Depending on the options given when creating the attribute there may be |
|
450
|
|
|
|
|
|
|
various other options present under the C<meta> key. |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
A sample method entry: |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
simple_method => { |
|
455
|
|
|
|
|
|
|
code => 'sub simple_method { return \'simple\' }', |
|
456
|
|
|
|
|
|
|
from => 'Module' |
|
457
|
|
|
|
|
|
|
} |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
The C<code> key will contain the actual code from the method, extracted with |
|
460
|
|
|
|
|
|
|
PPI. Depending on where the method code actually lives, this key may or may |
|
461
|
|
|
|
|
|
|
not be present. |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head1 CREDITS |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=over 4 |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=item Semi-inspired by L<MooseX::Documenter>. |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=item Syntax highlighting Javascript/CSS stuff based on SHJS and largely stolen from search.cpan.org. |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=back |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=head1 AUTHOR |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
John SJ Anderson <john@genehack.org> |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
This software is copyright (c) 2020 by John SJ Anderson. |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
482
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=cut |