| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Test::Stream::Plugin::SpecDeclare; | 
| 2 | 5 |  |  | 5 |  | 1071139 | use strict; | 
|  | 5 |  |  |  |  | 13 |  | 
|  | 5 |  |  |  |  | 213 |  | 
| 3 | 5 |  |  | 5 |  | 27 | use warnings; | 
|  | 5 |  |  |  |  | 10 |  | 
|  | 5 |  |  |  |  | 140 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 5 |  |  | 5 |  | 28 | use Test::Stream::Plugin; | 
|  | 5 |  |  |  |  | 10 |  | 
|  | 5 |  |  |  |  | 102 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 5 |  |  | 5 |  | 4582 | use Devel::Declare; | 
|  | 5 |  |  |  |  | 25526 |  | 
|  | 5 |  |  |  |  | 23 |  | 
| 8 | 5 |  |  | 5 |  | 4174 | use B::Hooks::EndOfScope; | 
|  | 5 |  |  |  |  | 60635 |  | 
|  | 5 |  |  |  |  | 39 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 5 |  |  | 5 |  | 3742 | use PadWalker qw/peek_my peek_our/; | 
|  | 5 |  |  |  |  | 3688 |  | 
|  | 5 |  |  |  |  | 378 |  | 
| 11 | 5 |  |  | 5 |  | 45 | use Carp qw/confess croak/; | 
|  | 5 |  |  |  |  | 11 |  | 
|  | 5 |  |  |  |  | 6803 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | # Do not declare any variables here!!!! | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | my %META; | 
| 16 |  |  |  |  |  |  | sub _metahash { | 
| 17 | 36 |  |  | 36 |  | 2226 | my $string = ""; | 
| 18 | 36 |  |  |  |  | 47 | my $vars = { %{peek_our(1)}, %{peek_my(1)} }; | 
|  | 36 |  |  |  |  | 239 |  | 
|  | 36 |  |  |  |  | 157 |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | { | 
| 21 | 36 |  |  |  |  | 81 | my $id = shift; | 
|  | 36 |  |  |  |  | 59 |  | 
| 22 | 36 |  |  |  |  | 276 | my @caller = caller(0); | 
| 23 | 36 |  | 100 |  |  | 291 | my $meta = $META{$id} || return {}; | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 17 |  |  |  |  | 24 | my $var_string = ""; | 
| 26 | 17 |  |  |  |  | 47 | for my $var (keys %$vars) { | 
| 27 | 36 |  |  |  |  | 59 | my $end = "\$vars->{'$var'}"; | 
| 28 | 36 | 50 |  |  |  | 93 | if ($var =~ m/^([\@\%\$])/) { | 
| 29 | 36 |  |  |  |  | 72 | $end = "${1}{$end}"; | 
| 30 |  |  |  |  |  |  | } | 
| 31 |  |  |  |  |  |  | else { | 
| 32 | 0 |  |  |  |  | 0 | next; | 
| 33 |  |  |  |  |  |  | } | 
| 34 | 36 |  |  |  |  | 76 | $var_string .= "my $var = $end;\n"; | 
| 35 |  |  |  |  |  |  | } | 
| 36 |  |  |  |  |  |  |  | 
| 37 | 17 |  |  |  |  | 90 | $string = <<"        EOT"; | 
| 38 |  |  |  |  |  |  | package $caller[0]; | 
| 39 |  |  |  |  |  |  | $var_string | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | # This is cut off access to these variables so they can not be modified in the | 
| 42 |  |  |  |  |  |  | # eval. | 
| 43 |  |  |  |  |  |  | my \$vars; | 
| 44 |  |  |  |  |  |  | my \$string; | 
| 45 |  |  |  |  |  |  | my \%META; | 
| 46 |  |  |  |  |  |  | # line $caller[2] "$caller[1] (SpecDeclare eval)" | 
| 47 |  |  |  |  |  |  | my \$h = {$meta}; | 
| 48 |  |  |  |  |  |  | EOT | 
| 49 |  |  |  |  |  |  | } | 
| 50 |  |  |  |  |  |  |  | 
| 51 | 17 |  |  |  |  | 1989 | my $hash = eval $string; | 
| 52 | 17 | 50 |  |  |  | 304 | die $@ unless $hash; | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 17 |  |  |  |  | 129 | return $hash; | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | # Now we can define some variables. | 
| 58 |  |  |  |  |  |  | my $ID = 1; | 
| 59 |  |  |  |  |  |  | our $DEBUG   = 0; | 
| 60 |  |  |  |  |  |  | our $VERSION = "0.000003"; | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | sub load_ts_plugin { | 
| 63 | 5 |  |  | 5 | 0 | 122 | my $class = shift; | 
| 64 | 5 |  |  |  |  | 10 | my $caller = shift; | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | Devel::Declare->setup_for( | 
| 67 |  |  |  |  |  |  | $caller->[0], | 
| 68 |  |  |  |  |  |  | { | 
| 69 | 5 |  |  |  |  | 28 | map { $_ => { const => \&parser } } grep { $caller->[0]->can($_) } qw{ | 
|  | 70 |  |  |  |  | 238 |  | 
|  | 70 |  |  |  |  | 269 |  | 
| 70 |  |  |  |  |  |  | describe    cases | 
| 71 |  |  |  |  |  |  | tests       it | 
| 72 |  |  |  |  |  |  | case | 
| 73 |  |  |  |  |  |  | before_all  after_all  around_all | 
| 74 |  |  |  |  |  |  | before_case after_case around_case | 
| 75 |  |  |  |  |  |  | before_each after_each around_each | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  | }, | 
| 78 |  |  |  |  |  |  | ); | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | sub _inject_scope { | 
| 82 |  |  |  |  |  |  | on_scope_end { | 
| 83 | 36 |  |  | 36 |  | 1304 | my $line = Devel::Declare::get_linestr(); | 
| 84 | 36 |  |  |  |  | 81 | my $offset = Devel::Declare::get_linestr_offset(); | 
| 85 | 36 |  |  |  |  | 79 | substr($line, $offset, 0) = ', __LINE__;'; | 
| 86 | 36 |  |  |  |  | 88 | Devel::Declare::set_linestr($line); | 
| 87 | 36 | 50 |  |  |  | 133 | print STDERR "FINAL: |$line|\n" if $DEBUG; | 
| 88 |  |  |  |  |  |  | } | 
| 89 | 36 |  |  | 36 |  | 2166 | } | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | sub parser { | 
| 92 | 41 |  |  | 41 | 0 | 3222 | my ($dec, $offset) = @_; | 
| 93 | 41 |  |  |  |  | 50 | my ($name, $meta); | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | # Due to parsing strangeness we need to grab the meta-data and get it back | 
| 96 |  |  |  |  |  |  | # later. This ID is used to fetch the data later. | 
| 97 | 41 |  |  |  |  | 58 | my $id = $ID++; | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | # This is used to back out all changes if a parsing error occurs. | 
| 100 | 41 |  |  |  |  | 49 | my @restore; | 
| 101 |  |  |  |  |  |  | my $restore = sub { | 
| 102 | 5 |  |  | 5 |  | 14 | my $line = Devel::Declare::get_linestr(); | 
| 103 | 5 | 50 |  |  |  | 14 | print "MANGLE: |$line|\n" if $DEBUG; | 
| 104 | 5 |  |  |  |  | 10 | for my $set (reverse @restore) { | 
| 105 | 4 |  |  |  |  | 10 | my ($offset, $len, $val) = @$set; | 
| 106 | 4 |  |  |  |  | 13 | substr($line, $offset, $len) = $val; | 
| 107 |  |  |  |  |  |  | } | 
| 108 | 5 |  |  |  |  | 11 | Devel::Declare::set_linestr($line); | 
| 109 | 5 | 50 |  |  |  | 10 | print "FIXED:  |$line|\n" if $DEBUG; | 
| 110 | 5 |  |  |  |  | 53 | return 0; | 
| 111 | 41 |  |  |  |  | 168 | }; | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | # Skip the initial boring stuff | 
| 114 | 41 |  |  |  |  | 114 | $offset += Devel::Declare::toke_move_past_token($offset); | 
| 115 | 41 |  |  |  |  | 87 | $offset += Devel::Declare::toke_skipspace($offset); | 
| 116 | 41 |  |  |  |  | 105 | my $line = Devel::Declare::get_linestr(); | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | # After the name we use a fat comma, then get the meta hash by id, then add | 
| 119 |  |  |  |  |  |  | # an opening paren, which strangely works around some parser issues, we | 
| 120 |  |  |  |  |  |  | # will close it later | 
| 121 | 41 |  |  |  |  | 80 | my $post_name = " => __LINE__, Test::Stream::Plugin::SpecDeclare::_metahash($id), ("; | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | # Get the block name | 
| 124 | 41 |  |  |  |  | 75 | my $start = substr($line, $offset, 1); | 
| 125 | 41 | 100 | 100 |  |  | 308 | if ($start eq '"' || $start eq "'") { | 
|  |  | 100 |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | # Quoted name | 
| 127 | 11 |  |  |  |  | 61 | my $len = Devel::Declare::toke_scan_str($offset); | 
| 128 | 11 |  |  |  |  | 31 | $name = Devel::Declare::get_lex_stuff(); | 
| 129 | 11 |  |  |  |  | 23 | Devel::Declare::clear_lex_stuff(); | 
| 130 | 11 |  |  |  |  | 12 | $offset += $len; | 
| 131 | 11 |  |  |  |  | 33 | my $new = $post_name; | 
| 132 | 11 |  |  |  |  | 18 | substr($line, $offset, 0) = $new; | 
| 133 | 11 |  |  |  |  | 24 | Devel::Declare::set_linestr($line); | 
| 134 | 11 |  |  |  |  | 30 | push @restore => [$offset, length($new), ""]; | 
| 135 | 11 |  |  |  |  | 21 | $offset += length($new); | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  | elsif (my $nlen = Devel::Declare::toke_scan_word($offset, 1)) { | 
| 138 |  |  |  |  |  |  | # Bareword name | 
| 139 | 29 |  |  |  |  | 51 | $name = substr($line, $offset, $nlen); | 
| 140 | 29 |  |  |  |  | 50 | my $new = qq|"${name}"${post_name}|; | 
| 141 | 29 |  |  |  |  | 55 | substr($line, $offset, $nlen) = $new; | 
| 142 | 29 |  |  |  |  | 59 | Devel::Declare::set_linestr($line); | 
| 143 | 29 |  |  |  |  | 77 | push @restore => [$offset, length($new), $name]; | 
| 144 | 29 |  |  |  |  | 52 | $offset += length($new); | 
| 145 |  |  |  |  |  |  | } | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | # Back out if we failed to get a name | 
| 148 | 41 | 100 |  |  |  | 109 | return $restore->() unless defined $name; | 
| 149 |  |  |  |  |  |  |  | 
| 150 | 40 |  |  |  |  | 86 | $offset += Devel::Declare::toke_skipspace($offset); | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | # See if there is any meta stuff listed. | 
| 153 | 40 |  |  |  |  | 91 | $line = Devel::Declare::get_linestr(); | 
| 154 | 40 |  |  |  |  | 105 | $start = substr($line, $offset, 1); | 
| 155 | 40 | 100 |  |  |  | 96 | if ($start eq '(') { | 
| 156 | 17 |  |  |  |  | 68 | my $len = Devel::Declare::toke_scan_str($offset); | 
| 157 | 17 |  |  |  |  | 44 | $meta = Devel::Declare::get_lex_stuff(); | 
| 158 | 17 |  |  |  |  | 33 | Devel::Declare::clear_lex_stuff(); | 
| 159 | 17 |  |  |  |  | 34 | $line = Devel::Declare::get_linestr(); | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | # Stash the meta stuff to get later, in perls older than 5.20 we can't | 
| 162 |  |  |  |  |  |  | # leave it here as it messes up the parser | 
| 163 | 17 |  |  |  |  | 40 | $META{$id} = $meta; | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | # Replace meta with nothing except the newlines (to preserve line | 
| 166 |  |  |  |  |  |  | # numbers) | 
| 167 |  |  |  |  |  |  | # For some reason putting anything here other than whitespace causes | 
| 168 |  |  |  |  |  |  | # problems. | 
| 169 | 17 |  |  |  |  | 44 | my @newlines = $meta =~ /(\n)/g; | 
| 170 | 17 |  |  |  |  | 30 | my $new = join '' => @newlines; | 
| 171 | 17 |  |  |  |  | 42 | substr($line, $offset, $len) = $new; | 
| 172 | 17 |  |  |  |  | 39 | Devel::Declare::set_linestr($line); | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | # This is how to back it out later | 
| 175 | 17 |  |  |  |  | 52 | push @restore => [$offset, length($new), "($meta)"]; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | # Advance the offset | 
| 178 | 17 |  |  |  |  | 31 | $offset += length($new); | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | # Move to the start of the block | 
| 182 | 40 |  |  |  |  | 78 | $offset += Devel::Declare::toke_skipspace($offset); | 
| 183 | 40 |  |  |  |  | 85 | $line = Devel::Declare::get_linestr(); | 
| 184 | 40 |  |  |  |  | 59 | $start = substr($line, $offset, 1); | 
| 185 | 40 | 100 |  |  |  | 96 | return $restore->() unless $start eq '{'; | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | # Close the paren we opened above, then inject the sub keyword and the | 
| 188 |  |  |  |  |  |  | # inject scope call which gets us the trailing semicolon. | 
| 189 | 36 |  |  |  |  | 40 | my $new = "), sub { BEGIN { Test::Stream::Plugin::SpecDeclare::_inject_scope(); }; "; | 
| 190 | 36 |  |  |  |  | 57 | substr($line, $offset, 1) = $new; | 
| 191 | 36 |  |  |  |  | 72 | Devel::Declare::set_linestr($line); | 
| 192 | 36 |  |  |  |  | 45 | $offset += length($new); | 
| 193 | 36 | 50 |  |  |  | 464 | print STDERR "PREFIN: |$line|\n" if $DEBUG; | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | 1; | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | __END__ |