File Coverage

blib/lib/Type/TinyX/Facets.pm
Criterion Covered Total %
statement 72 72 100.0
branch 7 12 58.3
condition 5 8 62.5
subroutine 18 18 100.0
pod 3 3 100.0
total 105 113 92.9


line stmt bran cond sub pod time code
1             package Type::TinyX::Facets;
2              
3             # ABSTRACT: Easily create a facet parameterized Type::Tiny type
4              
5 1     1   319973 use strict;
  1         10  
  1         29  
6 1     1   5 use warnings;
  1         3  
  1         40  
7              
8             our $VERSION = '1.3';
9              
10 1     1   8 use B ();
  1         1  
  1         13  
11 1     1   5 use Exporter::Tiny ();
  1         2  
  1         12  
12 1     1   4 use Eval::TypeTiny ();
  1         2  
  1         14  
13 1     1   469 use Safe::Isa;
  1         486  
  1         187  
14              
15 1     1   457 use parent 'Exporter::Tiny';
  1         301  
  1         6  
16             our @EXPORT = qw( with_facets facet facetize );
17              
18             # handle both generations of Type::Tiny interfaces to create library
19             # subs. only used by facetize.
20             my $type_to_coderef
21             = exists &Eval::TypeTiny::type_to_coderef
22             ? \&Eval::TypeTiny::type_to_coderef
23             : do {
24             require Type::Library;
25             exists &Type::Library::_mksub;
26             }
27             ? sub { $_[0]->library->_mksub( $_[0] ) }
28             : _croak( "can't find type-to-coderef function?" );
29              
30             sub _croak {
31 4     4   94 require Carp;
32 4         602 goto &Carp::croak;
33             }
34              
35             my %FACET;
36              
37              
38              
39              
40              
41              
42              
43              
44              
45              
46              
47              
48              
49              
50              
51              
52              
53              
54              
55              
56              
57              
58              
59              
60              
61              
62              
63              
64             sub facet {
65              
66 6     6 1 10369 my ( $name, $coderef ) = @_;
67              
68 6         13 my $caller = caller();
69              
70 6   100     24 $FACET{$caller} ||= {};
71 6         21 $FACET{$caller}{$name} = $coderef;
72             }
73              
74              
75              
76              
77              
78              
79              
80              
81              
82              
83              
84              
85              
86              
87              
88              
89              
90              
91              
92              
93              
94              
95             sub with_facets {
96 3     3 1 1204 _with_facets( scalar caller(), @_ );
97             }
98              
99              
100             sub _with_facets {
101              
102 6     6   16 my ( $caller, $facets ) = ( shift, shift );
103              
104 6         10 my $FACET = $FACET{$caller};
105              
106             my @facets = map {
107 12         145 my ( $facet, $sub ) = @{$_};
  12         24  
108 12   33     57 $sub ||= $FACET->{$facet} || _croak( "unknown facet: $facet" );
      66        
109 12         36 [ $facet, $sub ];
110 6         10 } @{ Exporter::Tiny::mkopt( $facets ) };
  6         15  
111              
112              
113             # so blithely stolen from Type::XSD::Lite. Thanks TOBYINK!
114 6         14 my %return;
115             my $IG = $return{inline_generator} = sub {
116 30     30   290 my %p_not_destroyed = @_;
117             return sub {
118 30         1930 my %p = %p_not_destroyed; # copy;
119 30         60 my $var = $_[1];
120 30         125 my @r = map $_->[1]->( \%p, $var, $_->[0] ), @facets;
121 24 50       704 _croak sprintf(
    100          
122             'Attempt to parameterize type "%s" with unrecognised parameter%s %s',
123             $_[0]->name,
124             scalar( keys %p ) == 1 ? '' : 's',
125             Type::Utils::english_list( map( qq["$_"], sort keys %p ) ),
126             ) if keys %p;
127 20         62 return ( undef, @r );
128 30         163 };
129 6         26 };
130              
131             $return{constraint_generator} = sub {
132 1     1   533 my $base = do { no warnings 'once'; $Type::Tiny::parameterize_type };
  1     20   3  
  1         393  
  20         38785  
  20         37  
133 20 50       96 my %params = @_ or return $base;
134 20         77 my @checks = $IG->( %params )->( $base, '$_[0]' );
135 10         90 $checks[0] = $base->inline_check( '$_[0]' );
136 10         1207 my $sub = sprintf( 'sub { %s }', join( ' and ', map "($_)", @checks ), );
137             ## no critic (ProhibitStringyEval)
138 10 50       1238 eval( $sub ) or _croak "could not build sub: $@\n\nCODE: $sub\n";
139 6         37 };
140              
141             $return{name_generator} = sub {
142 10     10   266 my ( $s, %a ) = @_;
143 10         136 sprintf( '%s[%s]', $s, join q[,], map sprintf( "%s=>%s", $_, B::perlstring $a{$_} ), sort keys %a );
144 6         31 };
145              
146 6         39 return ( %return, @_ );
147             }
148              
149              
150              
151              
152              
153              
154              
155              
156              
157              
158              
159              
160              
161              
162              
163              
164              
165              
166              
167              
168              
169              
170              
171              
172              
173              
174              
175              
176              
177              
178              
179              
180             sub facetize {
181              
182             # maybe at some later date, just to annoy.
183             # warnings::warnif( 'deprecated',
184             # q{'facetize' is deprecated; use 'with_facets' instead.} );
185              
186             # type may be first or last parameter
187 3 50   3 1 1600 my $self
188             = $_[-1]->$_isa( 'Type::Tiny' )
189             ? pop
190             : _croak( "type object must be last parameter\n" );
191              
192 3         73 my %args = _with_facets( scalar caller(), \@_ );
193              
194             # old skool poke at the guts. need to do this in-place, and
195             # Type::Tiny objects are pretty immutable, e.g. there is no
196             # defined API to modify them after they're creaed. which is why
197             # this approach is deprecated.
198 3         16 $self->{$_} = $args{$_} for keys %args;
199              
200 3 50       13 return if $self->is_anon;
201              
202             ## no critic( ProhibitNoStrict )
203 1     1   8 no strict qw( refs );
  1         2  
  1         41  
204 1     1   7 no warnings qw( redefine prototype );
  1         2  
  1         100  
205 3         29 *{ $self->library . '::' . $self->name } = $type_to_coderef->( $self );
  3         941  
206             }
207              
208              
209              
210             1;
211              
212             #
213             # This file is part of Type-TinyX-Facets
214             #
215             # This software is copyright (c) 2017 by Smithsonian Astrophysical Observatory.
216             #
217             # This is free software; you can redistribute it and/or modify it under
218             # the same terms as the Perl 5 programming language system itself.
219             #
220              
221             __END__