File Coverage

blib/lib/Babble/Plugin/CoreSignatures.pm
Criterion Covered Total %
statement 71 71 100.0
branch 15 16 93.7
condition n/a
subroutine 9 10 90.0
pod 0 4 0.0
total 95 101 94.0


line stmt bran cond sub pod time code
1             package Babble::Plugin::CoreSignatures;
2              
3 1     1   70017 use strictures 2;
  1         9  
  1         55  
4 1     1   833 use Moo;
  1         7452  
  1         9  
5              
6       0 0   sub extend_grammar { } # PPR::X can already parse everything we need
7              
8             # .......bbbbbSSSSSSSa
9             # sub foo :Bar ($baz) {
10              
11             # .......bSSSSSSSaaaaa
12             # sub foo ($baz) :Bar {
13              
14             sub transform_to_signatures {
15 1     1 0 2079 my ($self, $top) = @_;
16             my $tf = sub {
17 4     4   91 my $s = (my $m = shift)->submatches;
18 4 100       38 if ((my $after = $s->{after}->text) =~ /\S/) {
19 2         20 $s->{after}->replace_text('');
20 2         18 $s->{before}->replace_text($s->{before}->text.$after);
21             }
22 1         8 };
23 1         7 $self->_transform_signatures($top, $tf);
24             }
25              
26             sub transform_to_oldsignatures {
27 1     1 0 1030 my ($self, $top) = @_;
28             my $tf = sub {
29 4     4   82 my $s = (my $m = shift)->submatches;
30 4 100       29 if ((my $before = $s->{before}->text) =~ /\S/) {
31 2         12 $s->{before}->replace_text('');
32 2         12 $s->{after}->replace_text($before.$s->{after}->text);
33             }
34 1         9 };
35 1         6 $self->_transform_signatures($top, $tf);
36             }
37              
38             sub transform_to_plain {
39 9     9 0 8933 my ($self, $top) = @_;
40 9         54 $top->remove_use_argument(experimental => 'signatures');
41 9         168 $top->remove_use_argument('Mojo::Base' => '-signatures', 1);
42             my $tf = sub {
43 10     10   234 my $s = (my $m = shift)->submatches;
44              
45             # shift attributes after first before we go hunting for :prototype
46 10 100       87 if ((my $before = $s->{before}->text) =~ /\S/) {
47 8         67 $s->{before}->replace_text('');
48 8         53 $s->{after}->replace_text($before.$s->{after}->text);
49             }
50              
51 10         38 my $proto = '';
52             {
53 10         23 my $try = $s->{after};
  10         28  
54 10         30 local $try->{top_rule} = 'Attributes';
55 10         192 my $grammar = $m->grammar->clone;
56 10         1241 $grammar->add_rule(Attribute =>
57             '(?&PerlOWS) :? (?&PerlOWS)
58             (?&PerlIdentifier)
59             (?: (?= \( ) (?&PPR_X_quotelike_body) )?+'
60             )->replace_rule(Attributes =>
61             '(?=(?&PerlOWS):)(?&PerlAttribute)
62             (?&PerlAttribute)*'
63             );
64 10         39 local $try->{grammar} = $grammar;
65 10         22 my $each; $each = sub {
66 14         40 my ($attr) = @_;
67 14 100       111 if ($attr->text =~ /prototype(\(.*?\))/) {
68 7         24 $proto = $1;
69 7         38 $attr->replace_text('');
70             $each = sub {
71 2         6 my ($attr) = @_;
72 2 50       23 $attr->transform_text(sub { s/^(\s*)/${1}:/ }) unless $attr->text =~ /^\s*:/;
  2         21  
73 2         20 $each = sub {};
74 7         70 };
75             }
76 10         82 };
77 10         89 $try->each_match_of(Attribute => sub { $each->(@_) });
  16         68  
78 10         273 undef($each);
79             }
80              
81 10         173 s/\A\s*\(//, s/\)\s*\Z// for my $sig_orig = $s->{sig}->text;
82 10         236 my $grammar_re = $m->grammar_regexp;
83 10         381118 my @sig_parts = grep defined($_),
84             $sig_orig =~ /((?&PerlAssignment)) ${grammar_re}/xg;
85              
86 10         1827 my (@sig_text, @defaults);
87              
88 10         79 foreach my $idx (0..$#sig_parts) {
89 9         40 my $part = $sig_parts[$idx];
90 9 100       71 if ($part =~ s/^(\S+?)\s*=\s*(.*?)(,$|$)/$1$3/) {
91 1         8 push @defaults, "$1 = $2 if \@_ <= $idx;";
92             }
93 9         48 push @sig_text, $part;
94             }
95              
96 10 100       84 my $sig_text =
97             @sig_text
98             ? 'my ('.(join ', ', @sig_text).') = @_;'
99             : '';
100 10         40 my $code = join ' ', $sig_text, @defaults;
101 10         169 $s->{body}->transform_text(sub { s/^{/{ ${code}/ });
  10         107  
102 10 100       83 if ($proto) {
103             $s->{sig}->transform_text(sub {
104 7         97 s/\A(\s*)\(.*\)(\s*)\Z/${1}${proto}${2}/;
105 7         57 });
106             } else {
107 3         13 $s->{sig}->replace_text('');
108             }
109 9         227 };
110 9         63 $self->_transform_signatures($top, $tf);
111             }
112              
113             sub _transform_signatures {
114 11     11   38 my ($self, $top, $tf) = @_;
115 11         94 my @common = (
116             '(?:', # 5.20, 5.28+
117             [ before => '(?: (?&PerlOWS) (?>(?&PerlAttributes)) )?+' ],
118             [ sig => '(?&PerlOWS) (?&PerlParenthesesList)' ], # not optional for us
119             [ after => '(?&PerlOWS)' ],
120             '|', # 5.22 - 5.26
121             [ before => '(?&PerlOWS)' ],
122             [ sig => '(?&PerlParenthesesList) (?&PerlOWS)' ], # not optional for us
123             [ after => '(?: (?>(?&PerlAttributes)) (?&PerlOWS) )?+' ],
124             ')',
125             [ body => '(?&PerlBlock)' ],
126             );
127 11         72 $top->each_match_within('SubroutineDeclaration' => [
128             'sub \b (?&PerlOWS) (?&PerlOldQualifiedIdentifier)',
129             @common,
130             ], $tf);
131 11         94 $top->each_match_within('AnonymousSubroutine' => [
132             'sub \b',
133             @common,
134             ], $tf);
135             }
136              
137             1;
138             __END__
139              
140             =head1 NAME
141              
142             Babble::Plugin::CoreSignatures - Plugin for signatures feature
143              
144             =head1 SYNOPSIS
145              
146             Supports converting from signatures syntax to plain C<@_> unpacking, for
147             example from
148              
149             sub foo :prototype($) ($sig) { }
150              
151             to
152              
153             sub foo ($) { my ($sig) = @_; }
154              
155             =head1 SEE ALSO
156              
157             L<signatures feature|feature/"The 'signatures' feature">
158              
159             =cut