File Coverage

blib/lib/Salvation/TC/Meta/Type/Parameterized.pm
Criterion Covered Total %
statement 57 65 87.6
branch 16 24 66.6
condition 3 9 33.3
subroutine 15 16 93.7
pod 8 8 100.0
total 99 122 81.1


line stmt bran cond sub pod time code
1             package Salvation::TC::Meta::Type::Parameterized;
2              
3             =head1 NAME
4              
5             Salvation::TC::Meta::Type::Parameterized - Базовый класс для параметризованных типов
6              
7             =cut
8              
9 4     4   16 use strict;
  4         6  
  4         95  
10 4     4   14 use warnings;
  4         3  
  4         73  
11              
12 4     4   12 use base 'Salvation::TC::Meta::Type';
  4         4  
  4         262  
13              
14 4     4   16 use Scalar::Util 'blessed';
  4         4  
  4         166  
15              
16 4     4   14 use Salvation::TC::Exception::WrongType::TC ();
  4         3  
  4         2040  
17              
18             =head1 METHODS
19              
20             =cut
21              
22             =head2 new()
23              
24             =cut
25              
26             sub new {
27              
28 46     46 1 107 my ( $proto, %args ) = @_;
29              
30 46 50       75 die( 'Parameterized type metaclass must have inner type' ) unless( defined $args{ 'inner' } );
31              
32 46 50 33     273 unless( blessed $args{ 'inner' } && $args{ 'inner' } -> isa( 'Salvation::TC::Meta::Type' ) ) {
33              
34 0         0 die( 'Inner type must be a Salvation::TC::Meta::Type' );
35             }
36              
37 46         158 my $self = $proto -> SUPER::new( %args );
38              
39 46         142 $self -> { 'container_validator' } = delete( $self -> { 'validator' } );
40 46         104 $self -> { 'validator' } = $self -> build_validator();
41              
42 46         306 return $self;
43             }
44              
45             =head2 inner()
46              
47             =cut
48              
49             sub inner {
50              
51 55     55 1 45 my ( $self ) = @_;
52              
53 55         85 return $self -> { 'inner' };
54             }
55              
56             =head2 iterate( Any $value, CodeRef $code )
57              
58             =cut
59              
60             sub iterate {
61              
62 0     0 1 0 my ( $self, $value, $code ) = @_;
63              
64 0         0 $code -> ( $value, undef );
65              
66 0         0 return;
67             }
68              
69             =head2 container_validator()
70              
71             =cut
72              
73             sub container_validator {
74              
75 98     98 1 66 my ( $self ) = @_;
76              
77 98         168 return $self -> { 'container_validator' };
78             }
79              
80             =head2 check_container( Any $value )
81              
82             =cut
83              
84             sub check_container {
85              
86 98     98 1 78 my ( $self, $value ) = @_;
87              
88 98         130 return $self -> container_validator() -> ( $value );
89             }
90              
91             =head2 build_validator()
92              
93             =cut
94              
95             sub build_validator {
96              
97 46     46 1 41 my ( $self ) = @_;
98              
99 46         76 my $item_type = $self -> inner();
100              
101             return sub {
102              
103 74     74   65 my ( $value ) = @_;
104              
105 74         66 eval { $self -> check_container( $value ) };
  74         101  
106              
107 74 100       117 if( $@ ) {
108              
109 11 50 33     60 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
110              
111 11 100       25 Salvation::TC::Exception::WrongType::TC -> throw(
112             type => $self -> name(), value => $value,
113             ( $@ -> isa( 'Salvation::TC::Exception::WrongType::TC' ) ? (
114             prev => $@,
115             ) : () )
116             );
117              
118             } else {
119              
120 0         0 die( $@ );
121             }
122             };
123              
124             $self -> iterate( $value, sub {
125              
126 86         78 my ( $item, $key ) = @_;
127              
128 86         66 eval { $item_type -> check( $item ) };
  86         148  
129              
130 86 100       233 if( $@ ) {
131              
132 26 50 33     135 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
133              
134 26 100       50 Salvation::TC::Exception::WrongType::TC -> throw(
135             type => $self -> name(), value => $value,
136             prev => Salvation::TC::Exception::WrongType::TC -> new(
137             type => $item_type -> name(),
138             value => $item,
139             param_name => $key,
140             ( $@ -> isa( 'Salvation::TC::Exception::WrongType::TC' ) ? (
141             prev => $@,
142             ) : () )
143             )
144             );
145              
146             } else {
147              
148 0         0 die( $@ );
149             }
150             };
151 63         285 } );
152              
153 37         127 return 1;
154 46         183 };
155             }
156              
157             =head2 sign( ArrayRef $signature )
158              
159             Генерирует валидатор для текущего типа на основе подписи.
160              
161             =cut
162              
163             sub sign {
164              
165 4     4 1 5 my ( $self, $signature ) = @_;
166              
167 4         11 my $signed_type_generator = $self -> signed_type_generator();
168              
169 4 50       8 unless( defined $signed_type_generator ) {
170              
171 0         0 die( sprintf( 'Type %s cannot be signed', $self -> name() ) )
172             }
173              
174 4         10 my $signed_validator = $signed_type_generator -> ( $signature );
175              
176             return sub {
177              
178 10 50   10   21 $self -> check_container( $_[ 0 ] ) && $signed_validator -> ( $_[ 0 ] )
179 4         26 };
180             }
181              
182             =head2 length_checker( Int $min, Maybe[Int] $max )
183              
184             Генерирует валидатор для текущего типа на основе спецификации длины.
185              
186             =cut
187              
188             sub length_checker {
189              
190 5     5 1 6 my ( $self, $min, $max ) = @_;
191              
192 5         8 my $length_type_generator = $self -> length_type_generator();
193              
194 5 50       8 unless( defined $length_type_generator ) {
195              
196 0         0 die( sprintf( 'Length of type %s could not be checked', $self -> name() ) );
197             }
198              
199 5         10 my $length_validator = $length_type_generator -> ( $min, $max );
200              
201             return sub {
202              
203 14 50   14   18 $self -> check_container( $_[ 0 ] ) && $length_validator -> ( $_[ 0 ] )
204 5         18 };
205             }
206              
207             1;
208              
209             __END__