File Coverage

blib/lib/Kavorka/ReturnType.pm
Criterion Covered Total %
statement 73 74 98.6
branch 6 14 42.8
condition 1 3 33.3
subroutine 15 15 100.0
pod 0 6 0.0
total 95 112 84.8


line stmt bran cond sub pod time code
1 38     38   751 use 5.014;
  38         88  
2 38     38   144 use strict;
  38         47  
  38         823  
3 38     38   120 use warnings;
  38         45  
  38         3052  
4              
5             package Kavorka::ReturnType;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.037';
9             our @CARP_NOT = qw( Kavorka::Signature Kavorka::Sub Kavorka );
10              
11 38     38   152 use Carp qw( croak );
  38         42  
  38         2000  
12 38     38   154 use Parse::Keyword {};
  38         42  
  38         274  
13 38     38   3706 use Parse::KeywordX qw(parse_trait);
  38         50  
  38         293  
14              
15 38     38   6619 use Moo;
  38         51  
  38         189  
16 38     38   15281 use namespace::sweep;
  38         61  
  38         274  
17              
18             has package => (is => 'ro');
19             has type => (is => 'ro');
20             has traits => (is => 'ro', default => sub { +{} });
21              
22 6     6 0 35 sub coerce { !!shift->traits->{coerce} }
23 8     8 0 30 sub list { !!shift->traits->{list} }
24 7     7 0 33 sub assumed { !!shift->traits->{assumed} }
25              
26             sub BUILD
27             {
28 4     4 0 426 my $self = shift;
29            
30             # traits handled natively
31 4         14 state $native_traits = {
32             coerce => 1,
33             list => 1,
34             scalar => 1,
35             };
36            
37             my @custom_traits =
38             map "Kavorka::TraitFor::ReturnType::$_",
39             grep !exists($native_traits->{$_}),
40 4         6 keys %{$self->traits};
  4         28  
41            
42 4 50       112 'Moo::Role'->apply_roles_to_object($self, @custom_traits) if @custom_traits;
43             }
44              
45             sub parse
46             {
47 4     4 0 50 my $class = shift;
48 4         13 my %args = @_;
49            
50 4         7 lex_read_space;
51            
52 4         7 my %traits = ();
53            
54 4         3 my $type;
55 4         9 my $peek = lex_peek(1000);
56 4 100       23 if ($peek =~ /\A[^\W0-9]/)
    50          
57             {
58 3         3 my $reg = do {
59 3         531 require Type::Registry;
60 3         9286 require Type::Utils;
61 3         25907 my $tmp = 'Type::Registry::DWIM'->new;
62 3         25 $tmp->{'~~chained'} = $args{package};
63 3         7 $tmp->{'~~assume'} = 'Type::Tiny::Class';
64 3         4 $tmp;
65             };
66            
67 3         18 require Type::Parser;
68 3         11 ($type, my($remaining)) = Type::Parser::extract_type($peek, $reg);
69 3         51135 my $len = length($peek) - length($remaining);
70 3         18 lex_read($len);
71 3         22 lex_read_space;
72             }
73             elsif ($peek =~ /\A\(/)
74             {
75 1         3 lex_read(1);
76 1         3 lex_read_space;
77 1 0       41 my $expr = parse_listexpr
78             or croak('Could not parse type constraint expression as listexpr');
79 1         4 lex_read_space;
80 1 0       3 lex_peek eq ')'
81             or croak("Expected ')' after type constraint expression");
82 1         4 lex_read(1);
83 1         1 lex_read_space;
84            
85 1         6 require Types::TypeTiny;
86 1         4 $type = Types::TypeTiny::to_TypeTiny( scalar $expr->() );
87 1 50       9 $type->isa('Type::Tiny')
88             or croak("Type constraint expression did not return a blessed type constraint object");
89             }
90             else
91             {
92 0         0 croak("Expected return type!");
93             }
94            
95 4         15 undef($peek);
96            
97 4         24 while (lex_peek(5) =~ m{ \A (is|does|but) \s }xsm)
98             {
99 2         10 lex_read(length($1));
100 2         4 lex_read_space;
101 2         8 my ($name, undef, $args) = parse_trait;
102 2         5 $traits{$name} = $args;
103 2         10 lex_read_space;
104             }
105            
106 4         145 return $class->new(
107             %args,
108             type => $type,
109             traits => \%traits,
110             );
111             }
112              
113             sub sanity_check
114             {
115 4     4 0 5 my $self = shift;
116            
117 4 50 33     10 croak("Return type cannot coerce and be assumed")
118             if $self->assumed && $self->coerce;
119            
120 4         9 ();
121             }
122              
123             sub _effective_type
124             {
125 4     4   6 my $self = shift;
126 4         30 $self->type;
127             }
128              
129             1;