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   2500 use 5.010001;
  109         486  
2 109     109   722 use strict;
  109         4187  
  109         3281  
3 109     109   718 use warnings;
  109         314  
  109         6020  
4              
5             package Mite::Trait::HasMethods;
6 109     109   759 use Mite::Miteception -role, -all;
  109         361  
  109         1099  
7              
8             our $AUTHORITY = 'cpan:TOBYINK';
9             our $VERSION = '0.012000';
10              
11             requires qw( _function_for_croak );
12              
13             BEGIN {
14 109 50 33 109   22229 *_CONSTANTS_DEFLATE = "$]" >= 5.012 && "$]" < 5.020 ? \&true : \&false;
15             };
16              
17             has method_signatures =>
18             is => ro,
19             isa => Map[ MethodName, MiteSignature ],
20 155     155   573 builder => sub { {} };
21              
22             sub add_method_signature {
23 8     8 0 48 my ( $self, $method_name, %opts ) = @_;
24              
25 8 50       71 defined $self->method_signatures->{ $method_name }
26             and croak( 'Method signature for %s already exists', $method_name );
27              
28 8         3382 require Mite::Signature;
29 8         101 $self->method_signatures->{ $method_name } = 'Mite::Signature'->new(
30             method_name => $method_name,
31             class => $self,
32             %opts,
33             );
34              
35 8         28 return;
36             }
37              
38             sub _all_subs {
39 147     147   373 my $self = shift;
40 147         651 my $package = $self->name;
41 109     109   948 no strict 'refs';
  109         332  
  109         53694  
42 147         339 my $stash = \%{"$package\::"};
  147         745  
43             return {
44             map {;
45             # this is an ugly hack to populate the scalar slot of any globs, to
46             # prevent perl from converting constants back into scalar refs in the
47             # stash when they are used (perl 5.12 - 5.18). scalar slots on their own
48             # aren't detectable through pure perl, so this seems like an acceptable
49             # compromise.
50 120         195 ${"${package}::${_}"} = ${"${package}::${_}"}
51             if _CONSTANTS_DEFLATE;
52 120         214 $_ => \&{"${package}::${_}"}
  120         680  
53             }
54 147         1414 grep exists &{"${package}::${_}"},
  1234         3640  
55             grep !/::\z/,
56             keys %$stash
57             };
58             }
59              
60             sub native_methods {
61 147     147 0 351 my $self = shift;
62 147         350 my %methods = %{ $self->_all_subs };
  147         690  
63              
64 147         1029 require B;
65 147         704 for my $name ( sort keys %methods ) {
66 120         577 my $cv = B::svref_2object( $methods{$name} );
67 120         258 my $stashname = eval { $cv->GV->STASH->NAME };
  120         1478  
68             $stashname eq $self->name
69             or $stashname eq 'constant'
70 120 100 66     752 or delete $methods{$name};
71             }
72              
73 147         411 delete $methods{meta};
74              
75 147         689 return \%methods;
76             }
77              
78             before inject_mite_functions => sub {
79             my ( $self, $file, $arg ) = ( shift, @_ );
80              
81             my $requested = sub { $arg->{$_[0]} ? 1 : $arg->{'!'.$_[0]} ? 0 : $arg->{'-all'} ? 1 : $_[1]; };
82             my $defaults = ! $arg->{'!-defaults'};
83             my $shim = $self->shim_name;
84             my $package = $self->name;
85             my $kind = $self->kind;
86             my $parse_mm_args = $shim->can( '_parse_mm_args' ) || \&Mite::Shim::_parse_mm_args;
87              
88 109     109   1003 no strict 'refs';
  109         387  
  109         65883  
89              
90             if ( $requested->( 'signature_for', $defaults ) ) {
91              
92             *{ $package .'::signature_for' } = sub {
93 0     0     my $name = shift;
94 0 0         if ( $name =~ /^\+/ ) {
95 0           $name =~ s/^\+//;
96 0           $self->extend_method_signature( $name, @_ );
97             }
98             else {
99 0           $self->add_method_signature( $name, @_ );
100             }
101 0           return;
102             };
103              
104             $self->imported_keywords->{signature_for} =
105             sprintf 'sub { $SHIM->HANDLE_signature_for( $CALLER, %s, @_ ) }',
106             B::perlstring( $kind );
107             }
108              
109             for my $modifier ( qw( before after around ) ) {
110              
111             $requested->( $modifier, $defaults ) or next;
112              
113             *{ $package .'::'. $modifier } = sub {
114 0     0     my ( $names, $coderef ) = &$parse_mm_args;
115 0 0         CodeRef->check( $coderef )
116             or croak "Expected a coderef method modifier";
117 0 0 0       ArrayRef->of(Str)->check( $names ) && @$names
118             or croak "Expected a list of method names to modify";
119 0 0         $self->add_required_methods( @$names ) if $kind eq 'role';
120 0           return;
121             };
122              
123             $self->imported_keywords->{$modifier} =
124             sprintf 'sub { $SHIM->HANDLE_%s( $CALLER, %s, @_ ) }',
125             $modifier, B::perlstring( $kind );
126             }
127             };
128              
129             around compilation_stages => sub {
130             my ( $next, $self ) = ( shift, shift );
131             my @stages = $self->$next( @_ );
132             push @stages, '_compile_method_signatures';
133             return @stages;
134             };
135              
136             sub _compile_method_signatures {
137 123     123   367 my $self = shift;
138 123 100       298 my %sigs = %{ $self->method_signatures } or return;
  123         3190  
139              
140 9         30 my $code = "# Method signatures\n"
141             . "our \%SIGNATURE_FOR;\n\n";
142              
143 9         51 for my $name ( sort keys %sigs ) {
144 10         48 my $guard = $sigs{$name}->locally_set_compiling_class( $self );
145              
146             $code .= sprintf(
147             '$SIGNATURE_FOR{%s} = %s;' . "\n\n",
148             B::perlstring( $name ),
149 10         82 $sigs{$name}->_compile_coderef,
150             );
151              
152 10 100       83 if ( my $support = $sigs{$name}->_compile_support ) {
153 5         1368 $code .= "$support\n\n";
154             }
155             }
156              
157 9         319 return $code;
158             }
159              
160             1;