File Coverage

blib/lib/Salvation/TC.pm
Criterion Covered Total %
statement 143 178 80.3
branch 36 52 69.2
condition 39 76 51.3
subroutine 42 45 93.3
pod 25 25 100.0
total 285 376 75.8


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   54208 use strict;
  4         6  
  4         105  
33 4     4   14 use warnings;
  4         4  
  4         90  
34 4     4   1338 use boolean;
  4         8425  
  4         12  
35              
36 4     4   227 use Carp 'confess';
  4         5  
  4         152  
37 4     4   1542 use Module::Load ();
  4         2786  
  4         62  
38 4     4   16 use Scalar::Util 'blessed';
  4         5  
  4         253  
39 4     4   1565 use Class::Inspector ();
  4         9220  
  4         63  
40 4     4   2096 use Devel::PartialDump ();
  4         147677  
  4         90  
41              
42 4     4   1267 use Salvation::TC::Parser ();
  4         5  
  4         56  
43 4     4   1252 use Salvation::TC::Meta::Type ();
  4         8  
  4         70  
44 4     4   1165 use Salvation::TC::Meta::Type::Maybe ();
  4         6  
  4         52  
45 4     4   1085 use Salvation::TC::Meta::Type::Union ();
  4         6  
  4         63  
46 4     4   19 use Salvation::TC::Exception::WrongType ();
  4         4  
  4         6131  
