File Coverage

blib/lib/Devel/InPackage.pm
Criterion Covered Total %
statement 54 55 98.1
branch 5 6 83.3
condition 3 15 20.0
subroutine 11 11 100.0
pod 0 2 0.0
total 73 89 82.0


line stmt bran cond sub pod time code
1             package Devel::InPackage;
2             BEGIN {
3 1     1   580 $Devel::InPackage::VERSION = '0.01';
4             }
5             # ABSTRACT: scan a file for package declarations or determine which package a line belongs to
6 1     1   6 use strict;
  1         1  
  1         26  
7 1     1   4 use warnings;
  1         2  
  1         30  
8 1     1   26 use 5.010;
  1         3  
  1         42  
9              
10 1     1   6 use Carp qw(confess);
  1         1  
  1         60  
11 1     1   1075 use File::Slurp qw(read_file);
  1         30135  
  1         91  
12 1         11 use Sub::Exporter -setup => {
13             exports => ['in_package', 'scan'],
14 1     1   3221 };
  1         18231  
15              
16             our $VERSION;
17              
18             my $MODULE = qr/(?[A-Za-z0-9:]+)/;
19              
20             sub in_package {
21 23     23 0 14468 my %args = @_;
22             # XXX: hope you don't want to know what package foo is in here:
23             # package main;
24             # { package Bar; }
25 23   33     79 my $point = delete $args{line} || confess 'need line';
26              
27 23         39 my $result = 'main';
28             my $cb = sub {
29 52     52   155 my ($line, $package, %info) = @_;
30 52         85 my $line_number = $info{line_number};
31 52 100       118 if( $line_number >= $point ){
32 23         35 $result = $package;
33 23         60 return 0;
34             }
35 29         71 return 1;
36 23         116 };
37              
38 23         79 scan( %args, callback => $cb);
39              
40 23         179 return $result;
41             }
42              
43             sub scan {
44 23     23 0 58 my %args = @_;
45              
46 23   0     81 my $program = $args{code} //
      33        
      0        
47             ($args{file} && read_file($args{file})) //
48             confess 'Need "file" or "code"';
49              
50 23   33     54 my $callback = $args{callback} // confess 'Need "callback"';
51              
52             # this is very crude, and makes incorrect assumptions about Perl
53             # syntax
54 23         39 my @state = ('main');
55 23         31 my $line_no = 0;
56 23         214 while( $program =~ /^(?.+)$/mg ){
57 1     1   1749 my $line = $+{line};
  1         587  
  1         594  
  52         317  
58 52         115 my $saved_line = $line;
59              
60             # skip comments
61 52         90 $line =~ s/#(.+)$//;
62              
63 52         544 while( $line =~ /(?(?:
64             { |
65             } |
66             \bpackage \s+ $MODULE \s* ; |
67             \b(?:class|role) \s+ $MODULE (.+)? { ))
68             /xg ){
69 33         175 given($+{token}){
70 33         78 when('{'){
71 5         43 push @state, $state[-1];
72             }
73 28         38 when('}'){
74 4 50       15 confess "Unmatched closing } at $line_no" unless @state > 0;
75 4         35 pop @state;
76             }
77 24         205 when(/(package|class|role) ($MODULE)/){
78 24         312 push @state, $+{package};
79             }
80             }
81             }
82              
83 52         126 my $continue_scanning = $callback->( $line, $state[-1], line_number => ++$line_no );
84 52 100       284 return if !$continue_scanning; # end early
85             }
86              
87 0           return;
88             }
89              
90             1;
91              
92             __END__