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 108     108   2103 use 5.010001;
  108         392  
2 108     108   571 use strict;
  108         271  
  108         2754  
3 108     108   547 use warnings;
  108         219  
  108         5071  
4              
5             use Mite::Miteception -role, -all;
6 108     108   672  
  108         313  
  108         986  
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.010008';
9              
10             requires qw( _function_for_croak );
11              
12             BEGIN {
13             *_CONSTANTS_DEFLATE = "$]" >= 5.012 && "$]" < 5.020 ? \&true : \&false;
14 108 50 33 108   18444 };
15              
16             has method_signatures =>
17             is => ro,
18             isa => Map[ MethodName, MiteSignature ],
19             builder => sub { {} };
20 162     162   417  
21             my ( $self, $method_name, %opts ) = @_;
22              
23 8     8 0 34 defined $self->method_signatures->{ $method_name }
24             and croak( 'Method signature for %s already exists', $method_name );
25 8 50       53  
26             require Mite::Signature;
27             $self->method_signatures->{ $method_name } = 'Mite::Signature'->new(
28 8         3030 method_name => $method_name,
29 8         68 class => $self,
30             %opts,
31             );
32              
33             return;
34             }
35 8         27  
36             my $self = shift;
37             my $package = $self->name;
38             no strict 'refs';
39 155     155   335 my $stash = \%{"$package\::"};
40 155         573 return {
41 108     108   779 map {;
  108         223  
  108         43116  
42 155         273 # this is an ugly hack to populate the scalar slot of any globs, to
  155         639  
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 118         166 }
51             grep exists &{"${package}::${_}"},
52 118         157 grep !/::\z/,
  118         567  
53             keys %$stash
54 155         1165 };
  1233         2607  
55             }
56              
57             my $self = shift;
58             my %methods = %{ $self->_all_subs };
59              
60             require B;
61 155     155 0 329 for my $name ( sort keys %methods ) {
62 155         247 my $cv = B::svref_2object( $methods{$name} );
  155         546  
63             my $stashname = eval { $cv->GV->STASH->NAME };
64 155         914 $stashname eq $self->name
65 155         617 or $stashname eq 'constant'
66 118         462 or delete $methods{$name};
67 118         190 }
  118         1215  
68              
69             delete $methods{meta};
70 118 100 66     605  
71             return \%methods;
72             }
73 155         346  
74             before inject_mite_functions => sub {
75 155         592 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 108     108   796 *{ $package .'::signature_for' } = sub {
  108         271  
  108         54246  
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 131     131   297  
138 131 100       266 for my $name ( sort keys %sigs ) {
  131         2810  
139             my $guard = $sigs{$name}->locally_set_compiling_class( $self );
140 9         20  
141             $code .= sprintf(
142             '$SIGNATURE_FOR{%s} = %s;' . "\n\n",
143 9         42 B::perlstring( $name ),
144 10         49 $sigs{$name}->_compile_coderef,
145             );
146              
147             if ( my $support = $sigs{$name}->_compile_support ) {
148             $code .= "$support\n\n";
149 10         70 }
150             }
151              
152 10 100       64 return $code;
153 5         1032 }
154              
155             1;