File Coverage

blib/lib/Salvation/TC.pm
Criterion Covered Total %
statement 149 186 80.1
branch 36 52 69.2
condition 39 76 51.3
subroutine 42 45 93.3
pod 25 25 100.0
total 291 384 75.7


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   63583 use strict;
  4         7  
  4         128  
33 4     4   15 use warnings;
  4         4  
  4         93  
34 4     4   1769 use boolean;
  4         10334  
  4         13  
35              
36 4     4   276 use Carp 'confess';
  4         5  
  4         178  
37 4     4   1909 use Module::Load ();
  4         3386  
  4         85  
38 4     4   21 use Scalar::Util 'blessed';
  4         4  
  4         327  
39 4     4   1903 use Class::Inspector ();
  4         11317  
  4         80  
40 4     4   1795 use Devel::PartialDump ();
  4         176158  
  4         106  
41              
42 4     4   1461 use Salvation::TC::Parser ();
  4         6  
  4         64  
43 4     4   1439 use Salvation::TC::Meta::Type ();
  4         7  
  4         64  
44 4     4   1404 use Salvation::TC::Meta::Type::Maybe ();
  4         8  
  4         59  
45 4     4   1317 use Salvation::TC::Meta::Type::Union ();
  4         7  
  4         64  
46 4     4   19 use Salvation::TC::Exception::WrongType ();
  4         5  
  4         7624  
