File Coverage

blib/lib/Mite/Trait/HasMethods.pm
Criterion Covered Total %
statement 54 65 83.0
branch 8 18 44.4
condition 3 9 33.3
subroutine 12 14 85.7
pod 0 2 0.0
total 77 108 71.3


line stmt bran cond sub pod time code
1 109     109   2523 use 5.010001;
  109         430  
2 109     109   666 use strict;
  109         3838  
  109         2996  
3 109     109   643 use warnings;
  109         292  
  109         5570  
4              
5             use Mite::Miteception -role, -all;
6 109     109   771  
  109         277  
  109         918  
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.011000';
9              
10             requires qw( _function_for_croak );
11              
12             BEGIN {
13             *_CONSTANTS_DEFLATE = "$]" >= 5.012 && "$]" < 5.020 ? \&true : \&false;
14 109 50 33 109   20753 };
15              
16             has method_signatures =>
17             is => ro,
18             isa => Map[ MethodName, MiteSignature ],
19             builder => sub { {} };
20 154     154   530  
21             my ( $self, $method_name, %opts ) = @_;
22              
23 8     8 0 46 defined $self->method_signatures->{ $method_name }
24             and croak( 'Method signature for %s already exists', $method_name );
25 8 50       73  
26             require Mite::Signature;
27             $self->method_signatures->{ $method_name } = 'Mite::Signature'->new(
28 8         3331 method_name => $method_name,
29 8         80 class => $self,
30             %opts,
31             );
32              
33             return;
34             }
35 8         38  
36             my $self = shift;
37             my $package = $self->name;
38             no strict 'refs';
39 147     147   356 my $stash = \%{"$package\::"};
40 147         620 return {
41 109     109   1233 map {;
  109         333  
  109         50267  
42 147         316 # this is an ugly hack to populate the scalar slot of any globs, to
  147         694  
43             # prevent perl from converting constants back into scalar refs in the
44             # stash when they are used (perl 5.12 - 5.18). scalar slots on their own
45             # aren't detectable through pure perl, so this seems like an acceptable
46             # compromise.
47             ${"${package}::${_}"} = ${"${package}::${_}"}
48             if _CONSTANTS_DEFLATE;
49             $_ => \&{"${package}::${_}"}
50 120         188 }
51             grep exists &{"${package}::${_}"},
52 120         204 grep !/::\z/,
  120         638  
53             keys %$stash
54 147         1406 };
  1234         3083  
55             }
56              
57             my $self = shift;
58             my %methods = %{ $self->_all_subs };
59              
60             require B;
61 147     147 0 330 for my $name ( sort keys %methods ) {
62 147         264 my $cv = B::svref_2object( $methods{$name} );
  147         628  
63             my $stashname = eval { $cv->GV->STASH->NAME };
64 147         1001 $stashname eq $self->name
65 147         635 or $stashname eq 'constant'
66 120         503 or delete $methods{$name};
67 120         239 }
  120         1315  
68              
69             delete $methods{meta};
70 120 100 66     648  
71             return \%methods;
72             }
73 147         415  
74             before inject_mite_functions => sub {
75 147         676 my ( $self, $file, $arg ) = ( shift, @_ );
76              
77             my $requested = sub { $arg->{$_[0]} ? 1 : $arg->{'!'.$_[0]} ? 0 : $arg->{'-all'} ? 1 : $_[1]; };
78             my $defaults = ! $arg->{'!-defaults'};
79             my $shim = $self->shim_name;
80             my $package = $self->name;
81             my $kind = $self->kind;
82             my $parse_mm_args = $shim->can( '_parse_mm_args' ) || \&Mite::Shim::_parse_mm_args;
83              
84             no strict 'refs';
85              
86             if ( $requested->( 'signature_for', $defaults ) ) {
87              
88 109     109   897 *{ $package .'::signature_for' } = sub {
  109         320  
  109         63118  
89             my $name = shift;
90             if ( $name =~ /^\+/ ) {
91             $name =~ s/^\+//;
92             $self->extend_method_signature( $name, @_ );
93 0     0     }
94 0 0         else {
95 0           $self->add_method_signature( $name, @_ );
96 0           }
97             return;
98             };
99 0            
100             $self->imported_keywords->{signature_for} =
101 0           sprintf 'sub { $SHIM->HANDLE_signature_for( $CALLER, %s, @_ ) }',
102             B::perlstring( $kind );
103             }
104              
105             for my $modifier ( qw( before after around ) ) {
106              
107             $requested->( $modifier, $defaults ) or next;
108              
109             *{ $package .'::'. $modifier } = sub {
110             my ( $names, $coderef ) = &$parse_mm_args;
111             CodeRef->check( $coderef )
112             or croak "Expected a coderef method modifier";
113             ArrayRef->of(Str)->check( $names ) && @$names
114 0     0     or croak "Expected a list of method names to modify";
115 0 0         $self->add_required_methods( @$names ) if $kind eq 'role';
116             return;
117 0 0 0       };
118              
119 0 0         $self->imported_keywords->{$modifier} =
120 0           sprintf 'sub { $SHIM->HANDLE_%s( $CALLER, %s, @_ ) }',
121             $modifier, B::perlstring( $kind );
122             }
123             };
124              
125             around compilation_stages => sub {
126             my ( $next, $self ) = ( shift, shift );
127             my @stages = $self->$next( @_ );
128             push @stages, '_compile_method_signatures';
129             return @stages;
130             };
131              
132             my $self = shift;
133             my %sigs = %{ $self->method_signatures } or return;
134              
135             my $code = "# Method signatures\n"
136             . "our \%SIGNATURE_FOR;\n\n";
137 123     123   334  
138 123 100       259 for my $name ( sort keys %sigs ) {
  123         2964  
139             my $guard = $sigs{$name}->locally_set_compiling_class( $self );
140 9         27  
141             $code .= sprintf(
142             '$SIGNATURE_FOR{%s} = %s;' . "\n\n",
143 9         45 B::perlstring( $name ),
144 10         53 $sigs{$name}->_compile_coderef,
145             );
146              
147             if ( my $support = $sigs{$name}->_compile_support ) {
148             $code .= "$support\n\n";
149 10         72 }
150             }
151              
152 10 100       73 return $code;
153 5         1303 }
154              
155             1;