File Coverage

blib/lib/perl5i/2/Meta.pm
Criterion Covered Total %
statement 72 73 98.6
branch 24 26 92.3
condition 8 8 100.0
subroutine 14 14 100.0
pod 0 8 0.0
total 118 129 91.4


line stmt bran cond sub pod time code
1             package perl5i::2::Meta;
2              
3 103     103   666 use strict;
  103         285  
  103         5726  
4 103     103   858 use warnings;
  103         425  
  103         8997  
5 103     103   2667 use 5.010_000;
  103         375  
  103         10113  
6              
7             # Be very careful not to import anything.
8             require Carp::Fix::1_25;
9             require mro;
10              
11             require perl5i::2::Meta::Instance;
12             require perl5i::2::Meta::Class;
13 103     103   664 use perl5i::2::autobox;
  103         421  
  103         1564  
14              
15             sub UNIVERSAL::mo {
16             # Be careful to pass through an alias, not a copy
17 224     224 0 264279 return perl5i::2::Meta::Instance->new($_[0]);
18             }
19              
20             sub UNIVERSAL::mc {
21 54     54 0 16101 return perl5i::2::Meta::Class->new($_[0]);
22             }
23              
24             sub new {
25 278     278 0 467 my $class = shift;
26             # Be careful to take a reference to an alias, not a copy
27 278         2075 return bless \\$_[0], $class;
28             }
29              
30             sub ISA {
31 6     6 0 25 my $class = $_[0]->class;
32              
33 103     103   122551 no strict 'refs';
  103         254  
  103         108237  
34 6 100       17 return wantarray ? @{$class.'::ISA'} : \@{$class.'::ISA'};
  5         45  
  1         11  
35             }
36              
37             sub linear_isa {
38 23     23 0 39 my $self = shift;
39 23         96 my $class = $self->class;
40              
41             # get_linear_isa() does not return UNIVERSAL
42 23         36 my @extra;
43 23 100       80 @extra = qw(UNIVERSAL) unless $class eq 'UNIVERSAL';
44              
45 23         27 my $isa = [@{mro::get_linear_isa($class)}, @extra];
  23         136  
46 23 100       161 return wantarray ? @$isa : $isa;
47             }
48              
49             sub methods {
50 12     12 0 14 my $self = shift;
51 12   100     86 my $opts = shift // {};
52 12         53 my $top = $self->class;
53              
54 12         22 my %exclude;
55              
56 12         22 state $defaults = {
57             with_UNIVERSAL => 0,
58             just_mine => 0,
59             };
60              
61 12         47 $opts = { %$defaults, %$opts };
62 12         36 $exclude{UNIVERSAL} = !$opts->{with_UNIVERSAL};
63              
64 12 100       63 my @classes = $opts->{just_mine} ? $self->class : $self->linear_isa;
65              
66 12         18 my %all_methods;
67 12         22 for my $class (@classes) {
68 26 100 100     101 next if $exclude{$class} && $class ne $top;
69              
70 18         77 my $sym_table = $class->mc->symbol_table;
71 18         282 for my $name (keys %$sym_table) {
72 1041         2216 my $glob = $sym_table->{$name};
73 1041 50       2032 next unless ref \$glob eq "GLOB";
74 1041 100       1133 next unless my $code = *{$glob}{CODE};
  1041         3458  
75 319         1547 my $sig = $code->signature;
76 319 100 100     889 next if $sig and !$sig->is_method;
77 313         866 $all_methods{$name} = $class;
78             }
79             }
80              
81 12 100       241 return wantarray ? keys %all_methods : [keys %all_methods];
82             }
83              
84             sub symbol_table {
85 19     19 0 27 my $self = shift;
86 19         57 my $class = $self->class;
87              
88 103     103   836 no strict 'refs';
  103         248  
  103         93264  
89 19         38 return \%{$class.'::'};
  19         72  
90             }
91              
92             # A single place to put the "method not found" error.
93             my $method_not_found = sub {
94             my $class = shift;
95             my $method = shift;
96              
97             Carp::Fix::1_25::croak(
98             sprintf q[Can't locate object method "%s" via package "%s"],
99             $method, $class
100             );
101             };
102              
103              
104             # caller() will return if its inside an eval, need to skip over those.
105             my $find_method = sub {
106             my $method;
107             my $height = 2;
108             do {
109             $method = (caller($height))[3];
110             $height++;
111             } until( !defined $method or $method ne '(eval)' );
112              
113             return $method;
114             };
115              
116              
117             sub super {
118 10     10 0 13 my $self = shift;
119 10         32 my $class = $self->class;
120              
121 10         27 my $fq_method = $find_method->();
122 10 100       189 Carp::Fix::1_25::croak("super() called outside a method") unless $fq_method;
123              
124 9         68 my($parent, $method) = $fq_method =~ /^(.*)::(\w+)$/;
125              
126 9 100       253 Carp::Fix::1_25::croak(
127             sprintf qq["%s" is not a parent class of "%s"],
128             $parent, $class
129             ) unless $class->isa($parent);
130              
131 8         22 my @isa = $self->linear_isa();
132              
133 8         22 while(@isa) {
134 12         20 my $class = shift @isa;
135 12 100       34 last if $class eq $parent;
136             }
137              
138 8         12 for (@isa) {
139 8         49 my $code = $_->can($method);
140 8         25 @_ = ($$$self, @_);
141 8 50       52 goto &$code if $code;
142             }
143              
144 0           $class->$method_not_found($method);
145             }
146              
147             1;