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   232708 use warnings;
  3         9  
  3         87  
4 3     3   13 use strict;
  3         6  
  3         48  
5 3     3   10 use Carp;
  3         4  
  3         3745  
6              
7             # For AUTHOR, COPYRIGHT, AND LICENSE see Argv.pod
8              
9             our $VERSION = '0.18';
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   87266 my $class = shift;
18 41 100       264 croak $class."::tie/new: bad number of arguments" if @_%2;
19 40         108 my %args = @_;
20 40         104 for (keys %args) { croak "$class->tie/new: unknown argument '$_'"
21 44 100       215 unless $TIEHANDLE_KNOWN_ARGS{$_} }
22             croak "$class->tie/new: filename must be a scalar ref"
23 39 100 100     227 if defined($args{filename}) && ref $args{filename} ne 'SCALAR';
24             croak "$class->tie/new: files must be an arrayref"
25 38 100 100     240 if defined($args{files}) && ref $args{files} ne 'ARRAY';
26 37         160 my $self = $class->SUPER::TIEHANDLE();
27 37         581 $self->{__lineno} = undef; # also keeps state: undef = not currently active, defined = active
28 37 100       153 $self->{__debug} = ref($args{debug}) ? $args{debug} : ( $args{debug} ? *STDERR{IO} : undef);
    100          
29 37         78 $self->{__s_argv} = $args{filename};
30 37         95 $self->{__a_argv} = $args{files};
31 37         102 return $self;
32             }
33              
34             sub _debug { ## no critic (RequireArgUnpacking)
35 550     550   660 my $self = shift;
36 550 100       1292 return 1 unless $self->{__debug};
37 7 100       202 confess "not enough arguments to _debug" unless @_;
38 6         18 local ($",$,,$\) = (' ');
39 6         8 return print {$self->{__debug}} ref($self), " DEBUG: ", @_ ,"\n";
  6         111  
40             }
41              
42             sub inner_close {
43 40     40 1 98 return shift->SUPER::CLOSE(@_);
44             }
45             sub _close {
46 90     90   129 my $self = shift;
47 90 100       260 confess "bad number of arguments to _close" unless @_==1;
48 89         112 my $keep_lineno = shift;
49 89         201 my $rv = $self->inner_close;
50 89 100       718 if ($keep_lineno)
51 81         168 { $. = $self->{__lineno} } ## no critic (RequireLocalizedPunctuationVars)
52             else
53 8         21 { $. = $self->{__lineno} = 0 } ## no critic (RequireLocalizedPunctuationVars)
54 89         136 return $rv; # see tests in 20_tie_handle_base.t: we know close always returns a scalar
55             }
56 8     8   3005 sub CLOSE { return shift->_close(0) }
57              
58             sub init_empty_argv {
59 3     3 1 3718 my $self = shift;
60 3         8 $self->_debug("adding '-' to file list");
61 3 100       6 unshift @{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV }, '-';
  3         13  
62 3         5 return;
63             }
64             sub advance_argv {
65 82     82 1 115 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       222 return ${ defined $self->{__s_argv} ? $self->{__s_argv} : \$ARGV }
70 82 100       92 = shift @{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV };
  82         163  
71             }
72       16 1   sub sequence_end {}
73             sub _advance {
74 116     116   748 my $self = shift;
75 116         156 my $peek = shift;
76 116 100       303 confess "too many arguments to _advance" if @_;
77 115 100 100     240 if ( !defined($self->{__lineno}) && !@{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV } ) {
  38 100       166  
78 2         8 $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         14 $self->init_empty_argv;
82             }
83             FILE: {
84 115 100       146 $self->_close(1) if defined $self->{__lineno};
  119         337  
85 119 100       140 if ( !@{ defined $self->{__a_argv} ? $self->{__a_argv} : \@ARGV } ) {
  119 100       346  
86 37         157 $self->_debug("file list is now empty, closing and done (\$.=$.)");
87 37 100       90 $self->{__lineno} = undef unless $peek;
88 37         91 $self->sequence_end;
89 37         109 return;
90             } # else
91 82         167 my $fn = $self->advance_argv;
92 82         262 $self->_debug("opening '$fn'");
93             # note: ->SUPER::OPEN uses ->CLOSE, but we don't want that, so we ->_close above
94 82 100       220 if ( $self->OPEN($fn) ) {
95 77 100       1456 defined $self->{__lineno} or $self->{__lineno} = 0;
96             }
97             else {
98 4         115 $self->_debug("open '$fn' failed: $!");
99 4         869 warnings::warnif("inplace", "Can't open $fn: $!");
100 4         218 redo FILE;
101             }
102             }
103 77         259 return 1;
104             }
105              
106             sub read_one_line {
107 124     124 1 300 return scalar shift->SUPER::READLINE(@_);
108             }
109             sub READLINE {
110 146     146   90355 my $self = shift;
111 146 100       466 $self->_debug("readline in ", wantarray?"list":"scalar", " context");
112 146         188 my @out;
113 146         179 RL_LINE: while (1) {
114 160         288 while ($self->EOF(1)) {
115 107         905 $self->_debug("current file is at EOF, advancing");
116 107 100       232 $self->_advance or last RL_LINE;
117             }
118 124         1395 my $line = $self->read_one_line;
119 124 100       1021 last unless defined $line;
120 123         215 push @out, $line;
121 123         251 $. = ++$self->{__lineno}; ## no critic (RequireLocalizedPunctuationVars)
122 123 100       290 last unless wantarray;
123             }
124 145         543 $self->_debug("readline: ",0+@out," lines (\$.=$.)");
125 145 100       590 return wantarray ? @out : $out[0];
126             }
127              
128             sub inner_eof {
129 252     252 1 606 return shift->SUPER::EOF(@_);
130             }
131             sub EOF { ## no critic (RequireArgUnpacking)
132 246     246   9883 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     877 if (@_ && $_[0]==2) {
139 14         37 while ( $self->inner_eof(1) ) {
140 8         49 $self->_debug("eof(): current file is at EOF, peeking");
141 8 100       18 if ( not $self->_advance("peek") ) {
142 2         8 $self->_debug("eof(): could not peek => EOF");
143 2         11 return !!1;
144             }
145             }
146 12         145 $self->_debug("eof(): => Not at EOF");
147 12         45 return !!0;
148             }
149 232         465 return $self->inner_eof(@_);
150             }
151              
152 1     1   860 sub WRITE { croak ref(shift)." is read-only" }
153              
154             sub UNTIE {
155 36     36   46004 my $self = shift;
156 36         127 delete @$self{ grep {/^__(?!innerhandle)/} keys %$self };
  180         430  
157 36         142 return $self->SUPER::UNTIE(@_);
158             }
159              
160             sub DESTROY {
161 37     37   162 my $self = shift;
162 37         74 delete @$self{ grep {/^__(?!innerhandle)/} keys %$self };
  5         11  
163 37         99 return $self->SUPER::DESTROY(@_);
164             }
165              
166             1;