File Coverage

blib/lib/Exporter/Declare/Magic/Parser.pm
Criterion Covered Total %
statement 55 79 69.6
branch 22 48 45.8
condition 13 27 48.1
subroutine 10 10 100.0
pod 2 4 50.0
total 102 168 60.7


line stmt bran cond sub pod time code
1             package Exporter::Declare::Magic::Parser;
2 1     1   5 use strict;
  1         2  
  1         36  
3 1     1   5 use warnings;
  1         1  
  1         31  
4              
5 1     1   5 use base 'Devel::Declare::Parser';
  1         2  
  1         95  
6 1     1   5 use Devel::Declare::Interface;
  1         2  
  1         92  
7 1     1   5 BEGIN { Devel::Declare::Interface::register_parser( 'export' )};
8              
9             __PACKAGE__->add_accessor( '_inject' );
10             __PACKAGE__->add_accessor( 'parser' );
11              
12             sub inject {
13 6     6 1 229 my $self = shift;
14 6         6 my @out;
15              
16 6 50       14 if( my $items = $self->_inject() ) {
17 0         0 my $ref = ref( $items );
18 0 0       0 if ( $ref eq 'ARRAY' ) {
    0          
19 0         0 push @out => @$items;
20             }
21             elsif ( !$ref ) {
22 0         0 push @out => $items;
23             }
24             else {
25 0         0 $self->bail( "$items is not a valid injection" );
26             }
27             }
28 6         43 return @out;
29             }
30              
31             sub _check_parts {
32 10     10   12 my $self = shift;
33 10         415 $self->bail( "You must provide a name to " . $self->name . "()" )
34 10 50 33     26 if ( !$self->parts || !@{ $self->parts });
35              
36 10 50       230 if ( @{ $self->parts } > 3 ) {
  10         200  
37 0         0 ( undef, undef, undef, my @bad ) = @{ $self->parts };
  0         0  
38 0         0 $self->bail(
39             "Syntax error near: " . join( ' and ',
40 0         0 map { $self->format_part($_)} @bad
41             )
42             );
43             }
44             }
45              
46             sub sort_parts {
47 8     8 0 214 my $self = shift;
48              
49 8 100       403 if ($self->parts->[0] =~ m/^[\%\$\&\@]/) {
50 1         209 $self->parts->[0] = [
51             $self->parts->[0],
52             undef,
53             ];
54             }
55              
56             $self->bail(
57 0         0 "Parsing Error, unrecognized tokens: "
58 8 50       459 . join( ', ', map {"'$_'"} $self->has_non_string_or_quote_parts )
59             ) if $self->has_non_string_or_quote_parts;
60              
61 8         283 my ( @names, @specs );
62 8         7 for my $part (@{ $self->parts }) {
  8         22  
63 10 50       51 $self->bail( "Bad part: $part" ) unless ref($part);
64 10 50 66     39 $part->[1] && $part->[1] eq '('
65             ? ( push @specs => $part )
66             : ( push @names => $part )
67             }
68              
69 8 50       19 if ( @names > 2 ) {
70 0         0 ( undef, undef, my @bad ) = @names;
71 0         0 $self->bail(
72             "Syntax error near: " . join( ' and ',
73 0         0 map { $self->format_part($_)} @bad
74             )
75             );
76             }
77              
78 8         15 return ( \@names, \@specs );
79             }
80              
81             sub strip_prototype {
82 10     10 0 9 my $self = shift;
83 10         366 my $parts = $self->parts;
84 10 50       253 return unless @$parts > 3;
85 0 0       0 return unless ref( $parts->[2] );
86 0 0       0 return unless $parts->[2]->[0] eq 'sub';
87 0 0       0 return unless ref( $parts->[3] );
88 0 0       0 return unless $parts->[3]->[1] eq '(';
89 0 0       0 return unless !$parts->[2]->[1];
90 0         0 $self->prototype(
91             $parts->[3]->[1]
92             . $parts->[3]->[0]
93             . $self->end_quote($parts->[3]->[1])
94             );
95 0         0 delete $parts->[3];
96             }
97              
98             sub rewrite {
99 10     10 1 16593 my $self = shift;
100              
101 10         188 $self->strip_prototype;
102 10         22 $self->_check_parts;
103              
104 10   66     234 my $is_arrow = $self->parts->[1]
105             && ($self->parts->[1] eq '=>' || $self->parts->[1] eq ',');
106 10 100 66     313 if ( $is_arrow && $self->parts->[2] ) {
107 2         18 my $is_ref = !ref( $self->parts->[2] );
108 2 100       17 my $is_sub = $is_ref ? 0 : $self->parts->[2]->[0] eq 'sub';
109              
110 2 100 66     16 if (( $is_arrow && $is_ref )
  1 50 66     5  
      33        
      33        
111 0         0 || ( @{ $self->parts } == 1 )) {
112 1         7 $self->new_parts([ $self->parts->[0], $self->parts->[2] ]);
113 1         12 return 1;
114             }
115             elsif (( $is_arrow && $is_sub )
116             || ( @{ $self->parts } == 1 )) {
117 1         20 $self->new_parts([ $self->parts->[0] ]);
118 1         12 return 1;
119             }
120             }
121              
122 8         18 my ( $names, $specs ) = $self->sort_parts();
123 8 100       34 $self->parser( $names->[1] ? $names->[1]->[0] : undef );
124 8 100       52 push @$names => 'undef' unless @$names > 1;
125 8         26 $self->new_parts( $names );
126              
127 8 50       46 if ( @$specs ) {
128 0 0       0 $self->bail( "Too many spec defenitions" )
129             if @$specs > 1;
130 0   0     0 my $specs = eval "{ " . $specs->[0]->[0] . " }"
131             || $self->bail($@);
132 0         0 $self->_inject( delete $specs->{ inject });
133             }
134              
135 8         16 1;
136             }
137              
138             1;
139              
140             __END__