File Coverage

blib/lib/Salvation/TC/Meta/Type.pm
Criterion Covered Total %
statement 73 87 83.9
branch 17 28 60.7
condition 10 21 47.6
subroutine 20 24 83.3
pod 16 16 100.0
total 136 176 77.2


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   13 use strict;
  4         5  
  4         110  
10 4     4   12 use warnings;
  4         4  
  4         65  
11 4     4   13 use boolean;
  4         2  
  4         21  
12              
13 4     4   232 use base 'Salvation::TC::Meta';
  4         4  
  4         1122  
14              
15 4     4   16 use Scalar::Util 'blessed';
  4         3  
  4         2604  
16              
17             =head1 METHODS
18              
19             =cut
20              
21             =head2 new()
22              
23             =cut
24              
25             sub new {
26              
27 178     178 1 404 my ( $proto, %args ) = @_;
28              
29 178 50       273 die( 'Type metaclass must have validator' ) unless( defined $args{ 'validator' } );
30 178 50       330 die( 'Validator must be a CodeRef' ) if( ref( $args{ 'validator' } ) ne 'CODE' );
31              
32 178         247 $args{ 'coercion_map' } = []; # Salvation::TC::Meta::Type => CodeRef
33              
34 178 100       289 if( exists $args{ 'parent' } ) {
35              
36 9 50 33     76 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         11 my $self_validator = $args{ 'validator' };
45 9         18 my $parent_validator = $args{ 'parent' } -> validator();
46              
47             $args{ 'validator' } = sub {
48 27 50   27   45 $parent_validator -> ( $_[ 0 ] ) && $self_validator -> ( $_[ 0 ] )
49 9         30 };
50             }
51              
52 178 100       270 if( exists $args{ 'base' } ) {
53              
54 74 50 33     519 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         426 foreach my $spec (
64             [ 'signed_type_generator', 'Signed type generator' ],
65             [ 'length_type_generator', 'Length type generator' ],
66             ) {
67 356         301 my ( $key, $name ) = @$spec;
68              
69 356 50 100     1191 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         729 return $proto -> SUPER::new( %args );
76             }
77              
78             =head2 validator()
79              
80             =cut
81              
82             sub validator {
83              
84 391     391 1 290 my ( $self ) = @_;
85              
86 391         813 return $self -> { 'validator' };
87             }
88              
89             =head2 check( Any $value )
90              
91             =cut
92              
93             sub check {
94              
95 335     335 1 284 my ( $self, $value ) = @_;
96              
97 335         395 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         3 return $self -> { 'signature' };
109             }
110              
111             =head2 has_signature()
112              
113             =cut
114              
115             sub has_signature {
116              
117 24     24 1 24 my ( $self ) = @_;
118              
119 24         83 return exists $self -> { 'signature' };
120             }
121              
122             =head2 coercion_map()
123              
124             =cut
125              
126             sub coercion_map {
127              
128 11     11 1 11 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         86 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         98 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 6 my ( $self, $signature ) = @_;
208              
209 8         14 my $signed_type_generator = $self -> signed_type_generator();
210              
211 8 50       15 unless( defined $signed_type_generator ) {
212              
213 0         0 die( sprintf( 'Type %s cannot be signed', $self -> name() ) )
214             }
215              
216 8         13 my $signed_validator = $signed_type_generator -> ( $signature );
217              
218             return sub {
219              
220 16 50   16   23 $self -> check( $_[ 0 ] ) && $signed_validator -> ( $_[ 0 ] )
221 8         25 };
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 20 my ( $self, $min, $max ) = @_;
233              
234 19         25 my $length_type_generator = $self -> length_type_generator();
235              
236 19 50       43 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   48 $self -> check( $_[ 0 ] ) && $length_validator -> ( $_[ 0 ] )
246 19         54 };
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         8  
258              
259 5         7 return;
260             }
261              
262             =head2 coerce( Any $value )
263              
264             =cut
265              
266             sub coerce {
267              
268 11     11 1 10 my ( $self, $value ) = @_;
269              
270 11         8 foreach my $rule ( @{ $self -> coercion_map() } ) {
  11         16  
271              
272 10         6 eval { $rule -> [ 0 ] -> check( $value ) };
  10         16  
273              
274 10 100       29 if( $@ ) {
275              
276 3 50 33     16 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
277              
278 3         6 next;
279              
280             } else {
281              
282 0         0 die( $@ );
283             }
284             };
285              
286 7         7 local $_ = $value; # Ради соответствия API Moose
287              
288 7         13 $value = $rule -> [ 1 ] -> ();
289              
290 7         21 last;
291             }
292              
293 11         23 return $value; # Moose возвращает либо старое, либо приведённое значение
294             }
295              
296             1;
297              
298             __END__