47              
48             our $VERSION = 0.07;
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         9 my %table = (
66             Int => 'Number::Integer',
67             Num => 'Number::Float',
68             );
69              
70 4         20 while( my ( $alias, $type ) = each( %table ) ) {
71              
72 8         16 $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         12 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         112 $self -> get( $type );
102             }
103              
104 4         12 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 84 my ( $self ) = @_;
119              
120             return $table //= [
121             [ 'Salvation::TC::Type' => {
122             validator => sub {
123 76     76   122 $self -> gen_salvation_tc_type_validator( @_ );
124             },
125             signed_type_generator => sub {
126 76     76   117 $self -> gen_salvation_tc_type_signer( @_ );
127             },
128             length_type_generator => sub {
129 76     76   115 $self -> gen_salvation_tc_type_length_check( @_ );
130             }
131 77   100     268 } ],
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 87 my ( $self, $class ) = @_;
176              
177             return sub {
178              
179 264     264   781 $class -> Check( $_[ 0 ] );
180 76         247 };
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 75 my ( $self, $class ) = @_;
223              
224 76 100       608 return undef unless( $class -> can( 'create_validator_from_sig' ) );
225              
226             return sub {
227              
228 12     12   49 $class -> create_validator_from_sig( $_[ 0 ] );
229 8         29 };
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 77 my ( $self, $class ) = @_;
273              
274 76 100       375 return undef unless( $class -> can( 'create_length_validator' ) );
275              
276             return sub {
277              
278 24     24   81 $class -> create_length_validator( @_[ 0, 1 ] );
279 20         51 };
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 2 my ( $self, $class ) = @_;
322              
323             return sub {
324              
325 8 100 66 8   70 ( 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 209 my ( $self, $name, @rest ) = @_;
368              
369 122   33     618 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 476 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 3 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 9 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 17 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 93 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 86 my ( $self, $name, $class, @rest ) = @_;
428              
429 46   33     386 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 379 my ( $self, $name ) = @_;
453              
454 499   33     2156 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 531 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 130 my ( $self, $str ) = @_;
493              
494 137         198 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 279 my ( $self, $tokens ) = @_;
508              
509 315 100       383 if( scalar( @$tokens ) == 1 ) {
510              
511 306 100       622 if( exists $tokens -> [ 0 ] -> { 'type' } ) {
    100          
    100          
    100          
    50          
512              
513 213         338 return $self -> get_or_create_simple_type( $tokens -> [ 0 ] -> { 'type' } );
514              
515             } elsif( exists $tokens -> [ 0 ] -> { 'maybe' } ) {
516              
517 2         9 my $type = $self -> materialize_type( $tokens -> [ 0 ] -> { 'maybe' } );
518 2         7 my $name = sprintf( 'Maybe[%s]', $type -> name() );
519              
520 2   66     5 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         161 my $base = $self -> materialize_type( $tokens -> [ 0 ] -> { 'base' } );
527 51         85 my $inner = $self -> materialize_type( $tokens -> [ 0 ] -> { 'param' } );
528 51         131 my $name = sprintf( '%s[%s]', $base -> name(), $inner -> name() );
529              
530 51   66     83 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         15 my $data = $tokens -> [ 0 ] -> { 'signed' };
538              
539 12         37 my $type = $self -> materialize_type( [ $data -> { 'type' } ] );
540 12         38 my $name = sprintf( '%s%s', $type -> name(), $data -> { 'source' } );
541              
542 12         20 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         23  
547              
548 15         18 $el -> { 'type' } = $self -> materialize_type( $el -> { 'type' } );
549             }
550              
551 12 100       63 my $method = ( $type -> isa( 'Salvation::TC::Meta::Type::Parameterized' )
552             ? 'setup_parameterized_type'
553             : 'setup_type' );
554              
555 12 100       41 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         29 my $data = $tokens -> [ 0 ] -> { 'length' };
569              
570 28         68 my $type = $self -> materialize_type( [ $data -> { 'type' } ] );
571 28   100     75 my $name = sprintf( '%s{%s,%s}', $type -> name(), $data -> { 'min' }, ( $data -> { 'max' } // '' ) );
572              
573 28 100       142 my $method = ( $type -> isa( 'Salvation::TC::Meta::Type::Parameterized' )
574             ? 'setup_parameterized_type'
575             : 'setup_type' );
576              
577 28 100 66     41 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         13 my @types = ();
600              
601 9         14 foreach my $token ( @$tokens ) {
602              
603 19         56 push( @types, $self -> materialize_type( [ $token ] ) );
604             }
605              
606 9         17 my $name = join( '|', map( { $_ -> name() } @types ) );
  19         34  
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 496 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 188 my ( $self, $str ) = @_;
632              
633 213         292 my $salvation_tc_type_str = sprintf( '%s::%s', $self -> simple_type_class_ns(), $str );
634              
635 213   100     300 my $type = ( $self -> get_type( $str ) // $self -> get_type( $salvation_tc_type_str ) );
636              
637 213 100       474 return $type if( defined $type );
638              
639 77 50 66     257 if(
      66        
      66        
640             ! Class::Inspector -> loaded( $str )
641             && ! eval{ Module::Load::load( $str ); 1 }
642             && (
643             Class::Inspector -> loaded( $salvation_tc_type_str )
644             || eval{ Module::Load::load( $salvation_tc_type_str ); 1 }
645             )
646             ) {
647              
648 76         4510 $str = $salvation_tc_type_str;
649             }
650              
651 77         188 my $validator = undef;
652 77         63 my $signed_type_generator = undef;
653 77         63 my $length_type_generator = undef;
654              
655 77         63 foreach my $spec ( @{ $self -> get_known_types() } ) {
  77         216  
656              
657 77 100       428 if( $str -> isa( $spec -> [ 0 ] ) ) {
658              
659 76         142 $validator = $spec -> [ 1 ] -> { 'validator' } -> ( $str );
660 76         137 $signed_type_generator = $spec -> [ 1 ] -> { 'signed_type_generator' } -> ( $str );
661 76         130 $length_type_generator = $spec -> [ 1 ] -> { 'length_type_generator' } -> ( $str );
662              
663 76         90 last;
664             }
665             }
666              
667 77   66     203 return $self -> setup_type( $str,
668             validator => ( $validator // $self -> gen_class_type_validator( $str ) ),
669             signed_type_generator => $signed_type_generator,
670             length_type_generator => $length_type_generator,
671             );
672             }
673              
674             {
675             my %cache = ();
676              
677             =head2 get( Str $constraint )
678              
679             Возвращает объект для типа C<$constraint>.
680              
681             =cut
682              
683             sub get {
684              
685 255     255 1 244 my ( $self, $constraint ) = @_;
686              
687 255   33     1504 return $cache{ ref( $self ) || $self } -> { $constraint } //= $self -> parse_type( $constraint );
      66        
688             }
689             }
690              
691             =head2 is( Any $value, Str $constraint )
692              
693             Проверяет, является ли C<$value> значением типа C<$constraint>.
694              
695             Возвращает C в случае, если является, иначе - возвращает C.
696              
697             =cut
698              
699             sub is {
700              
701 140     140 1 51941 my ( $self, $value, $constraint ) = @_;
702              
703 140         216 eval { $self -> get( $constraint ) -> check( $value ) };
  140         340  
704              
705 140 100       502 if( $@ ) {
706              
707 86 50 33     465 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
708              
709 86         164 return false;
710              
711             } else {
712              
713 0         0 die( $@ );
714             }
715             };
716              
717 54         104 return true;
718             }
719              
720             =head2 assert( Any $value, Str $constraint )
721              
722             Проверяет, является ли C<$value> значением типа C<$constraint>.
723              
724             Возвращает C в случае, если является, иначе - вызывает C.
725              
726             =cut
727              
728             sub assert {
729              
730 0     0 1 0 my ( $self, $value, $constraint ) = @_;
731              
732 0         0 eval { $self -> get( $constraint ) -> check( $value ) };
  0         0  
733              
734 0 0       0 if( $@ ) {
735              
736 0 0 0     0 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
737              
738 0         0 confess( join( "\n", ( $self -> create_error_message( $@ ), '' ) ) );
739              
740             } else {
741              
742 0         0 die( $@ );
743             }
744             };
745              
746 0         0 return true;
747             }
748              
749             =head2 create_error_message( Salvation::TC::Exception::WrongType $e )
750              
751             =cut
752              
753             sub create_error_message {
754              
755 0     0 1 0 my ( $self, $e ) = @_;
756              
757 0         0 my @stack = ( $e );
758 0         0 my @lines = ();
759              
760 0         0 while( defined( my $node = shift( @stack ) ) ) {
761              
762 0 0       0 if( $node -> isa( 'Salvation::TC::Exception::WrongType::TC' ) ) {
763              
764 0         0 my $str = '';
765              
766 0 0       0 if( defined( my $param_name = $node -> getParamName() ) ) {
767              
768 0         0 $str = sprintf(
769             'Value %s for parameter "%s" does not match type constraint %s',
770             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
771             $param_name, $node -> getType(),
772             );
773              
774             } else {
775              
776 0         0 $str = sprintf(
777             'Value %s does not match type constraint %s',
778             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
779             $node -> getType(),
780             );
781             }
782              
783              
784 0 0       0 if( defined( my $prev = $node -> getPrev() ) ) {
785              
786 0         0 push( @lines, "${str} because:" );
787              
788 0 0       0 if( ref( $prev ) eq 'ARRAY' ) {
789              
790 0         0 my $i = 0;
791              
792 0         0 foreach my $e ( @$prev ) {
793              
794 0         0 push( @lines,
795             ++$i . ': ',
796 0         0 map( { "\t$_" } $self -> create_error_message( $e ) )
797             );
798             }
799              
800             } else {
801              
802 0         0 push( @stack, $prev );
803             }
804              
805             } else {
806              
807 0         0 push( @lines, $str );
808             }
809              
810             } else {
811              
812 0         0 push( @lines, sprintf(
813             'Value %s does not match type constraint %s',
814             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
815             $node -> getType(),
816             ) );
817             }
818             }
819              
820 0         0 return @lines;
821             }
822              
823             =head2 coerce( Any $value, Str $constraint )
824              
825             Пытается привести значение C<$value> к значению типа C<$constraint>.
826              
827             Если приведение прошло успешно - возвращает изменённое значение, иначе -
828             возвращает C<$value> без изменения*.
829              
830             * Для совместимости с API Moose.
831              
832             =cut
833              
834             sub coerce {
835              
836 8     8 1 1393 my ( $self, $value, $constraint ) = @_;
837              
838 8         16 return $self -> get( $constraint ) -> coerce( $value );
839             }
840              
841             =head2 ensure( Any $value, Str $constraint )
842              
843             Пытается привести значение C<$value> к значению типа C<$constraint>.
844              
845             Если приведение прошло успешно - возвращает изменённое значение, иначе -
846             вызывает C.
847              
848             =cut
849              
850             sub ensure {
851              
852 0     0 1   my ( $self, $value, $constraint ) = @_;
853              
854 0           $value = $self -> coerce( $value, $constraint );
855              
856 0           $self -> assert( $value, $constraint );
857              
858 0           return $value;
859             }
860              
861             __PACKAGE__ -> init_regular_cases();
862              
863             1;
864              
865             __END__