File Coverage

blib/lib/Salvation/TC/Meta/Type.pm
Criterion Covered Total %
statement 75 89 84.2
branch 17 28 60.7
condition 10 21 47.6
subroutine 20 24 83.3
pod 16 16 100.0
total 138 178 77.5


line stmt bran cond sub pod time code
1             package Salvation::TC::Meta::Type;
2              
3             =head1 NAME
4              
5             Salvation::TC::Meta::Type - Класс для простых типов
6              
7             =cut
8              
9 4     4   12 use strict;
  4         4  
  4         102  
10 4     4   11 use warnings;
  4         4  
  4         63  
11 4     4   11 use boolean;
  4         4  
  4         21  
12              
13 4     4   250 use base 'Salvation::TC::Meta';
  4         4  
  4         1150  
14              
15 4     4   16 use Scalar::Util 'blessed';
  4         3  
  4         2602  
16              
17             =head1 METHODS
18              
19             =cut
20              
21             =head2 new()
22              
23             =cut
24              
25             sub new {
26              
27 178     178 1 409 my ( $proto, %args ) = @_;
28              
29 178 50       293 die( 'Type metaclass must have validator' ) unless( defined $args{ 'validator' } );
30 178 50       331 die( 'Validator must be a CodeRef' ) if( ref( $args{ 'validator' } ) ne 'CODE' );
31              
32 178         257 $args{ 'coercion_map' } = []; # Salvation::TC::Meta::Type => CodeRef
33              
34 178 100       319 if( exists $args{ 'parent' } ) {
35              
36 9 50 33     89 unless(
      33        
37             defined $args{ 'parent' } && blessed $args{ 'parent' }
38             && $args{ 'parent' } -> isa( 'Salvation::TC::Meta::Type' )
39             ) {
40              
41 0         0 die( 'Parent type must be a Salvation::TC::Meta::Type' );
42             }
43              
44 9         15 my $self_validator = $args{ 'validator' };
45 9         20 my $parent_validator = $args{ 'parent' } -> validator();
46              
47             $args{ 'validator' } = sub {
48 27 50   27   56 $parent_validator -> ( $_[ 0 ] ) && $self_validator -> ( $_[ 0 ] )
49 9         49 };
50             }
51              
52 178 100       256 if( exists $args{ 'base' } ) {
53              
54 74 50 33     508 unless(
      33        
55             defined $args{ 'base' } && blessed $args{ 'base' }
56             && $args{ 'base' } -> isa( 'Salvation::TC::Meta::Type' )
57             ) {
58              
59 0         0 die( 'Base type must be a Salvation::TC::Meta::Type' );
60             }
61             }
62              
63 178         394 foreach my $spec (
64             [ 'signed_type_generator', 'Signed type generator' ],
65             [ 'length_type_generator', 'Length type generator' ],
66             ) {
67 356         349 my ( $key, $name ) = @$spec;
68              
69 356 50 100     1235 if( exists $args{ $key } && defined $args{ $key } && ( ref( $args{ $key } ) ne 'CODE' ) ) {
      66        
70              
71 0         0 die( "${name} must be a CodeRef" );
72             }
73             }
74              
75 178         693 return $proto -> SUPER::new( %args );
76             }
77              
78             =head2 validator()
79              
80             =cut
81              
82             sub validator {
83              
84 391     391 1 299 my ( $self ) = @_;
85              
86 391         768 return $self -> { 'validator' };
87             }
88              
89             =head2 check( Any $value )
90              
91             =cut
92              
93             sub check {
94              
95 335     335 1 280 my ( $self, $value ) = @_;
96              
97 335         397 return $self -> validator() -> ( $value );
98             }
99              
100             =head2 signature()
101              
102             =cut
103              
104             sub signature {
105              
106 1     1 1 2 my ( $self ) = @_;
107              
108 1         4 return $self -> { 'signature' };
109             }
110              
111             =head2 has_signature()
112              
113             =cut
114              
115             sub has_signature {
116              
117 24     24 1 23 my ( $self ) = @_;
118              
119 24         87 return exists $self -> { 'signature' };
120             }
121              
122             =head2 coercion_map()
123              
124             =cut
125              
126             sub coercion_map {
127              
128 11     11 1 10 my ( $self ) = @_;
129              
130 11         19 return $self -> { 'coercion_map' };
131             }
132              
133             =head2 parent()
134              
135             =cut
136              
137             sub parent {
138              
139 0     0 1 0 my ( $self ) = @_;
140              
141 0         0 return $self -> { 'parent' };
142             }
143              
144             =head2 base()
145              
146             =cut
147              
148             sub base {
149              
150 0     0 1 0 my ( $self ) = @_;
151              
152 0         0 return $self -> { 'base' };
153             }
154              
155             =head2 has_base()
156              
157             =cut
158              
159             sub has_base {
160              
161 0     0 1 0 my ( $self ) = @_;
162              
163 0         0 return exists $self -> { 'base' };
164             }
165              
166             =head2 has_parent()
167              
168             =cut
169              
170             sub has_parent {
171              
172 0     0 1 0 my ( $self ) = @_;
173              
174 0         0 return exists $self -> { 'parent' };
175             }
176              
177             =head2 signed_type_generator()
178              
179             =cut
180              
181             sub signed_type_generator {
182              
183 42     42 1 39 my ( $self ) = @_;
184              
185 42         87 return $self -> { 'signed_type_generator' };
186             }
187              
188             =head2 length_type_generator()
189              
190             =cut
191              
192             sub length_type_generator {
193              
194 42     42 1 43 my ( $self ) = @_;
195              
196 42         99 return $self -> { 'length_type_generator' };
197             }
198              
199             =head2 sign( ArrayRef $signature )
200              
201             Генерирует валидатор для текущего типа на основе подписи.
202              
203             =cut
204              
205             sub sign {
206              
207 8     8 1 7 my ( $self, $signature ) = @_;
208              
209 8         12 my $signed_type_generator = $self -> signed_type_generator();
210              
211 8 50       13 unless( defined $signed_type_generator ) {
212              
213 0         0 die( sprintf( 'Type %s cannot be signed', $self -> name() ) )
214             }
215              
216 8         17 my $signed_validator = $signed_type_generator -> ( $signature );
217              
218             return sub {
219              
220 16 50   16   24 $self -> check( $_[ 0 ] ) && $signed_validator -> ( $_[ 0 ] )
221 8         32 };
222             }
223              
224             =head2 length_checker( Int $min, Maybe[Int] $max )
225              
226             Генерирует валидатор для текущего типа на основе спецификации длины.
227              
228             =cut
229              
230             sub length_checker {
231              
232 19     19 1 21 my ( $self, $min, $max ) = @_;
233              
234 19         28 my $length_type_generator = $self -> length_type_generator();
235              
236 19 50       28 unless( defined $length_type_generator ) {
237              
238 0         0 die( sprintf( 'Length of type %s could not be checked', $self -> name() ) );
239             }
240              
241 19         39 my $length_validator = $length_type_generator -> ( $min, $max );
242              
243             return sub {
244              
245 32 50   32   50 $self -> check( $_[ 0 ] ) && $length_validator -> ( $_[ 0 ] )
246 19         59 };
247             }
248              
249             =head2 add_coercion( Salvation::TC::Meta::Type $from, CodeRef $how )
250              
251             =cut
252              
253             sub add_coercion {
254              
255 5     5 1 5 my ( $self, $from, $how ) = @_;
256              
257 5         4 push( @{ $self -> { 'coercion_map' } }, [ $from => $how ] );
  5         10  
258              
259 5         6 return;
260             }
261              
262             =head2 coerce( Any $value )
263              
264             =cut
265              
266             sub coerce {
267              
268 11     11 1 9 my ( $self, $value ) = @_;
269              
270 11         9 foreach my $rule ( @{ $self -> coercion_map() } ) {
  11         16  
271              
272             {
273 10         7 local $SIG{ '__DIE__' } = 'DEFAULT';
  10         22  
274              
275 10         8 eval { $rule -> [ 0 ] -> check( $value ) };
  10         17  
276             }
277              
278 10 100       32 if( $@ ) {
279              
280 3 50 33     17 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
281              
282 3         5 next;
283              
284             } else {
285              
286 0         0 die( $@ );
287             }
288             };
289              
290 7         6 local $_ = $value; # Ради соответствия API Moose
291              
292 7         14 $value = $rule -> [ 1 ] -> ();
293              
294 7         20 last;
295             }
296              
297 11         26 return $value; # Moose возвращает либо старое, либо приведённое значение
298             }
299              
300             1;
301              
302             __END__