File Coverage

blib/lib/Salvation/TC.pm
Criterion Covered Total %
statement 147 184 79.8
branch 36 52 69.2
condition 39 76 51.3
subroutine 42 45 93.3
pod 25 25 100.0
total 289 382 75.6


line stmt bran cond sub pod time code
1             package Salvation::TC;
2              
3             =head1 NAME
4              
5             Salvation::TC - Type Constraint, система проверки типов значений.
6              
7             =head1 SYNOPSIS
8              
9             Salvation::TC -> is( 'asd', 'Str' );
10             Salvation::TC -> is( 123, 'Int' );
11             Salvation::TC -> is( 123.45, 'Num' );
12             Salvation::TC -> is( [], 'ArrayRef' );
13             Salvation::TC -> is( [ 1, 2, "asd" ], 'ArrayRef[Int|Str]' );
14              
15             Salvation::TC -> assert( [ { a => undef, b => 1 } ], 'ArrayRef[HashRef[Maybe[Int]]]' );
16             Salvation::TC -> assert( DBScheme::Image -> search_one([]), 'DBScheme' );
17              
18             Salvation::TC -> assert( { asd => 1 }, 'HashRef(Int :asd!, ArrayRef[Int] :list)' ); # OK
19             Salvation::TC -> assert( { asd => 1, list => [ 2 ] }, 'HashRef(Int :asd!, ArrayRef[Int] :list)' ); # OK
20             Salvation::TC -> assert( { qwe => 1 }, 'HashRef(Int :asd!, ArrayRef[Int] :list)' ); # FAIL
21              
22             Salvation::TC -> assert( [ { asd => [], qwe => 1 } ], 'ArrayRef[HashRef(Int :qwe!)](HashRef(ArrayRef :asd!) el)' ); # OK
23              
24             =head1 SEE ALSO
25              
26             L
27              
28             http://perlcabal.org/syn/S06.html#Signatures
29              
30             =cut
31              
32 4     4   53615 use strict;
  4         5  
  4         117  
33 4     4   13 use warnings;
  4         5  
  4         86  
34 4     4   1308 use boolean;
  4         9172  
  4         14  
35              
36 4     4   270 use Carp 'confess';
  4         6  
  4         179  
37 4     4   1615 use Module::Load ();
  4         2823  
  4         63  
38 4     4   17 use Scalar::Util 'blessed';
  4         4  
  4         272  
39 4     4   1649 use Class::Inspector ();
  4         9523  
  4         77  
40 4     4   1529 use Devel::PartialDump ();
  4         155301  
  4         97  
41              
42 4     4   1207 use Salvation::TC::Parser ();
  4         5  
  4         53  
43 4     4   1130 use Salvation::TC::Meta::Type ();
  4         7  
  4         62  
44 4     4   1302 use Salvation::TC::Meta::Type::Maybe ();
  4         8  
  4         51  
45 4     4   1288 use Salvation::TC::Meta::Type::Union ();
  4         7  
  4         62  
46 4     4   19 use Salvation::TC::Exception::WrongType ();
  4         5  
  4         7301  
