Filename | /home/hejohns/perl5/lib/perl5/Data/Printer/Filter/GenericClass.pm |
Statements | Executed 12 statements in 1.38ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 8µs | 9µs | BEGIN@2 | Data::Printer::Filter::GenericClass::
1 | 1 | 1 | 6µs | 6µs | BEGIN@5 | Data::Printer::Filter::GenericClass::
1 | 1 | 1 | 4µs | 11µs | BEGIN@6 | Data::Printer::Filter::GenericClass::
1 | 1 | 1 | 3µs | 16µs | BEGIN@3 | Data::Printer::Filter::GenericClass::
1 | 1 | 1 | 3µs | 14µs | BEGIN@4 | Data::Printer::Filter::GenericClass::
1 | 1 | 1 | 300ns | 300ns | __ANON__ (xsub) | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | __ANON__[:102] | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | __ANON__[:184] | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | __ANON__[:199] | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | __ANON__[:213] | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | __ANON__[:72] | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | __ANON__[:91] | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | _get_all_subs_from | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | _get_overloads | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | _get_stringification | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | _methods_of | Data::Printer::Filter::GenericClass::
0 | 0 | 0 | 0s | 0s | _show_methods | Data::Printer::Filter::GenericClass::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package Data::Printer::Filter::GenericClass; | ||||
2 | 2 | 16µs | 2 | 10µs | # spent 9µs (8+1) within Data::Printer::Filter::GenericClass::BEGIN@2 which was called:
# once (8µs+1µs) by Data::Printer::Object::BEGIN@61 at line 2 # spent 9µs making 1 call to Data::Printer::Filter::GenericClass::BEGIN@2
# spent 1µs making 1 call to strict::import |
3 | 2 | 16µs | 2 | 28µs | # spent 16µs (3+13) within Data::Printer::Filter::GenericClass::BEGIN@3 which was called:
# once (3µs+13µs) by Data::Printer::Object::BEGIN@61 at line 3 # spent 16µs making 1 call to Data::Printer::Filter::GenericClass::BEGIN@3
# spent 13µs making 1 call to warnings::import |
4 | 2 | 14µs | 2 | 26µs | # spent 14µs (3+12) within Data::Printer::Filter::GenericClass::BEGIN@4 which was called:
# once (3µs+12µs) by Data::Printer::Object::BEGIN@61 at line 4 # spent 14µs making 1 call to Data::Printer::Filter::GenericClass::BEGIN@4
# spent 12µs making 1 call to Data::Printer::Filter::import |
5 | 2 | 15µs | 2 | 6µs | # spent 6µs (6+300ns) within Data::Printer::Filter::GenericClass::BEGIN@5 which was called:
# once (6µs+300ns) by Data::Printer::Object::BEGIN@61 at line 5 # spent 6µs making 1 call to Data::Printer::Filter::GenericClass::BEGIN@5
# spent 300ns making 1 call to Data::Printer::Filter::GenericClass::__ANON__ |
6 | 2 | 1.31ms | 2 | 18µs | # spent 11µs (4+7) within Data::Printer::Filter::GenericClass::BEGIN@6 which was called:
# once (4µs+7µs) by Data::Printer::Object::BEGIN@61 at line 6 # spent 11µs making 1 call to Data::Printer::Filter::GenericClass::BEGIN@6
# spent 7µs making 1 call to Exporter::import |
7 | |||||
8 | filter '-class' => sub { | ||||
9 | my ($object, $ddp) = @_; | ||||
10 | |||||
11 | # if the class implements its own Data::Printer method, we use it! | ||||
12 | if ($ddp->class_method and my $method = $object->can( $ddp->class_method )) { | ||||
13 | return $method->($object, $ddp) if ref $method eq 'CODE'; | ||||
14 | } | ||||
15 | |||||
16 | my $class_name = ref $object; | ||||
17 | |||||
18 | # there are many parts of the class filter that require the object's | ||||
19 | # linear ISA, so we declare it earlier and load it only once: | ||||
20 | my $linear_ISA = Data::Printer::Common::_linear_ISA_for($class_name, $ddp); | ||||
21 | |||||
22 | # if the object overloads stringification, use it! | ||||
23 | # except for PDF::API2 which has a destructive stringify() | ||||
24 | if ($ddp->class->stringify && $class_name ne 'PDF::API2') { | ||||
25 | my $str = _get_stringification($ddp, $object, $class_name); | ||||
26 | return $ddp->maybe_colorize("$str ($class_name)", 'class') | ||||
27 | if defined $str; | ||||
28 | } | ||||
29 | |||||
30 | # otherwise, do our generic object representation: | ||||
31 | my $show_reftype = $ddp->class->show_reftype; | ||||
32 | my $show_internals = $ddp->class->internals; | ||||
33 | my $reftype; | ||||
34 | if ($show_reftype || $show_internals) { | ||||
35 | $reftype = Scalar::Util::reftype($object); | ||||
36 | $reftype = 'Regexp' if $reftype eq 'REGEXP'; | ||||
37 | } | ||||
38 | |||||
39 | $ddp->{_class_depth}++; | ||||
40 | my $string = $ddp->maybe_colorize( $class_name, 'class' ); | ||||
41 | |||||
42 | if ($show_reftype) { | ||||
43 | $string .= ' ' | ||||
44 | . $ddp->maybe_colorize('(', 'brackets') | ||||
45 | . $ddp->maybe_colorize( $reftype, 'class' ) | ||||
46 | . $ddp->maybe_colorize(')', 'brackets'); | ||||
47 | } | ||||
48 | |||||
49 | if ($ddp->class->expand eq 'all' || $ddp->class->expand >= $ddp->{_class_depth}) { | ||||
50 | $ddp->indent; | ||||
51 | $string .= ' ' . $ddp->maybe_colorize('{', 'brackets'); | ||||
52 | |||||
53 | my @superclasses = Data::Printer::Common::_get_superclasses_for($class_name); | ||||
54 | if (@superclasses && $ddp->class->parents) { | ||||
55 | $string .= $ddp->newline . 'parents: ' | ||||
56 | . join(', ', map $ddp->maybe_colorize($_, 'class'), @superclasses) | ||||
57 | ; | ||||
58 | } | ||||
59 | my (%roles, %attributes); | ||||
60 | if ($INC{'Role/Tiny.pm'} && exists $Role::Tiny::APPLIED_TO{$class_name}) { | ||||
61 | %roles = %{ $Role::Tiny::APPLIED_TO{$class_name} }; | ||||
62 | } | ||||
63 | my $is_moose = 0; | ||||
64 | |||||
65 | foreach my $parent (@$linear_ISA) { | ||||
66 | if ($parent eq 'Moo::Object') { | ||||
67 | Data::Printer::Common::_tryme(sub { | ||||
68 | my $moo_maker = 'Moo'->_constructor_maker_for($class_name); | ||||
69 | if (defined $moo_maker) { | ||||
70 | %attributes = %{ $moo_maker->all_attribute_specs }; | ||||
71 | } | ||||
72 | }); | ||||
73 | last; | ||||
74 | } | ||||
75 | elsif ($parent eq 'Moose::Object') { | ||||
76 | Data::Printer::Common::_tryme(sub { | ||||
77 | my $class_meta = $class_name->meta; | ||||
78 | $is_moose = 1; | ||||
79 | %attributes = map { | ||||
80 | $_->name => { | ||||
81 | index => $_->insertion_order, | ||||
82 | init_arg => $_->init_arg, | ||||
83 | is => (defined $_->writer ? 'rw' : 'ro'), | ||||
84 | reader => $_->reader, | ||||
85 | required => $_->is_required, | ||||
86 | } | ||||
87 | } $class_meta->get_all_attributes(); | ||||
88 | foreach my $role ($class_meta->calculate_all_roles()) { | ||||
89 | $roles{ $role->name } = 1; | ||||
90 | } | ||||
91 | }); | ||||
92 | last; | ||||
93 | } | ||||
94 | elsif ($parent eq 'Object::Pad::UNIVERSAL') { | ||||
95 | Data::Printer::Common::_tryme(sub { | ||||
96 | my $meta = Object::Pad::MOP::Class->for_class( $class_name ); | ||||
97 | %attributes = map { | ||||
98 | $_->name . $_->value($class_name) => { | ||||
99 | } | ||||
100 | } $meta->fields; | ||||
101 | %roles = map { $_->name => 1 } $meta->direct_roles; | ||||
102 | }); | ||||
103 | } | ||||
104 | } | ||||
105 | if ($ddp->class->show_methods ne 'none') { | ||||
106 | if (my @role_list = keys %roles) { | ||||
107 | @role_list = Data::Printer::Common::_nsort(@role_list) | ||||
108 | if @role_list && $ddp->class->sort_methods; | ||||
109 | $string .= $ddp->newline . 'roles (' . scalar(@role_list) . '): ' | ||||
110 | . join(', ' => map $ddp->maybe_colorize($_, 'class'), @role_list) | ||||
111 | ; | ||||
112 | } | ||||
113 | |||||
114 | if (my @attr_list = keys %attributes) { | ||||
115 | @attr_list = Data::Printer::Common::_nsort(@attr_list) | ||||
116 | if @attr_list && $ddp->class->sort_methods; | ||||
117 | $string .= $ddp->newline . 'attributes (' . scalar(@attr_list) . '): ' | ||||
118 | . join(', ' => map $ddp->maybe_colorize($_, 'method'), @attr_list) | ||||
119 | ; | ||||
120 | } | ||||
121 | } | ||||
122 | |||||
123 | my $show_linear_isa = $ddp->class->linear_isa && ( | ||||
124 | ($ddp->class->linear_isa eq 'auto' and @superclasses > 1) | ||||
125 | or ($ddp->class->linear_isa ne 'auto') | ||||
126 | ); | ||||
127 | |||||
128 | if ($show_linear_isa && @$linear_ISA) { | ||||
129 | $string .= $ddp->newline . 'linear @ISA: ' | ||||
130 | . join(', ' => map $ddp->maybe_colorize($_, 'class'), @$linear_ISA) | ||||
131 | ; | ||||
132 | } | ||||
133 | |||||
134 | if ($ddp->class->show_methods ne 'none') { | ||||
135 | $string .= _show_methods($class_name, $linear_ISA, \%attributes, $ddp); | ||||
136 | if ($is_moose && $ddp->class->show_wrapped) { | ||||
137 | my $modified = ''; | ||||
138 | my $modified_count = 0; | ||||
139 | $ddp->indent; | ||||
140 | for my $method ($class_name->meta->get_all_methods) { | ||||
141 | if (ref $method eq 'Class::MOP::Method::Wrapped') { | ||||
142 | foreach my $kind (qw(before around after)) { | ||||
143 | my $getter_method = $kind . '_modifiers'; | ||||
144 | if (my @modlist = $method->$getter_method) { | ||||
145 | $modified .= $ddp->newline . $kind . ' ' . $method->name . ': ' | ||||
146 | . (@modlist > 1 ? $ddp->parse(\@modlist) : $ddp->parse($modlist[0])); | ||||
147 | $modified_count++; | ||||
148 | } | ||||
149 | } | ||||
150 | } | ||||
151 | } | ||||
152 | $ddp->outdent; | ||||
153 | if ($modified_count) { | ||||
154 | $string .= $ddp->newline . 'method modifiers (' . $modified_count . '):' | ||||
155 | . $modified; | ||||
156 | } | ||||
157 | } | ||||
158 | } | ||||
159 | |||||
160 | if ($ddp->class->show_overloads) { | ||||
161 | my @overloads = _get_overloads($object); | ||||
162 | if (@overloads) { | ||||
163 | $string .= $ddp->newline . 'overloads: ' . join(', ' => @overloads); | ||||
164 | } | ||||
165 | } | ||||
166 | |||||
167 | if ($show_internals) { | ||||
168 | $string .= $ddp->newline | ||||
169 | . 'internals: ' | ||||
170 | . $ddp->parse_as($reftype, $object) | ||||
171 | ; | ||||
172 | } | ||||
173 | |||||
174 | $ddp->outdent; | ||||
175 | $string .= $ddp->newline . $ddp->maybe_colorize('}', 'brackets'); | ||||
176 | } | ||||
177 | $ddp->{_class_depth}--; | ||||
178 | |||||
179 | if ($ddp->show_tied and my $tie = ref tied $object) { | ||||
180 | $string .= " (tied to $tie)"; | ||||
181 | } | ||||
182 | |||||
183 | return $string; | ||||
184 | 1 | 5µs | 1 | 16µs | }; # spent 16µs making 1 call to Data::Printer::Filter::__ANON__[Data/Printer/Filter.pm:23] |
185 | |||||
186 | ####################################### | ||||
187 | ### Private auxiliary helpers below ### | ||||
188 | ####################################### | ||||
189 | |||||
190 | sub _get_stringification { | ||||
191 | my ($ddp, $object, $class_name) = @_; | ||||
192 | require overload; | ||||
193 | if (overload::Overloaded($object) | ||||
194 | && (overload::Method($object, q("")) | ||||
195 | || overload::Method($object, q(0+)) | ||||
196 | ) | ||||
197 | ) { | ||||
198 | my $string; | ||||
199 | my $error = Data::Printer::Common::_tryme(sub { $string = '' . $object }); | ||||
200 | if ($error) { | ||||
201 | Data::Printer::Common::_warn( | ||||
202 | $ddp, | ||||
203 | "string/number overload error for object $class_name: $error" | ||||
204 | ); | ||||
205 | } | ||||
206 | else { | ||||
207 | return $string; | ||||
208 | } | ||||
209 | } | ||||
210 | foreach my $method (qw(as_string stringify to_string)) { | ||||
211 | if ($object->can($method)) { | ||||
212 | my $string; | ||||
213 | my $error = Data::Printer::Common::_tryme(sub { $string = $object->$method }); | ||||
214 | if ($error) { | ||||
215 | Data::Printer::Common::_warn( | ||||
216 | $ddp, | ||||
217 | "error stringifying object $class_name with $method\(\): $error" | ||||
218 | ); | ||||
219 | } | ||||
220 | else { | ||||
221 | return $string; | ||||
222 | } | ||||
223 | } | ||||
224 | } | ||||
225 | return; | ||||
226 | } | ||||
227 | |||||
228 | # returns array of all overloads in class; | ||||
229 | sub _get_overloads { | ||||
230 | my ($object) = @_; | ||||
231 | require overload; | ||||
232 | return () unless overload::Overloaded($object); | ||||
233 | return sort grep overload::Method($object, $_), | ||||
234 | map split(/\s+/), values %overload::ops; | ||||
235 | } | ||||
236 | |||||
237 | sub _show_methods { | ||||
238 | my ($class_name, $linear_ISA, $attributes, $ddp) = @_; | ||||
239 | |||||
240 | my %methods = ( public => {}, private => {} ); | ||||
241 | my @all_methods = map _methods_of( | ||||
242 | $_, Data::Printer::Common::_get_namespace($_) | ||||
243 | ), @$linear_ISA; | ||||
244 | my $show_methods = $ddp->class->show_methods; | ||||
245 | my $show_inherited = $ddp->class->inherited; | ||||
246 | my %seen_method_name; | ||||
247 | foreach my $method (@all_methods) { | ||||
248 | my ($package_string, $method_string) = @$method; | ||||
249 | next if exists $attributes->{$method_string}; | ||||
250 | next if $seen_method_name{$method_string}++; | ||||
251 | next if $method_string eq '__ANON__'; # anonymous subs don't matter here. | ||||
252 | my $type = substr($method_string, 0, 1) eq '_' ? 'private' : 'public'; | ||||
253 | if ($package_string eq $class_name) { | ||||
254 | next unless $show_methods eq 'all' || $show_methods eq $type; | ||||
255 | $methods{$type}{$method_string} = undef; | ||||
256 | } | ||||
257 | else { | ||||
258 | next unless $show_inherited eq 'all' || $show_inherited eq $type; | ||||
259 | $methods{$type}{$method_string} = $package_string; | ||||
260 | } | ||||
261 | } | ||||
262 | my $string = ''; | ||||
263 | foreach my $type (qw(public private)) { | ||||
264 | next unless $show_methods eq 'all' or $show_methods eq $type | ||||
265 | or $show_inherited eq 'all' or $show_inherited eq $type | ||||
266 | ; | ||||
267 | if ($ddp->class->format_inheritance eq 'string') { | ||||
268 | my @method_list = keys %{$methods{$type}}; | ||||
269 | @method_list = Data::Printer::Common::_nsort(@method_list) | ||||
270 | if @method_list && $ddp->class->sort_methods; | ||||
271 | |||||
272 | $string .= $ddp->newline . "$type methods (" . scalar(@method_list) . ')'; | ||||
273 | if (@method_list) { | ||||
274 | $string .= ': ' | ||||
275 | . join(', ' => map { | ||||
276 | $ddp->maybe_colorize( | ||||
277 | $_ . (defined $methods{$type}{$_} ? " ($methods{$type}{$_})" : ''), | ||||
278 | 'method' | ||||
279 | ) | ||||
280 | } @method_list) | ||||
281 | ; | ||||
282 | } | ||||
283 | } | ||||
284 | else { # 'lines' | ||||
285 | # first we convert our hash to { pkg => [ @methods ] } | ||||
286 | my %lined_methods; | ||||
287 | my @base_methods; | ||||
288 | my $total_methods = 0; | ||||
289 | foreach my $method (keys %{$methods{$type}}) { | ||||
290 | my $pkg_name = $methods{$type}{$method}; | ||||
291 | if (defined $pkg_name) { | ||||
292 | push @{ $lined_methods{$pkg_name} }, $method; | ||||
293 | } | ||||
294 | else { | ||||
295 | push @base_methods, $method; | ||||
296 | } | ||||
297 | $total_methods++; | ||||
298 | } | ||||
299 | |||||
300 | # then we print them, starting with our own methods: | ||||
301 | @base_methods = Data::Printer::Common::_nsort(@base_methods) | ||||
302 | if @base_methods && $ddp->class->sort_methods; | ||||
303 | |||||
304 | $string .= $ddp->newline . "$type methods ($total_methods)" | ||||
305 | . ($total_methods ? ':' : '') | ||||
306 | ; | ||||
307 | if (@base_methods) { | ||||
308 | my $base_string = join(', ' => map { | ||||
309 | $ddp->maybe_colorize($_, 'method') | ||||
310 | } @base_methods); | ||||
311 | $ddp->indent; | ||||
312 | # newline only if we have parent methods to show: | ||||
313 | $string .= (keys %lined_methods ? $ddp->newline : ' ') . $base_string; | ||||
314 | $ddp->outdent; | ||||
315 | } | ||||
316 | foreach my $pkg (sort keys %lined_methods) { | ||||
317 | $ddp->indent; | ||||
318 | $string .= $ddp->newline . "$pkg:"; | ||||
319 | @{$lined_methods{$pkg}} = Data::Printer::Common::_nsort(@{$lined_methods{$pkg}}) | ||||
320 | if $ddp->class->sort_methods; | ||||
321 | $ddp->indent; | ||||
322 | $string .= $ddp->newline . join(', ' => map { | ||||
323 | $ddp->maybe_colorize($_, 'method') | ||||
324 | } @{$lined_methods{$pkg}} | ||||
325 | ); | ||||
326 | $ddp->outdent; | ||||
327 | $ddp->outdent; | ||||
328 | } | ||||
329 | } | ||||
330 | } | ||||
331 | |||||
332 | return $string; | ||||
333 | } | ||||
334 | |||||
335 | sub _methods_of { | ||||
336 | require B; | ||||
337 | my ($class_name, $namespace) = @_; | ||||
338 | my @methods; | ||||
339 | foreach my $subref (_get_all_subs_from($class_name, $namespace)) { | ||||
340 | next unless $subref; | ||||
341 | my $m = B::svref_2object($subref); | ||||
342 | next unless $m && $m->isa('B::CV'); | ||||
343 | my $gv = $m->GV; | ||||
344 | next unless $gv && !$gv->isa('B::Special') && $gv->NAME; | ||||
345 | push @methods, [ $gv->STASH->NAME, $gv->NAME ]; | ||||
346 | } | ||||
347 | return @methods; | ||||
348 | } | ||||
349 | |||||
350 | sub _get_all_subs_from { | ||||
351 | my ($class_name, $namespace) = @_; | ||||
352 | my @subs; | ||||
353 | foreach my $key (keys %$namespace) { | ||||
354 | # perlsub says any sub starting with '(' is reserved for overload, | ||||
355 | # so we skip those: | ||||
356 | next if substr($key, 0, 1) eq '('; | ||||
357 | if ( | ||||
358 | # any non-typeglob in the symbol table is a constant or stub | ||||
359 | ref(\$namespace->{$key}) ne 'GLOB' | ||||
360 | # regular subs are stored in the CODE slot of the typeglob | ||||
361 | || defined(*{$namespace->{$key}}{CODE}) | ||||
362 | ) { | ||||
363 | push @subs, $key; | ||||
364 | } | ||||
365 | } | ||||
366 | my @symbols; | ||||
367 | foreach my $sub (@subs) { | ||||
368 | push @symbols, Data::Printer::Common::_get_symbol($class_name, $namespace, $sub, 'CODE'); | ||||
369 | } | ||||
370 | return @symbols; | ||||
371 | } | ||||
372 | |||||
373 | 1 | 2µs | 1; | ||
# spent 300ns within Data::Printer::Filter::GenericClass::__ANON__ which was called:
# once (300ns+0s) by Data::Printer::Filter::GenericClass::BEGIN@5 at line 5 |