File Coverage

blib/lib/Type/Library/Compiler.pm
Criterion Covered Total %
statement 41 62 66.1
branch 2 14 14.2
condition 0 3 0.0
subroutine 10 14 71.4
pod 3 3 100.0
total 56 96 58.3


line stmt bran cond sub pod time code
1 2     2   1126967 use 5.008001;
  2         9  
2 2     2   14 use strict;
  2         5  
  2         74  
3 2     2   9 use warnings;
  2         5  
  2         256  
4              
5             package Type::Library::Compiler;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.008';
9              
10 2     2   1434 use Type::Library::Compiler::Mite -all;
  2         7  
  2         17  
11 2     2   35 use B ();
  2         6  
  2         3808  
12              
13             has types => (
14             is => ro,
15             isa => 'Map[NonEmptyStr,Object]',
16 0     0   0 builder => sub { [] },
17             );
18              
19             has pod => (
20             is => rw,
21             isa => 'Bool',
22             coerce => true,
23             default => true,
24             );
25              
26             has destination_module => (
27             is => ro,
28             isa => 'NonEmptyStr',
29             required => true,
30             );
31              
32             has constraint_module => (
33             is => ro,
34             isa => 'NonEmptyStr',
35             builder => sub {
36 1     1   11 sprintf '%s::TypeConstraint', shift->destination_module;
37             },
38             );
39              
40             has destination_filename => (
41             is => lazy,
42             isa => 'NonEmptyStr',
43             builder => sub {
44 0     0   0 ( my $module = shift->destination_module ) =~ s{::}{/}g;
45 0         0 return sprintf 'lib/%s.pm', $module;
46             },
47             );
48              
49             sub compile_to_file {
50 0     0 1 0 my $self = shift;
51              
52 0 0       0 open( my $fh, '>', $self->destination_filename )
53             or croak( 'Could not open %s: %s', $self->destination_filename, $! );
54              
55 0         0 print { $fh } $self->compile_to_string;
  0         0  
56              
57 0 0       0 close( $fh )
58             or croak( 'Could not close %s: %s', $self->destination_filename, $! );
59              
60 0         0 return;
61             }
62              
63             sub compile_to_string {
64 1     1 1 11 my $self = shift;
65              
66 1 50       3 my @type_names = sort keys %{ $self->types or {} };
  1         13  
67              
68 1         13 my $code = '';
69 1         8 $code .= $self->_compile_header;
70 1         11 $code .= $self->_compile_type( $self->types->{$_}, $_ ) for @type_names;
71 1         4 $code .= $self->_compile_footer;
72              
73 1 50       6 if ( $self->pod ) {
74 1         45 $code .= $self->_compile_pod_header;
75 1         44 $code .= $self->_compile_pod_type( $self->types->{$_}, $_ ) for @type_names;
76 1         41 $code .= $self->_compile_pod_footer;
77             }
78              
79 1         32 return $code;
80             }
81              
82             sub _compile_header {
83 1     1   2 my $self = shift;
84              
85 1         48 return sprintf <<'CODE', $self->destination_module, $self->VERSION, $self->constraint_module, $self->destination_module;
86             use 5.008001;
87             use strict;
88             use warnings;
89              
90             package %s;
91              
92             use Exporter ();
93             use Carp qw( croak );
94              
95             our $TLC_VERSION = "%s";
96             our @ISA = qw( Exporter );
97             our @EXPORT;
98             our @EXPORT_OK;
99             our %%EXPORT_TAGS = (
100             is => [],
101             types => [],
102             assert => [],
103             );
104              
105             BEGIN {
106             package %s;
107             our $LIBRARY = "%s";
108              
109             use overload (
110             fallback => !!1,
111             '|' => 'union',
112             bool => sub { !! 1 },
113             '""' => sub { shift->{name} },
114             '&{}' => sub {
115             my $self = shift;
116             return sub { $self->assert_return( @_ ) };
117             },
118             );
119              
120             sub union {
121             my @types = grep ref( $_ ), @_;
122             my @checks = map $_->{check}, @types;
123             bless {
124             check => sub { for ( @checks ) { return 1 if $_->(@_) } return 0 },
125             name => join( '|', map $_->{name}, @types ),
126             union => \@types,
127             }, __PACKAGE__;
128             }
129              
130             sub check {
131             $_[0]{check}->( $_[1] );
132             }
133              
134             sub get_message {
135             sprintf '%%s did not pass type constraint "%%s"',
136             defined( $_[1] ) ? $_[1] : 'Undef',
137             $_[0]{name};
138             }
139              
140             sub validate {
141             $_[0]{check}->( $_[1] )
142             ? undef
143             : $_[0]->get_message( $_[1] );
144             }
145              
146             sub assert_valid {
147             $_[0]{check}->( $_[1] )
148             ? 1
149             : Carp::croak( $_[0]->get_message( $_[1] ) );
150             }
151              
152             sub assert_return {
153             $_[0]{check}->( $_[1] )
154             ? $_[1]
155             : Carp::croak( $_[0]->get_message( $_[1] ) );
156             }
157              
158             sub to_TypeTiny {
159             if ( $_[0]{union} ) {
160             require Type::Tiny::Union;
161             return 'Type::Tiny::Union'->new(
162             display_name => $_[0]{name},
163             type_constraints => [ map $_->to_TypeTiny, @{ $_[0]{union} } ],
164             );
165             }
166             if ( my $library = $_[0]{library} ) {
167             local $@;
168             eval "require $library; 1" or die $@;
169             my $type = $library->get_type( $_[0]{library_name} );
170             return $type if $type;
171             }
172             require Type::Tiny;
173             my $check = $_[0]{check};
174             my $name = $_[0]{name};
175             return 'Type::Tiny'->new(
176             name => $name,
177             constraint => sub { $check->( $_ ) },
178             inlined => sub { sprintf '%%s::is_%%s(%%s)', $LIBRARY, $name, pop }
179             );
180             }
181              
182             sub DOES {
183             return 1 if $_[1] eq 'Type::API::Constraint';
184             return 1 if $_[1] eq 'Type::Library::Compiler::TypeConstraint';
185             shift->SUPER::DOES( @_ );
186             }
187             };
188              
189             CODE
190             }
191              
192             sub _compile_footer {
193 1     1   3 my $self = shift;
194              
195 1         3 return <<'CODE';
196              
197             1;
198             __END__