File Coverage

blib/lib/Mite/Signature.pm
Criterion Covered Total %
statement 54 63 85.7
branch 27 40 67.5
condition 16 29 55.1
subroutine 12 12 100.0
pod 0 3 0.0
total 109 147 74.1


line stmt bran cond sub pod time code
1 12     12   295 use 5.010001;
  12         51  
2 12     12   78 use strict;
  12         37  
  12         280  
3 12     12   70 use warnings;
  12         36  
  12         610  
4              
5             package Mite::Signature;
6 12     12   81 use Mite::Miteception -all;
  12         33  
  12         117  
7              
8             our $AUTHORITY = 'cpan:TOBYINK';
9             our $VERSION = '0.012000';
10              
11             has class =>
12             is => ro,
13             isa => MitePackage,
14             weak_ref => true;
15              
16             has compiling_class =>
17             init_arg => undef,
18             is => rw,
19             isa => MitePackage,
20             local_writer => true;
21              
22             has method_name =>
23             is => ro,
24             isa => Str,
25             required => true;
26              
27             has named =>
28             is => ro,
29             isa => ArrayRef->plus_coercions( HashRef, q([%$_]) ),
30             predicate => 'is_named';
31              
32             has positional =>
33             is => ro,
34             isa => ArrayRef,
35             alias => 'pos',
36             predicate => 'is_positional';
37              
38             has method =>
39             is => 'ro',
40             isa => Bool,
41             default => true;
42              
43             has head =>
44             is => lazy,
45             isa => ArrayRef | Int,
46 8 100   8   82 builder => sub { shift->method ? [ Defined, { name => 'invocant' } ] : [] };
47              
48             has tail =>
49             is => ro,
50             isa => ArrayRef | Int;
51              
52             has named_to_list =>
53             is => ro,
54             isa => Bool | ArrayRef,
55             default => false;
56              
57             has compiler =>
58             init_arg => undef,
59             is => lazy,
60             isa => Object,
61             builder => true,
62             handles => [ qw( has_head has_tail has_slurpy ) ];
63              
64             has should_bless =>
65             init_arg => undef,
66             is => lazy,
67             isa => Bool,
68 9   100 9   97 builder => sub { !!( $_[0]->is_named && !$_[0]->named_to_list ) };
69              
70             sub BUILD {
71 9     9 0 20 my $self = shift;
72              
73 9 50 66     90 croak 'Method cannot be both named and positional'
74             if $self->is_named && $self->is_positional;
75             }
76              
77             sub autolax {
78 9     9 0 21 my $self = shift;
79              
80 9   66     33 my $class = $self->compiling_class || $self->class;
81 9 50       30 return if not $class;
82 9 50       21 return if not eval { $class->project->config->data->{autolax} };
  9         50  
83 0         0 return sprintf '%s::STRICT', $class->project->config->data->{shim};
84             }
85              
86             sub _build_compiler {
87 9     9   38 my $self = shift;
88              
89 9         20 local $Type::Tiny::AvoidCallbacks = 1;
90 9         57 local $Type::Tiny::SafePackage = sprintf( 'package %s;', $self->class->shim_name );
91              
92 9         3363 require Mite::Signature::Compiler;
93             my $c = 'Mite::Signature::Compiler'->new_from_compile(
94             $self->is_named ? 'named' : 'positional',
95             {
96             package => $self->class->name,
97             subname => $self->method_name,
98             ( $self->head ? ( head => $self->head ) : () ),
99             ( $self->tail ? ( tail => $self->tail ) : () ),
100             named_to_list => $self->named_to_list,
101             strictness => scalar( $self->autolax // 1 ),
102             goto_next => true,
103             mite_signature => $self,
104             $self->should_bless
105             ? ( bless => sprintf '%s::__NAMED_ARGUMENTS__::%s', $self->class->name, $self->method_name )
106             : (),
107             },
108             $self->is_named
109 6         61 ? @{ $self->named }
110 9 100 50     155 : @{ $self->positional },
  3 50       59  
    50          
    100          
    100          
111             );
112              
113 9         10172 $c->coderef;
114              
115 9 50       1294 if ( keys %{ $c->coderef->{env} } ) {
  9         41  
116 0         0 croak "Signature could not be inlined properly; bailing out";
117             }
118              
119 9         86 return $c;
120             }
121              
122             sub _compile_coderef {
123 10     10   21 my $self = shift;
124              
125 10 100 66     38 if ( $self->compiling_class and $self->compiling_class != $self->class ) {
126 1         31 return sprintf( '$%s::SIGNATURE_FOR{%s}', $self->class->name, B::perlstring( $self->method_name ) );
127             }
128              
129 9         41 my $code = $self->compiler->coderef->code;
130 9         1764 $code =~ s/^\s+|\s+$//gs;
131              
132 9         141 return $code;
133             }
134              
135             sub _compile_support {
136 10     10   30 my $self = shift;
137              
138 10 100 66     35 if ( $self->compiling_class and $self->compiling_class != $self->class ) {
139 1         6 return;
140             }
141              
142 9 100       53 return unless $self->should_bless;
143 5         19 return $self->compiler->make_class_pp_code;
144             }
145              
146             sub clone {
147 1     1 0 3 my ( $self, %args ) = @_;
148              
149             # alias
150 1 50       4 $args{positional} = $args{pos} if exists $args{pos};
151              
152 1 50 33     3 if ( $self->has_slurpy and $args{positional} ) {
    50 33        
    50 33        
    50 33        
153 0         0 croak "Cannot add new positional parameters when extending an existing signature with a slurpy parameter";
154             }
155             elsif ( $self->has_slurpy and $args{named} ) {
156 0         0 croak "Cannot add new named parameters when extending an existing signature with a slurpy parameter";
157             }
158             elsif ( $self->is_named and $args{positional} ) {
159 0         0 croak "Cannot add positional parameters when extending an existing signature which has named parameters";
160             }
161             elsif ( !$self->is_named and $args{named} ) {
162 0         0 croak "Cannot add named parameters when extending an existing signature which has positional parameters";
163             }
164              
165 1 50       38 if ( $args{positional} ) {
166 0         0 $args{positional} = [ @{ $self->positional }, @{ $args{positional} } ];
  0         0  
  0         0  
167             }
168              
169 1 50       6 if ( $args{named} ) {
170 1         2 $args{named} = [ @{ $self->named }, @{ $args{named} } ];
  1         5  
  1         4  
171             }
172              
173 1         11 my %new_args = ( %$self, %args );
174              
175             # Rebuild these
176 1         4 delete $new_args{compiler};
177 1         2 delete $new_args{should_bless};
178              
179 1         13 return __PACKAGE__->new( %new_args );
180             }
181              
182             1;