| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Data::Printer::Filter::GenericClass; | 
| 2 | 34 |  |  | 34 |  | 230 | use strict; | 
|  | 34 |  |  |  |  | 74 |  | 
|  | 34 |  |  |  |  | 933 |  | 
| 3 | 34 |  |  | 34 |  | 219 | use warnings; | 
|  | 34 |  |  |  |  | 69 |  | 
|  | 34 |  |  |  |  | 797 |  | 
| 4 | 34 |  |  | 34 |  | 170 | use Data::Printer::Filter; | 
|  | 34 |  |  |  |  | 66 |  | 
|  | 34 |  |  |  |  | 190 |  | 
| 5 | 34 |  |  | 34 |  | 168 | use Data::Printer::Common; | 
|  | 34 |  |  |  |  | 87 |  | 
|  | 34 |  |  |  |  | 760 |  | 
| 6 | 34 |  |  | 34 |  | 204 | use Scalar::Util; | 
|  | 34 |  |  |  |  | 67 |  | 
|  | 34 |  |  |  |  | 85173 |  | 
| 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 |  |  |  |  |  |  | }; | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | ####################################### | 
| 187 |  |  |  |  |  |  | ### Private auxiliary helpers below ### | 
| 188 |  |  |  |  |  |  | ####################################### | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | sub _get_stringification { | 
| 191 | 50 |  |  | 50 |  | 110 | my ($ddp, $object, $class_name) = @_; | 
| 192 | 50 |  |  |  |  | 319 | require overload; | 
| 193 | 50 | 100 | 100 |  |  | 184 | if (overload::Overloaded($object) | 
|  |  |  | 100 |  |  |  |  | 
| 194 |  |  |  |  |  |  | && (overload::Method($object, q("")) | 
| 195 |  |  |  |  |  |  | || overload::Method($object, q(0+)) | 
| 196 |  |  |  |  |  |  | ) | 
| 197 |  |  |  |  |  |  | ) { | 
| 198 | 3 |  |  |  |  | 360 | my $string; | 
| 199 | 3 |  |  | 3 |  | 17 | my $error = Data::Printer::Common::_tryme(sub { $string = '' . $object }); | 
|  | 3 |  |  |  |  | 83 |  | 
| 200 | 3 | 50 |  |  |  | 12 | if ($error) { | 
| 201 | 0 |  |  |  |  | 0 | Data::Printer::Common::_warn( | 
| 202 |  |  |  |  |  |  | $ddp, | 
| 203 |  |  |  |  |  |  | "string/number overload error for object $class_name: $error" | 
| 204 |  |  |  |  |  |  | ); | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  | else { | 
| 207 | 3 |  |  |  |  | 11 | return $string; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  | } | 
| 210 | 47 |  |  |  |  | 3082 | foreach my $method (qw(as_string stringify to_string)) { | 
| 211 | 138 | 100 |  |  |  | 581 | if ($object->can($method)) { | 
| 212 | 2 |  |  |  |  | 5 | my $string; | 
| 213 | 2 |  |  | 2 |  | 13 | my $error = Data::Printer::Common::_tryme(sub { $string = $object->$method }); | 
|  | 2 |  |  |  |  | 7 |  | 
| 214 | 2 | 50 |  |  |  | 9 | if ($error) { | 
| 215 | 0 |  |  |  |  | 0 | Data::Printer::Common::_warn( | 
| 216 |  |  |  |  |  |  | $ddp, | 
| 217 |  |  |  |  |  |  | "error stringifying object $class_name with $method\(\): $error" | 
| 218 |  |  |  |  |  |  | ); | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | else { | 
| 221 | 2 |  |  |  |  | 6 | return $string; | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  | } | 
| 225 | 45 |  |  |  |  | 102 | return; | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | # returns array of all overloads in class; | 
| 229 |  |  |  |  |  |  | sub _get_overloads { | 
| 230 | 37 |  |  | 37 |  | 81 | my ($object) = @_; | 
| 231 | 37 |  |  |  |  | 175 | require overload; | 
| 232 | 37 | 100 |  |  |  | 113 | return () unless overload::Overloaded($object); | 
| 233 | 2 |  |  |  |  | 159 | return sort grep overload::Method($object, $_), | 
| 234 |  |  |  |  |  |  | map split(/\s+/), values %overload::ops; | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | sub _show_methods { | 
| 238 | 37 |  |  | 37 |  | 93 | my ($class_name, $linear_ISA, $attributes, $ddp) = @_; | 
| 239 |  |  |  |  |  |  |  | 
| 240 | 37 |  |  |  |  | 127 | my %methods = ( public => {}, private => {} ); | 
| 241 | 37 |  |  |  |  | 107 | my @all_methods = map _methods_of( | 
| 242 |  |  |  |  |  |  | $_, Data::Printer::Common::_get_namespace($_) | 
| 243 |  |  |  |  |  |  | ), @$linear_ISA; | 
| 244 | 37 |  |  |  |  | 132 | my $show_methods   = $ddp->class->show_methods; | 
| 245 | 37 |  |  |  |  | 82 | my $show_inherited = $ddp->class->inherited; | 
| 246 | 37 |  |  |  |  | 67 | my %seen_method_name; | 
| 247 | 37 |  |  |  |  | 73 | foreach my $method (@all_methods) { | 
| 248 | 224 |  |  |  |  | 413 | my ($package_string, $method_string) = @$method; | 
| 249 | 224 | 100 |  |  |  | 421 | next if exists $attributes->{$method_string}; | 
| 250 | 222 | 100 |  |  |  | 509 | next if $seen_method_name{$method_string}++; | 
| 251 | 196 | 100 |  |  |  | 366 | next if $method_string eq '__ANON__'; # anonymous subs don't matter here. | 
| 252 | 195 | 100 |  |  |  | 392 | my $type = substr($method_string, 0, 1) eq '_' ? 'private' : 'public'; | 
| 253 | 195 | 100 |  |  |  | 384 | if ($package_string eq $class_name) { | 
| 254 | 104 | 100 | 100 |  |  | 245 | next unless $show_methods eq 'all' || $show_methods eq $type; | 
| 255 | 91 |  |  |  |  | 216 | $methods{$type}{$method_string} = undef; | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  | else { | 
| 258 | 91 | 100 | 100 |  |  | 346 | next unless $show_inherited eq 'all' || $show_inherited eq $type; | 
| 259 | 47 |  |  |  |  | 119 | $methods{$type}{$method_string} = $package_string; | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  | } | 
| 262 | 37 |  |  |  |  | 73 | my $string = ''; | 
| 263 | 37 |  |  |  |  | 75 | foreach my $type (qw(public private)) { | 
| 264 | 74 | 100 | 100 |  |  | 222 | next unless $show_methods   eq 'all' or $show_methods   eq $type | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 265 |  |  |  |  |  |  | or $show_inherited eq 'all' or $show_inherited eq $type | 
| 266 |  |  |  |  |  |  | ; | 
| 267 | 71 | 100 |  |  |  | 173 | if ($ddp->class->format_inheritance eq 'string') { | 
| 268 | 4 |  |  |  |  | 8 | my @method_list = keys %{$methods{$type}}; | 
|  | 4 |  |  |  |  | 16 |  | 
| 269 | 4 | 100 | 66 |  |  | 19 | @method_list = Data::Printer::Common::_nsort(@method_list) | 
| 270 |  |  |  |  |  |  | if @method_list && $ddp->class->sort_methods; | 
| 271 |  |  |  |  |  |  |  | 
| 272 | 4 |  |  |  |  | 14 | $string .= $ddp->newline . "$type methods (" . scalar(@method_list) . ')'; | 
| 273 | 4 | 100 |  |  |  | 15 | if (@method_list) { | 
| 274 |  |  |  |  |  |  | $string .= ': ' | 
| 275 |  |  |  |  |  |  | . join(', ' => map { | 
| 276 | 3 |  |  |  |  | 9 | $ddp->maybe_colorize( | 
| 277 | 12 | 100 |  |  |  | 45 | $_ . (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 | 67 |  |  |  |  | 108 | my %lined_methods; | 
| 287 |  |  |  |  |  |  | my @base_methods; | 
| 288 | 67 |  |  |  |  | 112 | my $total_methods = 0; | 
| 289 | 67 |  |  |  |  | 100 | foreach my $method (keys %{$methods{$type}}) { | 
|  | 67 |  |  |  |  | 221 |  | 
| 290 | 126 |  |  |  |  | 220 | my $pkg_name = $methods{$type}{$method}; | 
| 291 | 126 | 100 |  |  |  | 218 | if (defined $pkg_name) { | 
| 292 | 41 |  |  |  |  | 56 | push @{ $lined_methods{$pkg_name} }, $method; | 
|  | 41 |  |  |  |  | 95 |  | 
| 293 |  |  |  |  |  |  | } | 
| 294 |  |  |  |  |  |  | else { | 
| 295 | 85 |  |  |  |  | 143 | push @base_methods, $method; | 
| 296 |  |  |  |  |  |  | } | 
| 297 | 126 |  |  |  |  | 221 | $total_methods++; | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | # then we print them, starting with our own methods: | 
| 301 | 67 | 100 | 66 |  |  | 211 | @base_methods = Data::Printer::Common::_nsort(@base_methods) | 
| 302 |  |  |  |  |  |  | if @base_methods && $ddp->class->sort_methods; | 
| 303 |  |  |  |  |  |  |  | 
| 304 | 67 | 100 |  |  |  | 193 | $string .= $ddp->newline . "$type methods ($total_methods)" | 
| 305 |  |  |  |  |  |  | . ($total_methods ? ':' : '') | 
| 306 |  |  |  |  |  |  | ; | 
| 307 | 67 | 100 |  |  |  | 188 | if (@base_methods) { | 
| 308 |  |  |  |  |  |  | my $base_string = join(', ' => map { | 
| 309 | 39 |  |  |  |  | 69 | $ddp->maybe_colorize($_, 'method') | 
|  | 85 |  |  |  |  | 184 |  | 
| 310 |  |  |  |  |  |  | } @base_methods); | 
| 311 | 39 |  |  |  |  | 126 | $ddp->indent; | 
| 312 |  |  |  |  |  |  | # newline only if we have parent methods to show: | 
| 313 | 39 | 100 |  |  |  | 119 | $string .= (keys %lined_methods ? $ddp->newline : ' ') . $base_string; | 
| 314 | 39 |  |  |  |  | 94 | $ddp->outdent; | 
| 315 |  |  |  |  |  |  | } | 
| 316 | 67 |  |  |  |  | 227 | foreach my $pkg (sort keys %lined_methods) { | 
| 317 | 22 |  |  |  |  | 63 | $ddp->indent; | 
| 318 | 22 |  |  |  |  | 48 | $string .= $ddp->newline . "$pkg:"; | 
| 319 | 22 | 50 |  |  |  | 58 | @{$lined_methods{$pkg}} = Data::Printer::Common::_nsort(@{$lined_methods{$pkg}}) | 
|  | 22 |  |  |  |  | 55 |  | 
|  | 22 |  |  |  |  | 72 |  | 
| 320 |  |  |  |  |  |  | if $ddp->class->sort_methods; | 
| 321 | 22 |  |  |  |  | 73 | $ddp->indent; | 
| 322 |  |  |  |  |  |  | $string .= $ddp->newline . join(', ' => map { | 
| 323 | 41 |  |  |  |  | 86 | $ddp->maybe_colorize($_, 'method') | 
| 324 | 22 |  |  |  |  | 48 | } @{$lined_methods{$pkg}} | 
|  | 22 |  |  |  |  | 49 |  | 
| 325 |  |  |  |  |  |  | ); | 
| 326 | 22 |  |  |  |  | 70 | $ddp->outdent; | 
| 327 | 22 |  |  |  |  | 46 | $ddp->outdent; | 
| 328 |  |  |  |  |  |  | } | 
| 329 |  |  |  |  |  |  | } | 
| 330 |  |  |  |  |  |  | } | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 37 |  |  |  |  | 237 | return $string; | 
| 333 |  |  |  |  |  |  | } | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | sub _methods_of { | 
| 336 | 70 |  |  | 70 |  | 310 | require B; | 
| 337 | 70 |  |  |  |  | 173 | my ($class_name, $namespace) = @_; | 
| 338 | 70 |  |  |  |  | 113 | my @methods; | 
| 339 | 70 |  |  |  |  | 148 | foreach my $subref (_get_all_subs_from($class_name, $namespace)) { | 
| 340 | 224 | 50 |  |  |  | 461 | next unless $subref; | 
| 341 | 224 |  |  |  |  | 588 | my $m = B::svref_2object($subref); | 
| 342 | 224 | 50 | 33 |  |  | 938 | next unless $m && $m->isa('B::CV'); | 
| 343 | 224 |  |  |  |  | 570 | my $gv = $m->GV; | 
| 344 | 224 | 50 | 33 |  |  | 1376 | next unless $gv && !$gv->isa('B::Special') && $gv->NAME; | 
|  |  |  | 33 |  |  |  |  | 
| 345 | 224 |  |  |  |  | 1124 | push @methods, [ $gv->STASH->NAME, $gv->NAME ]; | 
| 346 |  |  |  |  |  |  | } | 
| 347 | 70 |  |  |  |  | 261 | return @methods; | 
| 348 |  |  |  |  |  |  | } | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  | sub _get_all_subs_from { | 
| 351 | 70 |  |  | 70 |  | 128 | my ($class_name, $namespace) = @_; | 
| 352 | 70 |  |  |  |  | 99 | my @subs; | 
| 353 | 70 |  |  |  |  | 233 | foreach my $key (keys %$namespace) { | 
| 354 |  |  |  |  |  |  | # perlsub says any sub starting with '(' is reserved for overload, | 
| 355 |  |  |  |  |  |  | # so we skip those: | 
| 356 | 511 | 100 |  |  |  | 1083 | next if substr($key, 0, 1) eq '('; | 
| 357 | 502 | 100 | 66 |  |  | 1146 | 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 | 502 |  |  |  |  | 2064 | || defined(*{$namespace->{$key}}{CODE}) | 
| 362 |  |  |  |  |  |  | ) { | 
| 363 | 224 |  |  |  |  | 754 | push @subs, $key; | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  | } | 
| 366 | 70 |  |  |  |  | 134 | my @symbols; | 
| 367 | 70 |  |  |  |  | 128 | foreach my $sub (@subs) { | 
| 368 | 224 |  |  |  |  | 489 | push @symbols, Data::Printer::Common::_get_symbol($class_name, $namespace, $sub, 'CODE'); | 
| 369 |  |  |  |  |  |  | } | 
| 370 | 70 |  |  |  |  | 180 | return @symbols; | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | 1; |