File Coverage

blib/lib/Tie/Handle/Argv.pm
Criterion Covered Total %
statement 106 106 100.0
branch 58 58 100.0
condition 12 12 100.0
subroutine 19 19 100.0
pod 6 6 100.0
total 201 201 100.0


line stmt bran cond sub pod time code
1             #!perl
2             package Tie::Handle::Argv;
3 9     9   89477 use warnings;
  9         18  
  9         316  
4 9     9   45 use strict;
  9         19  
  9         182  
5 9     9   42 use Carp;
  9         19  
  9         12892  
6              
7             # For AUTHOR, COPYRIGHT, AND LICENSE see the bottom of this file
8              
9             our $VERSION = '0.14';
10              
11             require Tie::Handle::Base;
12             our @ISA = qw/ Tie::Handle::Base /; ## no critic (ProhibitExplicitISA)
13              
14             my %TIEHANDLE_KNOWN_ARGS = map {($_=>1)} qw/ files filename debug /;
15              
16             sub TIEHANDLE { ## no critic (RequireArgUnpacking)
17 41     41   104210 my $class = shift;
18 41 100       313 croak $class."::tie/new: bad number of arguments" if @_%2;
19 40         130 my %args = @_;
20 40         141 for (keys %args) { croak "$class->tie/new: unknown argument '$_'"
21 44 100       245 unless $TIEHANDLE_KNOWN_ARGS{$_} }
22             croak "$class->tie/new: filename must be a scalar ref"
23 39 100 100     243 if defined($args{filename}) && ref $args{filename} ne 'SCALAR';
24             croak "$class->tie/new: files must be an arrayref"
25 38 100 100     244 if defined($args{files}) && ref $args{files} ne 'ARRAY';
26 37         166 my $self = $class->SUPER::TIEHANDLE();
27 37         95 $self->{__lineno} = undef; # also keeps state: undef = not currently active, defined = active
28 37 100       136 $self->{__debug} = ref($args{debug}) ? $args{debug} : ( $args{debug} ? *STDERR{IO} : undef);
    100          
29 37         75 $self->{__s_argv} = $args{filename};
30 37         58 $self->{__a_argv} = $args{files};
31 37         121 return $self;
32             }
33              
34             sub _debug { ## no critic (RequireArgUnpacking)
35 550     550   783 my $self = shift;
36 550 100       1204 return 1 unless $self->{__debug};
37 7 100       281 confess "not enough arguments to _debug" unless @_;
38 6         29 local ($",$,,$\) = (' ');
39 6         13 return print {$self->{__debug}} ref($self), " DEBUG: ", @_ ,"\n";
  6         160  
40             }
41              
42             sub inner_close {
43 40     40 1 123 return shift->SUPER::CLOSE(@_);
44             }
45             sub _close {
46 90     90   144 my $self = shift;
47 90 100       297 confess "bad number of arguments to _close" unless @_==1;
48 89         137 my $keep_lineno = shift;
49 89         219 my $rv = $self->inner_close;
50 89 100       210 if ($keep_lineno)
51 81         187 { $. = $self->{__lineno} } ## no critic (RequireLocalizedPunctuationVars)
52             else
53 8         26 { $. = $self->{__lineno} = 0 } ## no critic (RequireLocalizedPunctuationVars)
54 89         154 return $rv; # see tests in 20_tie_handle_base.t: we know close always returns a scalar
55             }
56 8     8   70 sub CLOSE { return shift->_close(0) }
57              
58             sub init_empty_argv {
59 3     3 1 9239 my $self = shift;
60 3         12 $self->_debug("adding '-' to file list");
61 3 100       8 unshift @{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV }, '-';
  3         18  
62 3         8 return;
63             }
64             sub advance_argv {
65 82     82 1 126 my $self = shift;
66             # Note: we do these gymnastics with the references because we always want
67             # to access the currently global $ARGV and @ARGV - if we just stored references
68             # to these in our object, we wouldn't notices changes due to "local"ization!
69 82 100       235 return ${ defined $self->{__s_argv} ? $self->{__s_argv} : \$ARGV }
70 82 100       116 = shift @{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV };
  82         186  
71             }
72       16 1   sub sequence_end {}
73             sub _advance {
74 116     116   886 my $self = shift;
75 116         187 my $peek = shift;
76 116 100       340 confess "too many arguments to _advance" if @_;
77 115 100 100     273 if ( !defined($self->{__lineno}) && !@{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV } ) {
  38 100       203  
78 2         7 $self->_debug("file list is initially empty (\$.=0)");
79             # the normal <> also appears to reset $. to 0 in this case:
80 2         4 $. = 0; ## no critic (RequireLocalizedPunctuationVars)
81 2         12 $self->init_empty_argv;
82             }
83             FILE: {
84 115 100       167 $self->_close(1) if defined $self->{__lineno};
  119         385  
85 119 100       175 if ( !@{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV } ) {
  119 100       374  
86 37         185 $self->_debug("file list is now empty, closing and done (\$.=$.)");
87 37 100       97 $self->{__lineno} = undef unless $peek;
88 37         113 $self->sequence_end;
89 37         123 return;
90             } # else
91 82         193 my $fn = $self->advance_argv;
92 82         338 $self->_debug("opening '$fn'");
93             # note: ->SUPER::OPEN uses ->CLOSE, but we don't want that, so we ->_close above
94 82 100       233 if ( $self->OPEN($fn) ) {
95 77 100       276 defined $self->{__lineno} or $self->{__lineno} = 0;
96             }
97             else {
98 4         46 $self->_debug("open '$fn' failed: $!");
99 4         820 warnings::warnif("inplace", "Can't open $fn: $!");
100 4         254 redo FILE;
101             }
102             }
103 77         286 return 1;
104             }
105              
106             sub read_one_line {
107 124     124 1 334 return scalar shift->SUPER::READLINE(@_);
108             }
109             sub READLINE {
110 146     146   3864 my $self = shift;
111 146 100       559 $self->_debug("readline in ", wantarray?"list":"scalar", " context");
112 146         241 my @out;
113 146         208 RL_LINE: while (1) {
114 160         370 while ($self->EOF(1)) {
115 107         363 $self->_debug("current file is at EOF, advancing");
116 107 100       239 $self->_advance or last RL_LINE;
117             }
118 124         389 my $line = $self->read_one_line;
119 124 100       328 last unless defined $line;
120 123         236 push @out, $line;
121 123         280 $. = ++$self->{__lineno}; ## no critic (RequireLocalizedPunctuationVars)
122 123 100       277 last unless wantarray;
123             }
124 145         672 $self->_debug("readline: ",0+@out," lines (\$.=$.)");
125 145 100       711 return wantarray ? @out : $out[0];
126             }
127              
128             sub inner_eof {
129 252     252 1 646 return shift->SUPER::EOF(@_);
130             }
131             sub EOF { ## no critic (RequireArgUnpacking)
132 246     246   1089 my $self = shift;
133             # "Starting with Perl 5.12, an additional integer parameter will be passed.
134             # It will be zero if eof is called without parameter;
135             # 1 if eof is given a filehandle as a parameter, e.g. eof(FH);
136             # and 2 in the very special case that the tied filehandle is ARGV
137             # and eof is called with an empty parameter list, e.g. eof()."
138 246 100 100     982 if (@_ && $_[0]==2) {
139 14         33 while ( $self->inner_eof(1) ) {
140 8         33 $self->_debug("eof(): current file is at EOF, peeking");
141 8 100       24 if ( not $self->_advance("peek") ) {
142 2         8 $self->_debug("eof(): could not peek => EOF");
143 2         11 return !!1;
144             }
145             }
146 12         45 $self->_debug("eof(): => Not at EOF");
147 12         52 return !!0;
148             }
149 232         559 return $self->inner_eof(@_);
150             }
151              
152 1     1   96 sub WRITE { croak ref(shift)." is read-only" }
153              
154             sub UNTIE {
155 36     36   56134 my $self = shift;
156 36         116 delete @$self{ grep {/^__(?!innerhandle)/} keys %$self };
  180         524  
157 36         147 return $self->SUPER::UNTIE(@_);
158             }
159              
160             sub DESTROY {
161 37     37   67 my $self = shift;
162 37         81 delete @$self{ grep {/^__(?!innerhandle)/} keys %$self };
  5         20  
163 37         100 return $self->SUPER::DESTROY(@_);
164             }
165              
166             1;
167             __END__