File Coverage

blib/lib/Tie/FileSection.pm
Criterion Covered Total %
statement 89 95 93.6
branch 44 50 88.0
condition 36 42 85.7
subroutine 8 10 80.0
pod 1 1 100.0
total 178 198 89.9


line stmt bran cond sub pod time code
1 3     3   1555 use strict;
  3         8  
  3         2552  
2             package Tie::FileSection;
3             $Tie::FileSection::VERSION = '0.171861';
4             # ABSTRACT: restrict files sequential access using array like boundaries
5             require Tie::Handle;
6             our @ISA = qw( Tie::StdHandle );
7              
8             sub new{
9 28 50   28 1 11088 my $pkg = $_[0] eq __PACKAGE__ ? shift : __PACKAGE__ ;
10 28         169 my %opts = @_;
11 28 50 66     176 $opts{filename} || $opts{file} or die "filename|file parameter is mandatory!";
12 28   100     147 my $first_line = $opts{first_line} // 0;
13 28   100     120 my $last_line = $opts{last_line} // 0;
14 28         73 my $use_real_line_nr = $opts{use_real_line_nr};
15 28         66 my $FH = $opts{file};
16 28 100 66     153 if(!$FH && defined $opts{filename}){
17 12 50       570 open $FH, '<', $opts{filename} or die "** could not open file $opts{filename} : $!\n";
18             }
19 28         216 tie *F, $pkg, $FH, $first_line, $last_line, $use_real_line_nr;
20 28         144 return \*F;
21             }
22              
23             sub TIEHANDLE{
24 28     28   113 my ($pkg, $FH, $first_line, $last_line, $use_real_line_nr) = @_;
25 28         275 my $self = bless {
26             handle => $FH,
27             first_line => $first_line,
28             last_line => $last_line,
29             init => 0, #lazy read
30             curr_line => 0,
31             use_real_line_nr => $use_real_line_nr,
32             line_buffer => [],
33             tell_buffer => [],
34             }, $pkg;
35 28         244 return $self;
36             }
37              
38             sub UNTIE{
39 0     0   0 my $fh = $_[0]->{handle};
40 0         0 undef $_[0];
41 0         0 close( $fh );
42             }
43              
44             sub EOF{
45 111     111   9784 my $self = shift;
46 111         315 my $f = $self->{first_line};
47 111         234 my $l = $self->{last_line};
48 111 50 100     640 if($f>=0 && $l>0 && $f > $l){ #static EOF
      66        
49 0         0 return 1;
50             }
51 111 50 100     554 if($f<0 && $l<0 && $l < $f ){ #static EOF
      66        
52 0         0 return 1;
53             }
54            
55 111 100 100     460 if($f<0 && $l>0){
56 16         124 return abs($f) + $self->{curr_line} >= $l;
57             }
58            
59 95 100 100     563 if($self->{init} && 0 <= $l && $l >= $self->{curr_line}){
      100        
60 6         39 return 1;
61             }
62            
63 89 100       536 if(eof( $self->{handle} )){
64             #take in account buffer here
65 33 100 100     133 if($l < 0 && scalar(@{$self->{line_buffer}})
  20         110  
66 12         90 return 1;
67             }
68             else{
69             #buffer not empty
70 21 100       52 return if @{$self->{line_buffer}};
  21         102  
71             }
72            
73 12         85 return 1;
74             }
75 56         207 return;
76             }
77              
78             sub TELL {
79 30     30   8743 my $self = shift;
80 30         95 $. = $self->{curr_line};
81 30 100       194 return tell($self->{handle}) unless $self->{use_buffer};
82 16         69 return $self->{tell_buffer}[0];
83             }
84              
85             sub _readline{
86 63     63   150 my $self = shift;
87 63         146 my $fh = $self->{handle};
88 63         137 my $l = $self->{last_line};
89 63         135 my $tellbuff = $self->{tell_buffer};
90 63         133 my $linebuff = $self->{line_buffer};
91 63 100       205 unless($self->{init}++){
92 28         73 my $f = $self->{first_line};
93 28 100       136 if($f > 0){
    100          
94 10         25 my $i = $f;
95 10   66     102 while(--$i && defined scalar <$fh>){
96             }
97             }
98             elsif($f < 0){
99             #need to read until eof for abs($f) records
100 14         69 for(1..abs $f){
101 31         110 push @$tellbuff, tell($fh);
102 31         205 push @$linebuff, scalar <$fh>;
103             }
104 14         55 $self->{use_buffer}++;
105 14         65 while(!eof $fh){
106 41         109 shift @$tellbuff;
107 41         92 shift @$linebuff;
108 41         114 push @$tellbuff, tell($fh);
109 41         239 push @$linebuff, scalar <$fh>;
110             }
111             }
112 28 100 100     176 if($f > 0 && $l < 0){
113 4         20 for(1..abs $l){
114 8         30 push @$tellbuff, tell($fh);
115 8         38 push @$linebuff, scalar <$fh>;
116             }
117 4         14 $self->{use_buffer}++;
118             }
119 28 100       111 if(eof($fh)){
120             #add the final pos if requested aftere EOF.
121 14         44 push @$tellbuff, tell($fh);
122             }
123 28 100       98 if($self->{use_real_line_nr}){
124 3 100       13 $. -= @$linebuff if $self->{use_buffer};
125 3         10 $self->{curr_line} = $.;
126             }
127             else {
128 25         96 $. = undef;
129             }
130             }
131             #read one line and return it, take in accound first_line/last_line and buffer
132 63         185 my $eof = eof($fh);
133 63         151 my $pos = tell($fh);
134 63 100       270 my $line = $eof ? undef : <$fh>;
135 63 100       212 if($self->{use_buffer}){
136 35 100 50     201 unless($eof){
137 8         28 push @$linebuff, $line;
138 8         21 push @$tellbuff, $pos;
139             }
140             elsif($l < 0 && scalar(@$linebuff)
141             return;
142             }
143 35         105 $line = shift @$linebuff;
144 35 50       140 shift @$tellbuff unless @$tellbuff == 1; #always keep last pos
145             }
146 63         162 $self->{curr_line}++;
147 63         181 $. = $self->{curr_line};
148 63         352 return $line;
149             }
150              
151             sub READLINE {
152 99     99   23028 my $self = shift;
153 99 100       286 return if $self->EOF; #test basics boundaries
154 75 100       260 unless(wantarray){
155 63         209 return $self->_readline;
156             }
157             #ARRAY
158 12         28 my @rows;
159 12         58 while(defined($_=$self->READLINE)){
160 28         119 push @rows, $_;
161             }
162 12         86 @rows;
163             }
164              
165 12     12   215 sub CLOSE { close($_[0]->{handle}) }
166 0     0     sub FILENO { fileno($_[0]->{handle}) }
167             1;
168              
169             __END__