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   256633 use strict;
  1         9  
  1         24  
6 1     1   5 use warnings;
  1         2  
  1         33  
7              
8             our $VERSION = '1.2';
9              
10 1     1   4 use B ();
  1         2  
  1         10  
11 1     1   4 use Exporter::Tiny ();
  1         2  
  1         10  
12 1     1   3 use Eval::TypeTiny ();
  1         2  
  1         11  
13 1     1   333 use Safe::Isa;
  1         390  
  1         113  
14              
15 1     1   324 use parent 'Exporter::Tiny';
  1         273  
  1         4  
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   85 require Carp;
32 4         532 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 8448 my ( $name, $coderef ) = @_;
67              
68 6         9 my $caller = caller();
69              
70 6   100     21 $FACET{$caller} ||= {};
71 6         14 $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 666 _with_facets( scalar caller(), @_ );
97             }
98              
99              
100             sub _with_facets {
101              
102 6     6   13 my ( $caller, $facets ) = ( shift, shift );
103              
104 6         6 my $FACET = $FACET{$caller};
105              
106             my @facets = map {
107 12         127 my ( $facet, $sub ) = @{$_};
  12         19  
108 12   33     42 $sub ||= $FACET->{$facet} || _croak( "unknown facet: $facet" );
      66        
109 12         30 [ $facet, $sub ];
110 6         8 } @{ Exporter::Tiny::mkopt( $facets ) };
  6         12  
111              
112              
113             # so blithely stolen from Type::XSD::Lite. Thanks TOBYINK!
114 6         13 my %return;
115             my $IG = $return{inline_generator} = sub {
116 30     30   222 my %p_not_destroyed = @_;
117             return sub {
118 30         1586 my %p = %p_not_destroyed; # copy;
119 30         51 my $var = $_[1];
120 30         85 my @r = map $_->[1]->( \%p, $var, $_->[0] ), @facets;
121 24 50       583 _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         49 return ( undef, @r );
128 30         134 };
129 6         21 };
130              
131             $return{constraint_generator} = sub {
132 1     1   429 my $base = do { no warnings 'once'; $Type::Tiny::parameterize_type };
  1     20   2  
  1         320  
  20         31149  
  20         28  
133 20 50       72 my %params = @_ or return $base;
134 20         57 my @checks = $IG->( %params )->( $base, '$_[0]' );
135 10         72 $checks[0] = $base->inline_check( '$_[0]' );
136 10         1009 my $sub = sprintf( 'sub { %s }', join( ' and ', map "($_)", @checks ), );
137             ## no critic (ProhibitStringyEval)
138 10 50       1002 eval( $sub ) or _croak "could not build sub: $@\n\nCODE: $sub\n";
139 6         46 };
140              
141             $return{name_generator} = sub {
142 10     10   206 my ( $s, %a ) = @_;
143 10         107 sprintf( '%s[%s]', $s, join q[,], map sprintf( "%s=>%s", $_, B::perlstring $a{$_} ), sort keys %a );
144 6         28 };
145              
146 6         31 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 1310 my $self
188             = $_[-1]->$_isa( 'Type::Tiny' )
189             ? pop
190             : _croak( "type object must be last parameter\n" );
191              
192 3         56 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         13 $self->{$_} = $args{$_} for keys %args;
199              
200 3 50       9 return if $self->is_anon;
201              
202             ## no critic( ProhibitNoStrict )
203 1     1   7 no strict qw( refs );
  1         1  
  1         34  
204 1     1   6 no warnings qw( redefine prototype );
  1         2  
  1         80  
205 3         34 *{ $self->library . '::' . $self->name } = $type_to_coderef->( $self );
  3         753  
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__