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 |