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 101     101   491 use strict;
  101         177  
  101         3743  
4 101     101   428 use warnings;
  101         156  
  101         2658  
5 101     101   1923 use 5.010_000;
  101         277  
  101         12209  
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 101     101   508 use perl5i::2::autobox;
  101         173  
  101         833  
14              
15             sub UNIVERSAL::mo {
16             # Be careful to pass through an alias, not a copy
17 221     221 0 78778 return perl5i::2::Meta::Instance->new($_[0]);
18             }
19              
20             sub UNIVERSAL::mc {
21 48     48 0 8693 return perl5i::2::Meta::Class->new($_[0]);
22             }
23              
24             sub new {
25 269     269 0 332 my $class = shift;
26             # Be careful to take a reference to an alias, not a copy
27 269         1359 return bless \\$_[0], $class;
28             }
29              
30             sub ISA {
31 6     6 0 21 my $class = $_[0]->class;
32              
33 101     101   64439 no strict 'refs';
  101         194  
  101         35714  
34 6 100       14 return wantarray ? @{$class.'::ISA'} : \@{$class.'::ISA'};
  5         33  
  1         10  
35             }
36              
37             sub linear_isa {
38 20     20 0 17 my $self = shift;
39 20         44 my $class = $self->class;
40              
41             # get_linear_isa() does not return UNIVERSAL
42 20         21 my @extra;
43 20 100       51 @extra = qw(UNIVERSAL) unless $class eq 'UNIVERSAL';
44              
45 20         17 my $isa = [@{mro::get_linear_isa($class)}, @extra];
  20         88  
46 20 100       84 return wantarray ? @$isa : $isa;
47             }
48              
49             sub methods {
50 9     9 0 9 my $self = shift;
51 9   100     32 my $opts = shift // {};
52 9         25 my $top = $self->class;
53              
54 9         10 my %exclude;
55              
56 9         12 state $defaults = {
57             with_UNIVERSAL => 0,
58             just_mine => 0,
59             };
60              
61 9         32 $opts = { %$defaults, %$opts };
62 9         23 $exclude{UNIVERSAL} = !$opts->{with_UNIVERSAL};
63              
64 9 100       29 my @classes = $opts->{just_mine} ? $self->class : $self->linear_isa;
65              
66 9         9 my %all_methods;
67 9         14 for my $class (@classes) {
68 18 100 100     51 next if $exclude{$class} && $class ne $top;
69              
70 13         43 my $sym_table = $class->mc->symbol_table;
71 13         101 for my $name (keys %$sym_table) {
72 352         528 my $glob = $sym_table->{$name};
73 352 50       475 next unless ref \$glob eq "GLOB";
74 352 100       222 next unless my $code = *{$glob}{CODE};
  352         734  
75 206         579 my $sig = $code->signature;
76 206 100 100     408 next if $sig and !$sig->is_method;
77 205         331 $all_methods{$name} = $class;
78             }
79             }
80              
81 9 100       121 return wantarray ? keys %all_methods : [keys %all_methods];
82             }
83              
84             sub symbol_table {
85 14     14 0 13 my $self = shift;
86 14         68 my $class = $self->class;
87              
88 101     101   508 no strict 'refs';
  101         158  
  101         40663  
89 14         16 return \%{$class.'::'};
  14         41  
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 11 my $self = shift;
119 10         19 my $class = $self->class;
120              
121 10         21 my $fq_method = $find_method->();
122 10 100       230 Carp::Fix::1_25::croak("super() called outside a method") unless $fq_method;
123              
124 9         52 my($parent, $method) = $fq_method =~ /^(.*)::(\w+)$/;
125              
126 9 100       155 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         16 my @isa = $self->linear_isa();
132              
133 8         17 while(@isa) {
134 12         13 my $class = shift @isa;
135 12 100       23 last if $class eq $parent;
136             }
137              
138 8         12 for (@isa) {
139 8         35 my $code = $_->can($method);
140 8         15 @_ = ($$$self, @_);
141 8 50       33 goto &$code if $code;
142             }
143              
144 0           $class->$method_not_found($method);
145             }
146              
147             1;