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 3     3   279679 use warnings;
  3         10  
  3         103  
4 3     3   16 use strict;
  3         5  
  3         59  
5 3     3   16 use Carp;
  3         6  
  3         4563  
6              
7             # For AUTHOR, COPYRIGHT, AND LICENSE see the bottom of this file
8              
9             our $VERSION = '0.16';
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   101270 my $class = shift;
18 41 100       281 croak $class."::tie/new: bad number of arguments" if @_%2;
19 40         109 my %args = @_;
20 40         121 for (keys %args) { croak "$class->tie/new: unknown argument '$_'"
21 44 100       240 unless $TIEHANDLE_KNOWN_ARGS{$_} }
22             croak "$class->tie/new: filename must be a scalar ref"
23 39 100 100     252 if defined($args{filename}) && ref $args{filename} ne 'SCALAR';
24             croak "$class->tie/new: files must be an arrayref"
25 38 100 100     217 if defined($args{files}) && ref $args{files} ne 'ARRAY';
26 37         177 my $self = $class->SUPER::TIEHANDLE();
27 37         642 $self->{__lineno} = undef; # also keeps state: undef = not currently active, defined = active
28 37 100       142 $self->{__debug} = ref($args{debug}) ? $args{debug} : ( $args{debug} ? *STDERR{IO} : undef);
    100          
29 37         76 $self->{__s_argv} = $args{filename};
30 37         59 $self->{__a_argv} = $args{files};
31 37         123 return $self;
32             }
33              
34             sub _debug { ## no critic (RequireArgUnpacking)
35 550     550   825 my $self = shift;
36 550 100       1285 return 1 unless $self->{__debug};
37 7 100       240 confess "not enough arguments to _debug" unless @_;
38 6         21 local ($",$,,$\) = (' ');
39 6         8 return print {$self->{__debug}} ref($self), " DEBUG: ", @_ ,"\n";
  6         110  
40             }
41              
42             sub inner_close {
43 40     40 1 100 return shift->SUPER::CLOSE(@_);
44             }
45             sub _close {
46 90     90   156 my $self = shift;
47 90 100       307 confess "bad number of arguments to _close" unless @_==1;
48 89         128 my $keep_lineno = shift;
49 89         221 my $rv = $self->inner_close;
50 89 100       681 if ($keep_lineno)
51 81         209 { $. = $self->{__lineno} } ## no critic (RequireLocalizedPunctuationVars)
52             else
53 8         24 { $. = $self->{__lineno} = 0 } ## no critic (RequireLocalizedPunctuationVars)
54 89         147 return $rv; # see tests in 20_tie_handle_base.t: we know close always returns a scalar
55             }
56 8     8   3353 sub CLOSE { return shift->_close(0) }
57              
58             sub init_empty_argv {
59 3     3 1 4572 my $self = shift;
60 3         12 $self->_debug("adding '-' to file list");
61 3 100       7 unshift @{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV }, '-';
  3         16  
62 3         8 return;
63             }
64             sub advance_argv {
65 82     82 1 124 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       255 return ${ defined $self->{__s_argv} ? $self->{__s_argv} : \$ARGV }
70 82 100       118 = shift @{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV };
  82         204  
71             }
72       16 1   sub sequence_end {}
73             sub _advance {
74 116     116   912 my $self = shift;
75 116         175 my $peek = shift;
76 116 100       361 confess "too many arguments to _advance" if @_;
77 115 100 100     349 if ( !defined($self->{__lineno}) && !@{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV } ) {
  38 100       166  
78 2         9 $self->_debug("file list is initially empty (\$.=0)");
79             # the normal <> also appears to reset $. to 0 in this case:
80 2         5 $. = 0; ## no critic (RequireLocalizedPunctuationVars)
81 2         14 $self->init_empty_argv;
82             }
83             FILE: {
84 115 100       186 $self->_close(1) if defined $self->{__lineno};
  119         362  
85 119 100       180 if ( !@{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV } ) {
  119 100       396  
86 37         180 $self->_debug("file list is now empty, closing and done (\$.=$.)");
87 37 100       95 $self->{__lineno} = undef unless $peek;
88 37         116 $self->sequence_end;
89 37         122 return;
90             } # else
91 82         187 my $fn = $self->advance_argv;
92 82         286 $self->_debug("opening '$fn'");
93             # note: ->SUPER::OPEN uses ->CLOSE, but we don't want that, so we ->_close above
94 82 100       254 if ( $self->OPEN($fn) ) {
95 77 100       1676 defined $self->{__lineno} or $self->{__lineno} = 0;
96             }
97             else {
98 4         128 $self->_debug("open '$fn' failed: $!");
99 4         728 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 354 return scalar shift->SUPER::READLINE(@_);
108             }
109             sub READLINE {
110 146     146   107493 my $self = shift;
111 146 100       541 $self->_debug("readline in ", wantarray?"list":"scalar", " context");
112 146         213 my @out;
113 146         225 RL_LINE: while (1) {
114 160         357 while ($self->EOF(1)) {
115 107         1021 $self->_debug("current file is at EOF, advancing");
116 107 100       262 $self->_advance or last RL_LINE;
117             }
118 124         1738 my $line = $self->read_one_line;
119 124 100       1116 last unless defined $line;
120 123         244 push @out, $line;
121 123         279 $. = ++$self->{__lineno}; ## no critic (RequireLocalizedPunctuationVars)
122 123 100       279 last unless wantarray;
123             }
124 145         643 $self->_debug("readline: ",0+@out," lines (\$.=$.)");
125 145 100       713 return wantarray ? @out : $out[0];
126             }
127              
128             sub inner_eof {
129 252     252 1 673 return shift->SUPER::EOF(@_);
130             }
131             sub EOF { ## no critic (RequireArgUnpacking)
132 246     246   11636 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     1012 if (@_ && $_[0]==2) {
139 14         44 while ( $self->inner_eof(1) ) {
140 8         57 $self->_debug("eof(): current file is at EOF, peeking");
141 8 100       25 if ( not $self->_advance("peek") ) {
142 2         9 $self->_debug("eof(): could not peek => EOF");
143 2         11 return !!1;
144             }
145             }
146 12         179 $self->_debug("eof(): => Not at EOF");
147 12         50 return !!0;
148             }
149 232         495 return $self->inner_eof(@_);
150             }
151              
152 1     1   1640 sub WRITE { croak ref(shift)." is read-only" }
153              
154             sub UNTIE {
155 36     36   53893 my $self = shift;
156 36         124 delete @$self{ grep {/^__(?!innerhandle)/} keys %$self };
  180         531  
157 36         153 return $self->SUPER::UNTIE(@_);
158             }
159              
160             sub DESTROY {
161 37     37   177 my $self = shift;
162 37         93 delete @$self{ grep {/^__(?!innerhandle)/} keys %$self };
  5         13  
163 37         112 return $self->SUPER::DESTROY(@_);
164             }
165              
166             1;