47              
48             our $VERSION = 0.11;
49              
50              
51             =head1 METHODS
52              
53             =cut
54              
55             =head2 init_regular_cases()
56              
57             Инициализирует и кэширует самые частые кейсы.
58              
59             =cut
60              
61             sub init_regular_cases {
62              
63 4     4 1 7 my ( $self ) = @_;
64              
65 4         12 my %table = (
66             Int => 'Number::Integer',
67             Num => 'Number::Float',
68             );
69              
70 4         22 while( my ( $alias, $type ) = each( %table ) ) {
71              
72 8         19 $type = $self -> get( $type );
73              
74 8         36 $self -> setup_type( $alias,
75             validator => $type -> validator(),
76             signed_type_generator => $type -> signed_type_generator(),
77             length_type_generator => $type -> length_type_generator(),
78             );
79             }
80              
81 4         10 foreach my $type (
82             'Any',
83             'ArrayRef',
84             'Bool',
85             'CodeRef',
86             'Date::Reverse',
87             'Date',
88             'Defined',
89             'HashRef',
90             'Object',
91             'Ref',
92             'SessionId',
93             'Str',
94             'Text::English',
95             'Text',
96             'Time',
97             'Undef',
98             'ScalarRef',
99             ) {
100              
101 68         117 $self -> get( $type );
102             }
103              
104 4         11 return;
105             }
106              
107             {
108             my $table = undef;
109              
110             =head2 get_known_types()
111              
112             Возвращает таблицу известных базовых валидаторов и генератором для них.
113              
114             =cut
115              
116             sub get_known_types {
117              
118 77     77 1 90 my ( $self ) = @_;
119              
120             return $table //= [
121             [ 'Salvation::TC::Type' => {
122             validator => sub {
123 76     76   159 $self -> gen_salvation_tc_type_validator( @_ );
124             },
125             signed_type_generator => sub {
126 76     76   136 $self -> gen_salvation_tc_type_signer( @_ );
127             },
128             length_type_generator => sub {
129 76     76   125 $self -> gen_salvation_tc_type_length_check( @_ );
130             }
131 77   100     264 } ],
132             ];
133             }
134             }
135              
136             =head2 gen_salvation_tc_type_validator( Str $class )
137              
138             Генератор валидаторов значений на основе L.
139              
140             Возвращает CodeRef, являющийся валидатором, соответствующий следующей сигнатуре:
141              
142             ( Any $value )
143              
144             , где:
145              
146             =over
147              
148             =item $value
149              
150             Валидируемое значение.
151              
152             Обязательный параметр.
153              
154             =back
155              
156             Если значение не подходит - валидатор бросает исключение
157             L.
158              
159             Описание аргументов:
160              
161             =over
162              
163             =item $class
164              
165             Имя класса типа.
166              
167             Обязательный параметр.
168              
169             =back
170              
171             =cut
172              
173             sub gen_salvation_tc_type_validator {
174              
175 76     76 1 90 my ( $self, $class ) = @_;
176              
177             return sub {
178              
179 264     264   747 $class -> Check( $_[ 0 ] );
180 76         252 };
181             }
182              
183             =head2 gen_salvation_tc_type_signer( Str $class )
184              
185             Генератор валидаторов значений на основе подписанных L.
186              
187             Возвращает CodeRef, являющийся валидатором, соответствующий следующей сигнатуре:
188              
189             ( Any $value )
190              
191             , где:
192              
193             =over
194              
195             =item $value
196              
197             Валидируемое значение.
198              
199             Обязательный параметр.
200              
201             =back
202              
203             Если значение не подходит - валидатор бросает исключение
204             L.
205              
206             Описание аргументов:
207              
208             =over
209              
210             =item $class
211              
212             Имя класса типа.
213              
214             Обязательный параметр.
215              
216             =back
217              
218             =cut
219              
220             sub gen_salvation_tc_type_signer {
221              
222 76     76 1 71 my ( $self, $class ) = @_;
223              
224 76 100       625 return undef unless( $class -> can( 'create_validator_from_sig' ) );
225              
226             return sub {
227              
228 12     12   48 $class -> create_validator_from_sig( $_[ 0 ] );
229 8         31 };
230             }
231              
232             =head2 gen_salvation_tc_type_length_check( Str $class )
233              
234             Генератор валидаторов значений на основе L, ограниченных
235             под длине.
236              
237             Возвращает CodeRef, являющийся валидатором, соответствующий следующей сигнатуре:
238              
239             ( Any $value )
240              
241             , где:
242              
243             =over
244              
245             =item $value
246              
247             Валидируемое значение.
248              
249             Обязательный параметр.
250              
251             =back
252              
253             Если значение не подходит - валидатор бросает исключение
254             L.
255              
256             Описание аргументов:
257              
258             =over
259              
260             =item $class
261              
262             Имя класса типа.
263              
264             Обязательный параметр.
265              
266             =back
267              
268             =cut
269              
270             sub gen_salvation_tc_type_length_check {
271              
272 76     76 1 81 my ( $self, $class ) = @_;
273              
274 76 100       450 return undef unless( $class -> can( 'create_length_validator' ) );
275              
276             return sub {
277              
278 24     24   79 $class -> create_length_validator( @_[ 0, 1 ] );
279 20         53 };
280             }
281              
282             =head2 gen_class_type_validator( Str $class )
283              
284             Генератор валидаторов значений, являющихся экземпярами классов.
285              
286             Возвращает CodeRef, являющийся валидатором, соответствующий следующей сигнатуре:
287              
288             ( Any $value )
289              
290             , где:
291              
292             =over
293              
294             =item $value
295              
296             Валидируемое значение.
297              
298             Обязательный параметр.
299              
300             =back
301              
302             Если значение не подходит - валидатор бросает исключение
303             L.
304              
305             Описание аргументов:
306              
307             =over
308              
309             =item $class
310              
311             Имя класса типа.
312              
313             Обязательный параметр.
314              
315             =back
316              
317             =cut
318              
319             sub gen_class_type_validator {
320              
321 1     1 1 1 my ( $self, $class ) = @_;
322              
323             return sub {
324              
325 8 100 66 8   72 ( defined $_[ 0 ] && blessed $_[ 0 ] && $_[ 0 ] -> isa( $class ) )
      66        
326             || Salvation::TC::Exception::WrongType -> throw(
327             type => $class, value => $_[ 0 ]
328             )
329 1         8 };
330             }
331              
332             {
333             my %TYPE;
334              
335             =head2 setup_type( Str $name, @rest )
336              
337             Инициализирует класс для класса типа.
338              
339             Описание аргументов:
340              
341             =over
342              
343             =item $name
344              
345             Имя типа.
346              
347             Обязательный параметр.
348              
349             =item @rest
350              
351             Иные, сопутствующие типу параметры (пары ключ-значение). Основные параметры типа:
352              
353             =over
354              
355             =item validator
356              
357             CodeRef, функция-валидатор.
358              
359             =back
360              
361             =back
362              
363             =cut
364              
365             sub setup_type {
366              
367 122     122 1 220 my ( $self, $name, @rest ) = @_;
368              
369 122   33     631 return $TYPE{ ref( $self ) || $self } -> { $name } //= $self -> simple_type_class_name() -> new( @rest, name => $name );
      33        
370             }
371              
372             =head2 simple_type_class_name()
373              
374             =cut
375              
376             sub simple_type_class_name {
377              
378 122     122 1 424 return 'Salvation::TC::Meta::Type';
379             }
380              
381             =head2 setup_maybe_type( Str $name, @rest )
382              
383             =cut
384              
385             sub setup_maybe_type {
386              
387 1     1 1 2 my ( $self, $name, @rest ) = @_;
388              
389 1   33     11 return $TYPE{ ref( $self ) || $self } -> { $name } //= $self -> maybe_type_class_name() -> new( @rest, name => $name );
      33        
390             }
391              
392             =head2 maybe_type_class_name()
393              
394             =cut
395              
396             sub maybe_type_class_name {
397              
398 1     1 1 8 return 'Salvation::TC::Meta::Type::Maybe';
399             }
400              
401             =head2 setup_union_type( Str $name, @rest )
402              
403             =cut
404              
405             sub setup_union_type {
406              
407 9     9 1 14 my ( $self, $name, @rest ) = @_;
408              
409 9   33     61 return $TYPE{ ref( $self ) || $self } -> { $name } //= $self -> union_type_class_name() -> new( @rest, name => $name );
      33        
410             }
411              
412             =head2 union_type_class_name()
413              
414             =cut
415              
416             sub union_type_class_name {
417              
418 9     9 1 43 return 'Salvation::TC::Meta::Type::Union';
419             }
420              
421             =head2 setup_parameterized_type( Str $name, Str $class, @rest )
422              
423             =cut
424              
425             sub setup_parameterized_type {
426              
427 46     46 1 78 my ( $self, $name, $class, @rest ) = @_;
428              
429 46   33     313 return $TYPE{ ref( $self ) || $self } -> { $name } //= $class -> new( @rest, name => $name );
      33        
430             }
431              
432             =head2 get_type( Str $name )
433              
434             Возвращает уже созданный класс для класса типа.
435              
436             Описание аргументов:
437              
438             =over
439              
440             =item $name
441              
442             Имя типа.
443              
444             Обязательный параметр.
445              
446             =back
447              
448             =cut
449              
450             sub get_type {
451              
452 499     499 1 436 my ( $self, $name ) = @_;
453              
454 499   33     2083 return $TYPE{ ref( $self ) || $self } -> { $name };
455             }
456             }
457              
458             =head2 get_type_parser()
459              
460             Возвращает имя класса парсера типов.
461              
462             =cut
463              
464             sub get_type_parser {
465              
466 137     137 1 542 return 'Salvation::TC::Parser';
467             }
468              
469             =head2 parse_type( Str $str )
470              
471             Анализирует строку и возвращает класс описанного в ней класса типа.
472              
473             Если класс для этого класса типа ещё не был инициализирован - инициализирует
474             его.
475              
476             Описание аргументов:
477              
478             =over
479              
480             =item $str
481              
482             Строка, описывающая тип.
483              
484             Обязательный параметр.
485              
486             =back
487              
488             =cut
489              
490             sub parse_type {
491              
492 137     137 1 117 my ( $self, $str ) = @_;
493              
494 137         240 return $self -> materialize_type(
495             $self -> get_type_parser() -> tokenize_type_str( $str, {} )
496             );
497             }
498              
499             =head2 materialize_type( ArrayRef[HashRef] $tokens )
500              
501             Превращает токены �� классы типов.
502              
503             =cut
504              
505             sub materialize_type {
506              
507 315     315 1 255 my ( $self, $tokens ) = @_;
508              
509 315 100       389 if( scalar( @$tokens ) == 1 ) {
510              
511 306 100       577 if( exists $tokens -> [ 0 ] -> { 'type' } ) {
    100          
    100          
    100          
    50          
512              
513 213         356 return $self -> get_or_create_simple_type( $tokens -> [ 0 ] -> { 'type' } );
514              
515             } elsif( exists $tokens -> [ 0 ] -> { 'maybe' } ) {
516              
517 2         5 my $type = $self -> materialize_type( $tokens -> [ 0 ] -> { 'maybe' } );
518 2         6 my $name = sprintf( 'Maybe[%s]', $type -> name() );
519              
520 2   66     4 return ( $self -> get_type( $name ) // $self -> setup_maybe_type(
521             $name, validator => $type -> validator(), base => $type,
522             ) );
523              
524             } elsif( exists $tokens -> [ 0 ] -> { 'class' } ) {
525              
526 51         147 my $base = $self -> materialize_type( $tokens -> [ 0 ] -> { 'base' } );
527 51         83 my $inner = $self -> materialize_type( $tokens -> [ 0 ] -> { 'param' } );
528 51         155 my $name = sprintf( '%s[%s]', $base -> name(), $inner -> name() );
529              
530 51   66     77 return ( $self -> get_type( $name ) // $self -> setup_parameterized_type(
531             $name, $tokens -> [ 0 ] -> { 'class' }, base => $base,
532             validator => $base -> validator(), inner => $inner,
533             ) );
534              
535             } elsif( exists $tokens -> [ 0 ] -> { 'signed' } ) {
536              
537 12         14 my $data = $tokens -> [ 0 ] -> { 'signed' };
538              
539 12         40 my $type = $self -> materialize_type( [ $data -> { 'type' } ] );
540 12         38 my $name = sprintf( '%s%s', $type -> name(), $data -> { 'source' } );
541              
542 12         18 my $present_type = $self -> get_type( $name );
543              
544 12 50       19 return $present_type if( defined $present_type );
545              
546 12         9 foreach my $el ( @{ $data -> { 'signature' } } ) {
  12         22  
547              
548 15         22 $el -> { 'type' } = $self -> materialize_type( $el -> { 'type' } );
549             }
550              
551 12 100       62 my $method = ( $type -> isa( 'Salvation::TC::Meta::Type::Parameterized' )
552             ? 'setup_parameterized_type'
553             : 'setup_type' );
554              
555 12 100       37 return $self -> $method( $name,
556             ( ( $method eq 'setup_parameterized_type' ) ? (
557             ref( $type ),
558             inner => $type -> inner(),
559             ) : () ),
560             validator => $type -> sign( $data -> { 'signature' } ),
561             length_type_generator => $type -> length_type_generator(),
562             signature => $data -> { 'signature' },
563             base => $type,
564             );
565              
566             } elsif( exists $tokens -> [ 0 ] -> { 'length' } ) {
567              
568 28         26 my $data = $tokens -> [ 0 ] -> { 'length' };
569              
570 28         73 my $type = $self -> materialize_type( [ $data -> { 'type' } ] );
571 28   100     73 my $name = sprintf( '%s{%s,%s}', $type -> name(), $data -> { 'min' }, ( $data -> { 'max' } // '' ) );
572              
573 28 100       139 my $method = ( $type -> isa( 'Salvation::TC::Meta::Type::Parameterized' )
574             ? 'setup_parameterized_type'
575             : 'setup_type' );
576              
577 28 100 66     42 return ( $self -> get_type( $name ) // $self -> $method( $name,
    100          
578             ( ( $method eq 'setup_parameterized_type' ) ? (
579             ref( $type ),
580             inner => $type -> inner(),
581             ) : () ),
582             validator => $type -> length_checker( @$data{ 'min', 'max' } ),
583             signed_type_generator => $type -> signed_type_generator(),
584             ( $type -> has_signature() ? (
585             signature => $type -> signature(),
586             ) : () ),
587             base => $type,
588             ) );
589              
590             } else {
591              
592 0         0 require Data::Dumper;
593              
594 0         0 die( 'Unknown token: ' . Data::Dumper::Dumper( $tokens ) );
595             }
596              
597             } else {
598              
599 9         14 my @types = ();
600              
601 9         15 foreach my $token ( @$tokens ) {
602              
603 19         43 push( @types, $self -> materialize_type( [ $token ] ) );
604             }
605              
606 9         17 my $name = join( '|', map( { $_ -> name() } @types ) );
  19         32  
607              
608 9   33     19 return ( $self -> get_type( $name ) // $self -> setup_union_type(
609             $name, types => \@types
610             ) );
611             }
612             }
613              
614             =head2 simple_type_class_ns()
615              
616             =cut
617              
618             sub simple_type_class_ns {
619              
620 213     213 1 512 return 'Salvation::TC::Type';
621             }
622              
623             =head2 get_or_create_simple_type( Str $str )
624              
625             Возвращает базовый тип с именем C<$str>.
626              
627             =cut
628              
629             sub get_or_create_simple_type {
630              
631 213     213 1 171 my ( $self, $str ) = @_;
632              
633 213         271 my $salvation_tc_type_str = sprintf( '%s::%s', $self -> simple_type_class_ns(), $str );
634              
635 213   100     302 my $type = ( $self -> get_type( $str ) // $self -> get_type( $salvation_tc_type_str ) );
636              
637 213 100       466 return $type if( defined $type );
638              
639             {
640 77         62 local $SIG{ '__DIE__' } = 'DEFAULT';
  77         240  
641              
642 77 50 66     274 if(
      66        
      66        
643             ! Class::Inspector -> loaded( $str )
644             && ! eval{ Module::Load::load( $str ); 1 }
645             && (
646             Class::Inspector -> loaded( $salvation_tc_type_str )
647             || eval{ Module::Load::load( $salvation_tc_type_str ); 1 }
648             )
649             ) {
650              
651 76         4637 $str = $salvation_tc_type_str;
652             }
653             }
654              
655 77         157 my $validator = undef;
656 77         57 my $signed_type_generator = undef;
657 77         61 my $length_type_generator = undef;
658              
659 77         62 foreach my $spec ( @{ $self -> get_known_types() } ) {
  77         215  
660              
661 77 100       453 if( $str -> isa( $spec -> [ 0 ] ) ) {
662              
663 76         130 $validator = $spec -> [ 1 ] -> { 'validator' } -> ( $str );
664 76         136 $signed_type_generator = $spec -> [ 1 ] -> { 'signed_type_generator' } -> ( $str );
665 76         130 $length_type_generator = $spec -> [ 1 ] -> { 'length_type_generator' } -> ( $str );
666              
667 76         93 last;
668             }
669             }
670              
671 77   66     215 return $self -> setup_type( $str,
672             validator => ( $validator // $self -> gen_class_type_validator( $str ) ),
673             signed_type_generator => $signed_type_generator,
674             length_type_generator => $length_type_generator,
675             );
676             }
677              
678             {
679             my %cache = ();
680              
681             =head2 get( Str $constraint )
682              
683             Возвращает объект для типа C<$constraint>.
684              
685             =cut
686              
687             sub get {
688              
689 255     255 1 270 my ( $self, $constraint ) = @_;
690              
691 255   33     1566 return $cache{ ref( $self ) || $self } -> { $constraint } //= $self -> parse_type( $constraint );
      66        
692             }
693             }
694              
695             =head2 is( Any $value, Str $constraint )
696              
697             Проверяет, является ли C<$value> значением типа C<$constraint>.
698              
699             Возвращает C в случае, если является, иначе - возвращает C.
700              
701             =cut
702              
703             sub is {
704              
705 140     140 1 41280 my ( $self, $value, $constraint ) = @_;
706              
707             {
708 140         155 local $SIG{ '__DIE__' } = 'DEFAULT';
  140         472  
709              
710 140         158 eval { $self -> get( $constraint ) -> check( $value ) };
  140         410  
711             }
712              
713 140 100       482 if( $@ ) {
714              
715 86 50 33     486 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
716              
717 86         164 return false;
718              
719             } else {
720              
721 0         0 die( $@ );
722             }
723             };
724              
725 54         118 return true;
726             }
727              
728             =head2 assert( Any $value, Str $constraint )
729              
730             Проверяет, является ли C<$value> значением типа C<$constraint>.
731              
732             Возвращает C в случае, если является, иначе - вызывает C.
733              
734             =cut
735              
736             sub assert {
737              
738 0     0 1 0 my ( $self, $value, $constraint ) = @_;
739              
740             {
741 0         0 local $SIG{ '__DIE__' } = 'DEFAULT';
  0         0  
742              
743 0         0 eval { $self -> get( $constraint ) -> check( $value ) };
  0         0  
744             }
745              
746 0 0       0 if( $@ ) {
747              
748 0 0 0     0 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
749              
750 0         0 confess( join( "\n", ( $self -> create_error_message( $@ ), '' ) ) );
751              
752             } else {
753              
754 0         0 die( $@ );
755             }
756             };
757              
758 0         0 return true;
759             }
760              
761             =head2 create_error_message( Salvation::TC::Exception::WrongType $e )
762              
763             =cut
764              
765             sub create_error_message {
766              
767 0     0 1 0 my ( $self, $e ) = @_;
768              
769 0         0 my @stack = ( $e );
770 0         0 my @lines = ();
771              
772 0         0 while( defined( my $node = shift( @stack ) ) ) {
773              
774 0 0       0 if( $node -> isa( 'Salvation::TC::Exception::WrongType::TC' ) ) {
775              
776 0         0 my $str = '';
777              
778 0 0       0 if( defined( my $param_name = $node -> getParamName() ) ) {
779              
780 0         0 $str = sprintf(
781             'Value %s for parameter "%s" does not match type constraint %s',
782             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
783             $param_name, $node -> getType(),
784             );
785              
786             } else {
787              
788 0         0 $str = sprintf(
789             'Value %s does not match type constraint %s',
790             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
791             $node -> getType(),
792             );
793             }
794              
795              
796 0 0       0 if( defined( my $prev = $node -> getPrev() ) ) {
797              
798 0         0 push( @lines, "${str} because:" );
799              
800 0 0       0 if( ref( $prev ) eq 'ARRAY' ) {
801              
802 0         0 my $i = 0;
803              
804 0         0 foreach my $e ( @$prev ) {
805              
806 0         0 push( @lines,
807             ++$i . ': ',
808 0         0 map( { "\t$_" } $self -> create_error_message( $e ) )
809             );
810             }
811              
812             } else {
813              
814 0         0 push( @stack, $prev );
815             }
816              
817             } else {
818              
819 0         0 push( @lines, $str );
820             }
821              
822             } else {
823              
824 0         0 push( @lines, sprintf(
825             'Value %s does not match type constraint %s',
826             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
827             $node -> getType(),
828             ) );
829             }
830             }
831              
832 0         0 return @lines;
833             }
834              
835             =head2 coerce( Any $value, Str $constraint )
836              
837             Пытается привести значение C<$value> к значению типа C<$constraint>.
838              
839             Если приведение прошло успешно - возвращает изменённое значение, иначе -
840             возвращает C<$value> без изменения*.
841              
842             * Для совместимости с API Moose.
843              
844             =cut
845              
846             sub coerce {
847              
848 8     8 1 1348 my ( $self, $value, $constraint ) = @_;
849              
850 8         15 return $self -> get( $constraint ) -> coerce( $value );
851             }
852              
853             =head2 ensure( Any $value, Str $constraint )
854              
855             Пытается привести значение C<$value> к значению типа C<$constraint>.
856              
857             Если приведение прошло успешно - возвращает изменённое значение, иначе -
858             вызывает C.
859              
860             =cut
861              
862             sub ensure {
863              
864 0     0 1   my ( $self, $value, $constraint ) = @_;
865              
866 0           $value = $self -> coerce( $value, $constraint );
867              
868 0           $self -> assert( $value, $constraint );
869              
870 0           return $value;
871             }
872              
873             __PACKAGE__ -> init_regular_cases();
874              
875             1;
876              
877             __END__