47              
48             our $VERSION = 0.12;
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 6 my ( $self ) = @_;
64              
65 4         11 my %table = (
66             Int => 'Number::Integer',
67             Num => 'Number::Float',
68             );
69              
70 4         23 while( my ( $alias, $type ) = each( %table ) ) {
71              
72 8         17 $type = $self -> get( $type );
73              
74 8         37 $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         9 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         130 $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 99 my ( $self ) = @_;
119              
120             return $table //= [
121             [ 'Salvation::TC::Type' => {
122             validator => sub {
123 76     76   148 $self -> gen_salvation_tc_type_validator( @_ );
124             },
125             signed_type_generator => sub {
126 76     76   140 $self -> gen_salvation_tc_type_signer( @_ );
127             },
128             length_type_generator => sub {
129 76     76   138 $self -> gen_salvation_tc_type_length_check( @_ );
130             }
131 77   100     294 } ],
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 97 my ( $self, $class ) = @_;
176              
177             return sub {
178              
179 278     278   918 $class -> Check( $_[ 0 ] );
180 76         291 };
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 83 my ( $self, $class ) = @_;
223              
224 76 100       733 return undef unless( $class -> can( 'create_validator_from_sig' ) );
225              
226             return sub {
227              
228 15     15   69 $class -> create_validator_from_sig( @_[ 0, 1 ] );
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 92 my ( $self, $class ) = @_;
273              
274 76 100       438 return undef unless( $class -> can( 'create_length_validator' ) );
275              
276             return sub {
277              
278 24     24   93 $class -> create_length_validator( @_[ 0, 1 ] );
279 20         64 };
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   75 ( defined $_[ 0 ] && blessed $_[ 0 ] && $_[ 0 ] -> isa( $class ) )
      66        
326             || Salvation::TC::Exception::WrongType -> throw(
327             type => $class, value => $_[ 0 ]
328             )
329 1         7 };
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 125     125 1 262 my ( $self, $name, @rest ) = @_;
368              
369 125   33     717 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 125     125 1 539 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     10 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 15 my ( $self, $name, @rest ) = @_;
408              
409 9   33     64 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 45 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 110 my ( $self, $name, $class, @rest ) = @_;
428              
429 46   33     363 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 512     512 1 505 my ( $self, $name ) = @_;
453              
454 512   33     2507 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 140     140 1 605 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 140     140 1 160 my ( $self, $str ) = @_;
493              
494 140         236 return $self -> materialize_type(
495             $self -> get_type_parser() -> tokenize_type_str( $str, {} )
496             );
497             }
498              
499             =head2 materialize_type( HashRef( HashRef :opts!, ArrayRef[HashRef] :data! ) input )
500              
501             Превращает токены �� классы типов.
502              
503             =cut
504              
505             sub materialize_type {
506              
507 325     325 1 369 my ( $self, $input ) = @_;
508 325         572 my ( $opts, $tokens ) = @$input{ 'opts', 'data' };
509              
510 325 100       528 if( scalar( @$tokens ) == 1 ) {
511              
512 316 100       720 if( exists $tokens -> [ 0 ] -> { 'type' } ) {
    100          
    100          
    100          
    50          
513              
514 220         432 return $self -> get_or_create_simple_type( $tokens -> [ 0 ] -> { 'type' } );
515              
516             } elsif( exists $tokens -> [ 0 ] -> { 'maybe' } ) {
517              
518 2         11 my $type = $self -> materialize_type( $tokens -> [ 0 ] -> { 'maybe' } );
519 2         8 my $name = sprintf( 'Maybe[%s]', $type -> name() );
520              
521 2   66     4 return ( $self -> get_type( $name ) // $self -> setup_maybe_type(
522             $name, validator => $type -> validator(), base => $type,
523             ) );
524              
525             } elsif( exists $tokens -> [ 0 ] -> { 'class' } ) {
526              
527 51         147 my $base = $self -> materialize_type( $tokens -> [ 0 ] -> { 'base' } );
528 51         95 my $inner = $self -> materialize_type( $tokens -> [ 0 ] -> { 'param' } );
529 51         124 my $name = sprintf( '%s[%s]', $base -> name(), $inner -> name() );
530              
531 51   66     89 return ( $self -> get_type( $name ) // $self -> setup_parameterized_type(
532             $name, $tokens -> [ 0 ] -> { 'class' }, base => $base,
533             validator => $base -> validator(), inner => $inner,
534             length_type_generator => $base -> length_type_generator(),
535             ) );
536              
537             } elsif( exists $tokens -> [ 0 ] -> { 'signed' } ) {
538              
539 15         22 my $data = $tokens -> [ 0 ] -> { 'signed' };
540              
541 15         83 my $type = $self -> materialize_type( {
542             opts => {},
543             data => [ $data -> { 'type' } ],
544             } );
545 15         66 my $name = sprintf( '%s%s', $type -> name(), $data -> { 'source' } );
546              
547 15         28 my $present_type = $self -> get_type( $name );
548              
549 15 50       31 return $present_type if( defined $present_type );
550              
551 15         15 my ( $sig_tokens, $sig_opts ) = @{ $data -> { 'signature' } }{ 'data', 'opts' };
  15         29  
552              
553 15         25 foreach my $el ( @$sig_tokens ) {
554              
555 19         32 $el -> { 'type' } = $self -> materialize_type( $el -> { 'type' } );
556             }
557              
558 15 100       89 my $method = ( $type -> isa( 'Salvation::TC::Meta::Type::Parameterized' )
559             ? 'setup_parameterized_type'
560             : 'setup_type' );
561              
562 15 100       60 return $self -> $method( $name,
563             ( ( $method eq 'setup_parameterized_type' ) ? (
564             ref( $type ),
565             inner => $type -> inner(),
566             ) : () ),
567             validator => $type -> sign( $sig_tokens, $sig_opts ),
568             length_type_generator => $type -> length_type_generator(),
569             signature => $sig_tokens,
570             base => $type, options => $sig_opts,
571             );
572              
573             } elsif( exists $tokens -> [ 0 ] -> { 'length' } ) {
574              
575 28         35 my $data = $tokens -> [ 0 ] -> { 'length' };
576              
577 28         109 my $type = $self -> materialize_type( {
578             opts => {},
579             data => [ $data -> { 'type' } ],
580             } );
581 28   100     176 my $name = sprintf( '%s{%s,%s}', $type -> name(), $data -> { 'min' }, ( $data -> { 'max' } // '' ) );
582              
583 28 100       161 my $method = ( $type -> isa( 'Salvation::TC::Meta::Type::Parameterized' )
584             ? 'setup_parameterized_type'
585             : 'setup_type' );
586              
587 28 100 66     72 return ( $self -> get_type( $name ) // $self -> $method( $name,
    100          
588             ( ( $method eq 'setup_parameterized_type' ) ? (
589             ref( $type ),
590             inner => $type -> inner(),
591             ) : () ),
592             validator => $type -> length_checker( @$data{ 'min', 'max' } ),
593             signed_type_generator => $type -> signed_type_generator(),
594             ( $type -> has_signature() ? (
595             signature => $type -> signature(),
596             options => $type -> options(),
597             ) : () ),
598             base => $type,
599             ) );
600              
601             } else {
602              
603 0         0 require Data::Dumper;
604              
605 0         0 die( 'Unknown token: ' . Data::Dumper::Dumper( $tokens ) );
606             }
607              
608             } else {
609              
610 9         14 my @types = ();
611              
612 9         16 foreach my $token ( @$tokens ) {
613              
614 19         68 push( @types, $self -> materialize_type( {
615             opts => {},
616             data => [ $token ],
617             } ) );
618             }
619              
620 9         22 my $name = join( '|', map( { $_ -> name() } @types ) );
  19         41  
621              
622 9   33     22 return ( $self -> get_type( $name ) // $self -> setup_union_type(
623             $name, types => \@types
624             ) );
625             }
626             }
627              
628             =head2 simple_type_class_ns()
629              
630             =cut
631              
632             sub simple_type_class_ns {
633              
634 220     220 1 606 return 'Salvation::TC::Type';
635             }
636              
637             =head2 get_or_create_simple_type( Str $str )
638              
639             Возвращает базовый тип с именем C<$str>.
640              
641             =cut
642              
643             sub get_or_create_simple_type {
644              
645 220     220 1 246 my ( $self, $str ) = @_;
646              
647 220         344 my $salvation_tc_type_str = sprintf( '%s::%s', $self -> simple_type_class_ns(), $str );
648              
649 220   100     358 my $type = ( $self -> get_type( $str ) // $self -> get_type( $salvation_tc_type_str ) );
650              
651 220 100       607 return $type if( defined $type );
652              
653             {
654 77         63 local $SIG{ '__DIE__' } = 'DEFAULT';
  77         271  
655              
656 77 50 66     300 if(
      66        
      66        
657             ! Class::Inspector -> loaded( $str )
658             && ! eval{ Module::Load::load( $str ); 1 }
659             && (
660             Class::Inspector -> loaded( $salvation_tc_type_str )
661             || eval{ Module::Load::load( $salvation_tc_type_str ); 1 }
662             )
663             ) {
664              
665 76         5452 $str = $salvation_tc_type_str;
666             }
667             }
668              
669 77         168 my $validator = undef;
670 77         64 my $signed_type_generator = undef;
671 77         73 my $length_type_generator = undef;
672              
673 77         90 foreach my $spec ( @{ $self -> get_known_types() } ) {
  77         250  
674              
675 77 100       561 if( $str -> isa( $spec -> [ 0 ] ) ) {
676              
677 76         152 $validator = $spec -> [ 1 ] -> { 'validator' } -> ( $str );
678 76         145 $signed_type_generator = $spec -> [ 1 ] -> { 'signed_type_generator' } -> ( $str );
679 76         162 $length_type_generator = $spec -> [ 1 ] -> { 'length_type_generator' } -> ( $str );
680              
681 76         99 last;
682             }
683             }
684              
685 77   66     235 return $self -> setup_type( $str,
686             validator => ( $validator // $self -> gen_class_type_validator( $str ) ),
687             signed_type_generator => $signed_type_generator,
688             length_type_generator => $length_type_generator,
689             );
690             }
691              
692             {
693             my %cache = ();
694              
695             =head2 get( Str $constraint )
696              
697             Возвращает объект для типа C<$constraint>.
698              
699             =cut
700              
701             sub get {
702              
703 256     256 1 364 my ( $self, $constraint ) = @_;
704              
705 256   33     1764 return $cache{ ref( $self ) || $self } -> { $constraint } //= $self -> parse_type( $constraint );
      66        
706             }
707             }
708              
709             =head2 is( Any $value, Str $constraint )
710              
711             Проверяет, является ли C<$value> значением типа C<$constraint>.
712              
713             Возвращает C в случае, если является, иначе - возвращает C.
714              
715             =cut
716              
717             sub is {
718              
719 146     146 1 50107 my ( $self, $value, $constraint ) = @_;
720              
721             {
722 146         169 local $SIG{ '__DIE__' } = 'DEFAULT';
  146         490  
723              
724 146         177 eval { $self -> get( $constraint ) -> check( $value ) };
  146         411  
725             }
726              
727 146 100       618 if( $@ ) {
728              
729 90 50 33     556 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
730              
731 90         195 return false;
732              
733             } else {
734              
735 0         0 die( $@ );
736             }
737             };
738              
739 56         134 return true;
740             }
741              
742             =head2 assert( Any $value, Str $constraint )
743              
744             Проверяет, является ли C<$value> значением типа C<$constraint>.
745              
746             Возвращает C в случае, если является, иначе - вызывает C.
747              
748             =cut
749              
750             sub assert {
751              
752 0     0 1 0 my ( $self, $value, $constraint ) = @_;
753              
754             {
755 0         0 local $SIG{ '__DIE__' } = 'DEFAULT';
  0         0  
756              
757 0         0 eval { $self -> get( $constraint ) -> check( $value ) };
  0         0  
758             }
759              
760 0 0       0 if( $@ ) {
761              
762 0 0 0     0 if( blessed( $@ ) && $@ -> isa( 'Salvation::TC::Exception::WrongType' ) ) {
763              
764 0         0 confess( join( "\n", ( $self -> create_error_message( $@ ), '' ) ) );
765              
766             } else {
767              
768 0         0 die( $@ );
769             }
770             };
771              
772 0         0 return true;
773             }
774              
775             =head2 create_error_message( Salvation::TC::Exception::WrongType $e )
776              
777             =cut
778              
779             sub create_error_message {
780              
781 0     0 1 0 my ( $self, $e ) = @_;
782              
783 0         0 my @stack = ( $e );
784 0         0 my @lines = ();
785              
786 0         0 while( defined( my $node = shift( @stack ) ) ) {
787              
788 0 0       0 if( $node -> isa( 'Salvation::TC::Exception::WrongType::TC' ) ) {
789              
790 0         0 my $str = '';
791              
792 0 0       0 if( defined( my $param_name = $node -> getParamName() ) ) {
793              
794 0         0 $str = sprintf(
795             'Value %s for parameter "%s" does not match type constraint %s',
796             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
797             $param_name, $node -> getType(),
798             );
799              
800             } else {
801              
802 0         0 $str = sprintf(
803             'Value %s does not match type constraint %s',
804             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
805             $node -> getType(),
806             );
807             }
808              
809              
810 0 0       0 if( defined( my $prev = $node -> getPrev() ) ) {
811              
812 0         0 push( @lines, "${str} because:" );
813              
814 0 0       0 if( ref( $prev ) eq 'ARRAY' ) {
815              
816 0         0 my $i = 0;
817              
818 0         0 foreach my $e ( @$prev ) {
819              
820 0         0 push( @lines,
821             ++$i . ': ',
822 0         0 map( { "\t$_" } $self -> create_error_message( $e ) )
823             );
824             }
825              
826             } else {
827              
828 0         0 push( @stack, $prev );
829             }
830              
831             } else {
832              
833 0         0 push( @lines, $str );
834             }
835              
836             } else {
837              
838 0         0 push( @lines, sprintf(
839             'Value %s does not match type constraint %s',
840             Devel::PartialDump -> new() -> dump( $node -> getValue() ),
841             $node -> getType(),
842             ) );
843             }
844             }
845              
846 0         0 return @lines;
847             }
848              
849             =head2 coerce( Any $value, Str $constraint )
850              
851             Пытается привести значение C<$value> к значению типа C<$constraint>.
852              
853             Если приведение прошло успешно - возвращает изменённое значение, иначе -
854             возвращает C<$value> без изменения*.
855              
856             * Для совместимости с API Moose.
857              
858             =cut
859              
860             sub coerce {
861              
862 8     8 1 1270 my ( $self, $value, $constraint ) = @_;
863              
864 8         16 return $self -> get( $constraint ) -> coerce( $value );
865             }
866              
867             =head2 ensure( Any $value, Str $constraint )
868              
869             Пытается привести значение C<$value> к значению типа C<$constraint>.
870              
871             Если приведение прошло успешно - возвращает изменённое значение, иначе -
872             вызывает C.
873              
874             =cut
875              
876             sub ensure {
877              
878 0     0 1   my ( $self, $value, $constraint ) = @_;
879              
880 0           $value = $self -> coerce( $value, $constraint );
881              
882 0           $self -> assert( $value, $constraint );
883              
884 0           return $value;
885             }
886              
887             __PACKAGE__ -> init_regular_cases();
888              
889             1;
890              
891             __END__