File Coverage

blib/lib/Smart/Args/TypeTiny/Check.pm
Criterion Covered Total %
statement 83 83 100.0
branch 46 48 95.8
condition 3 3 100.0
subroutine 12 12 100.0
pod 0 5 0.0
total 144 151 95.3


line stmt bran cond sub pod time code
1             package Smart::Args::TypeTiny::Check;
2 17     17   195350 use strict;
  17         35  
  17         643  
3 17     17   128 use warnings;
  17         44  
  17         1018  
4 17     17   117 use Carp ();
  17         31  
  17         490  
5 17     17   85 use Scalar::Util qw/blessed/;
  17         33  
  17         2135  
6 17     17   9416 use Type::Registry;
  17         327256  
  17         193  
7 17     17   13428 use Type::Utils;
  17         448870  
  17         216  
8              
9 17     17   37666 use Exporter 'import';
  17         42  
  17         18512  
10             our @EXPORT_OK = qw/check_rule no_check_rule check_type type type_role/;
11              
12             $Carp::CarpInternal{+__PACKAGE__}++;
13              
14             my $reg = Type::Registry->for_class(__PACKAGE__);
15              
16             sub check_rule {
17 103     103 0 458259 my ($rule, $value, $exists, $name) = @_;
18              
19 103 100       346 if (ref $rule eq 'HASH') {
20 38         163 my %check = map { ($_ => undef) } keys %$rule;
  57         198  
21 38         214 delete $check{$_} for qw/isa does optional default/;
22 38 100       128 if (%check) {
23 1         191 Carp::croak("Malformed rule for '$name' (isa, does, optional, default)");
24             }
25             } else {
26 65         209 $rule = {isa => $rule};
27             }
28              
29 102 100       239 if ($exists) {
30 84 100 100     286 return $value if !defined $value && $rule->{optional};
31             } else {
32 18 100       88 if (exists $rule->{default}) {
    100          
33 8         32 my $default = $rule->{default};
34 8 100       53 $value = ref $default eq 'CODE' ? scalar $default->() : $default;
35             } elsif (!$rule->{optional}) {
36 6         1511 Carp::confess("Required parameter '$name' not passed");
37             } else {
38 4         31 return $value;
39             }
40             }
41              
42 89         192 my $type;
43 89 100       236 if (exists $rule->{isa}) {
    50          
44 87         287 $type = type($rule->{isa});
45             } elsif (exists $rule->{does}) {
46 2         10 $type = type_role($rule->{does});
47             }
48              
49 89         282 ($value, my $ok) = check_type($type, $value, $name);
50 89 100       1091 unless ($ok) {
51 22         121 Carp::confess("Type check failed in binding to parameter '\$$name'; " . $type->get_message($value));
52             }
53              
54 67         445 return $value;
55             }
56              
57             # Functions without type checking for better performance
58             sub no_check_rule {
59 25     25 0 12635 my ($rule, $value, $exists, $name) = @_;
60              
61 25 100       83 if (ref $rule eq 'HASH') {
62 15         53 my %check = map { ($_ => undef) } keys %$rule;
  27         89  
63 15         81 delete $check{$_} for qw/isa does optional default/;
64 15 100       49 if (%check) {
65 1         144 Carp::croak("Malformed rule for '$name' (isa, does, optional, default)");
66             }
67             } else {
68 10         33 $rule = {isa => $rule};
69             }
70              
71 24 100       59 if ($exists) {
72 17         84 return $value;
73             } else {
74 7 100       34 if (exists $rule->{default}) {
    100          
75 3         10 my $default = $rule->{default};
76 3 100       22 return ref $default eq 'CODE' ? scalar $default->() : $default;
77             } elsif (!$rule->{optional}) {
78 2         506 Carp::confess("Required parameter '$name' not passed");
79             } else {
80 2         10 return $value;
81             }
82             }
83             }
84              
85             sub check_type {
86 93     93 0 6656 my ($type, $value) = @_;
87 93 100       858 return ($value, 1) unless $type;
88 92 100       845 return ($value, 1) if $type->check($value);
89              
90 26 100       459 if ($type->has_coercion) {
91 4         80 my $coerced_value = $type->coerce($value);
92 4 100       3251 if ($type->check($coerced_value)) {
93 3         43 return ($coerced_value, 1);
94             }
95             }
96              
97 23         777 return ($value, 0);
98             }
99              
100             sub type {
101 92     92 0 7078 my ($type_name) = @_;
102 92 100       351 return $type_name if blessed($type_name);
103 23 100       129 if (my $type = $reg->simple_lookup($type_name)) {
104 10         242 return $type;
105             } else {
106 13         387 my $type = Type::Utils::dwim_type(
107             $type_name,
108             fallback => ['lookup_via_mouse', 'make_class_type'],
109             );
110 13         276883 $type->{display_name} = $type_name;
111 13         71 $reg->add_type($type, $type_name);
112 13         347 return $type;
113             }
114             }
115              
116             sub type_role {
117 3     3 0 3400 my ($type_name) = @_;
118 3 50       14 return $type_name if blessed($type_name);
119 3 100       19 if (my $type = $reg->simple_lookup($type_name)) {
120 1         27 return $type;
121             } else {
122 2         68 my $type = Type::Utils::dwim_type(
123             $type_name,
124             fallback => ['make_role_type'],
125             );
126 2         11233 $type->{display_name} = $type_name;
127 2         12 $reg->add_type($type, $type_name);
128 2         60 return $type;
129             }
130             }
131              
132             1;