File Coverage

blib/lib/Test2/Plugin/SpecDeclare.pm
Criterion Covered Total %
statement 75 78 96.1
branch 18 24 75.0
condition 4 6 66.6
subroutine 9 9 100.0
pod 0 2 0.0
total 106 119 89.0


line stmt bran cond sub pod time code
1             package Test2::Plugin::SpecDeclare;
2 5     5   462366 use strict;
  5         11  
  5         164  
3 5     5   27 use warnings;
  5         10  
  5         175  
4              
5 5     5   2956 use Devel::Declare;
  5         23604  
  5         22  
6 5     5   3089 use B::Hooks::EndOfScope;
  5         55398  
  5         34  
7              
8 5     5   444 use Carp qw/croak/;
  5         7  
  5         3304  
9              
10             our $VERSION = '0.000003';
11              
12             sub import {
13 5     5   101689 my $class = shift;
14 5         12 my $into = caller;
15              
16 5         8 my @keywords;
17             my %params;
18 5         14 for my $arg (@_) {
19 1 50       7 if ($arg =~ m/^-(.+)$/) {
20 0         0 $params{$1} = 1;
21 0         0 next;
22             }
23 1         3 push @keywords => $arg;
24             }
25              
26 5 100 66     47 if(delete $params{spec} || !@_) {
27 4         8 my %seen;
28 4 50       8 push @keywords => grep { !$seen{$_}++ && $into->can($_) }
  84         402  
29             @Test2::Tools::Spec::EXPORT,
30             @Test2::Tools::Spec::EXPORT_OK;
31             }
32              
33 5 50       18 croak "Unknown parameter(s): " . join(',', map { "-$_" } keys %params)
  0         0  
34             if keys %params;
35              
36 5 50       15 croak "No keywords (Did you forget to load Test2::Tools::Spec, or specify a list of keywords?)"
37             unless @keywords;
38              
39             Devel::Declare->setup_for(
40             $into,
41 5         12 {map { $_ => {const => \&parser} } @keywords},
  73         164  
42             );
43             }
44              
45             sub inject {
46             on_scope_end {
47 55     55   1478 my $linestr = Devel::Declare::get_linestr;
48 55         77 my $offset = Devel::Declare::get_linestr_offset;
49 55         86 substr($linestr, $offset, 0) = ', __LINE__;';
50 55         123 Devel::Declare::set_linestr($linestr);
51 55     55 0 2378 };
52             }
53              
54             sub parser {
55 63     63 0 2778 my ($declarator, $offset) = @_;
56 63         385 my @caller = caller(1);
57              
58             # Skip the declarator
59 63         134 $offset += Devel::Declare::toke_move_past_token($offset);
60 63         104 $offset += Devel::Declare::toke_skipspace($offset);
61 63         83 my $line = Devel::Declare::get_linestr();
62              
63 63         52 my $name;
64 63         58 my $name_offset = $offset;
65 63         45 my $name_len;
66              
67             # Get the block name
68 63         72 my $start = substr($line, $offset, 1);
69 63 100 66     362 if ($start eq '(') {
    100          
    50          
70             # No changes
71 1         9 return;
72             }
73             elsif ($start eq '"' || $start eq "'") {
74             # Quoted name
75 1         4 $name_len = Devel::Declare::toke_scan_str($offset);
76 1         2 $name = Devel::Declare::get_lex_stuff();
77 1         2 Devel::Declare::clear_lex_stuff();
78 1         1 $offset += $name_len;
79             }
80             elsif ($name_len = Devel::Declare::toke_scan_word($offset, 1)) {
81             # Bareword name
82 61         81 $name = substr($line, $offset, $name_len);
83 61         55 $offset += $name_len;
84             }
85              
86 62         72 $offset += Devel::Declare::toke_skipspace($offset);
87 62         73 $line = Devel::Declare::get_linestr();
88              
89 62         57 my $meta = "";
90 62         45 my $meta_offset;
91             my $meta_len;
92              
93 62         53 $start = substr($line, $offset, 1);
94 62 100       97 if ($start eq '(') {
95 14         17 $meta_offset = $offset;
96 14         79 $meta_len = Devel::Declare::toke_scan_str($offset);
97 14         28 $meta = Devel::Declare::get_lex_stuff();
98 14         18 Devel::Declare::clear_lex_stuff();
99 14         23 $line = Devel::Declare::get_linestr();
100              
101 14 50       49 die "Syntax error at $caller[1] line $caller[2]: Test2::Plugin::SpecDeclare does not support multiline parameters.\n"
102             if $meta =~ m/\n/;
103              
104 14         15 $offset += $meta_len;
105 14         16 $offset += Devel::Declare::toke_skipspace($offset);
106 14         27 $line = Devel::Declare::get_linestr();
107 14         15 $start = substr($line, $offset, 1);
108             }
109              
110             # No changes
111 62 100       131 return unless $start eq '{';
112              
113             # Ok! we are good to munge this thing!
114 55         81 substr($line, $offset, 1) = " sub { BEGIN { Test2::Plugin::SpecDeclare::inject() }; ";
115              
116 55 100       77 if ($meta) {
117 14         31 substr($line, $meta_offset + $meta_len - 1, 1) = '}, ';
118 14         17 substr($line, $meta_offset, 1) = ' +{';
119             }
120              
121 55         55 substr($line, $name_offset + $name_len, 0) = ' => __LINE__, ';
122              
123 55         68 Devel::Declare::set_linestr($line);
124 55         294 $line = Devel::Declare::get_linestr();
125             }
126              
127             1;
128              
129             __END__