File Coverage

blib/lib/Type/Library/Compiler.pm
Criterion Covered Total %
statement 14 62 22.5
branch 0 14 0.0
condition 0 3 0.0
subroutine 5 14 35.7
pod 3 3 100.0
total 22 96 22.9


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