GLOB vs IO::Handle

B

bill

I want to write a sub that takes either a string which is interpreted
as a filename to be opened and read, or an open read handle. The
question is how to test for the latter? At first I thought I'd
just test

ref $_[0] eq 'GLOB';

but then I realized that $_[0] could be an object of type IO::Handle,
or something like it. And besides, even if $in is a variable of
type GLOB, this does not ensure that <$in> is a valid operation.
After convincing myself that testing for GLOBness was *not* the
thing to do, I thought I could test

UNIVERSAL::can($_[0], 'getline');

but I soon discovered that if $in is defined by

open (my $in, 'foobar') or die "Can't read foobar: $!\n";

then UNIVERSAL::can($my, 'getline') fails.

By this point I get the distinct feeling that I just don't know
enough about this wheel to mess around with reinventing it. What's
the tried-and-true idiom for doing what I want to do?

Thanks!

bill
 
A

A. Sinan Unur

bill said:
I want to write a sub that takes either a string which is interpreted
as a filename to be opened and read, or an open read handle. The
question is how to test for the latter?

I personally would not go down that route, but rather pass two arguments to
the sub. The first would indicate whether a file handle or a filename was
passed:

#! /usr/bin/perl

# Untested pseudo-code below

use strict;
use warnings;

sub myread {
my ($type, $arg) = @_;
if($type eq 'filename') {
# filename passed
} elsif($_[0] eq 'filehandle') {
# filehandle passed
} else {
# programmer error
}
}

myread(filename => 'test.txt');
myread(filehandle => $fh);
myread(filehandle => \*STDIN);


Sinan.
 
X

xhoster

bill said:
I want to write a sub that takes either a string which is interpreted
as a filename to be opened and read, or an open read handle. The
question is how to test for the latter?

You don't. You gave the user two options, a plain old scalar, whose string
value is used as a filename, or a handle. Therefore, if it isn't a plain
old scalar, it must be a handle. Use it like a handle. If they send in
something that is neither one of these things, they should get bitched at.
But just let perl do the bitching, at the point where the whatever-it-is is
used as a handle.

Xho
 
A

Anno Siegel

bill said:
I want to write a sub that takes either a string which is interpreted
as a filename to be opened and read, or an open read handle. The
[...]

By this point I get the distinct feeling that I just don't know
enough about this wheel to mess around with reinventing it. What's
the tried-and-true idiom for doing what I want to do?

if ( defined fileno $x ) {
# it's an open file handle
}

Anno
 
B

Brian McCauley

You don't. You gave the user two options, a plain old scalar, whose string
value is used as a filename, or a handle. Therefore, if it isn't a plain
old scalar, it must be a handle. Use it like a handle. If they send in
something that is neither one of these things, they should get bitched at.
But just let perl do the bitching, at the point where the whatever-it-is is
used as a handle.

It is worth pointing out that a scalar varialble can be one of there
things: a plain old scalar, a reference or a (fake) GLOB.

Now the use of fake GLOBs rather than GLOBrefs is frowned upon by me but
if you want to leave the option open you need check that a scalar
variable is a plain old scalar thus:

ref(\$thing) eq 'SCALAR'

or if you are feeling really pendantic...

!ref($thing) && ref(\$thing) ne 'GLOB'

Of course this does not cope with objects that are can be treated as
strings because they overload "".

Even if you could cope with that what would you do with object that can
be treates as both strings and filehandles?
 
B

bill

In said:
bill said:
I want to write a sub that takes either a string which is interpreted
as a filename to be opened and read, or an open read handle. The
By this point I get the distinct feeling that I just don't know
enough about this wheel to mess around with reinventing it. What's
the tried-and-true idiom for doing what I want to do?
if ( defined fileno $x ) {
# it's an open file handle
}

Way cool... Is there a simpler way to deal with an open non-read
handle than to wrap everything in an eval, redefine $SIG{__WARN__}
to make warnings fatal, analyze $@ afterwards, and die if <$x> was
attempted on an open non-read handle?

bill
Perl Sophomore
 
A

Anno Siegel

bill said:
In <[email protected]>
I want to write a sub that takes either a string which is interpreted
as a filename to be opened and read, or an open read handle. The
By this point I get the distinct feeling that I just don't know
enough about this wheel to mess around with reinventing it. What's
the tried-and-true idiom for doing what I want to do?
if ( defined fileno $x ) {
# it's an open file handle
}

Way cool... Is there a simpler way to deal with an open non-read
handle than to wrap everything in an eval, redefine $SIG{__WARN__}
to make warnings fatal, analyze $@ afterwards, and die if <$x> was
attempted on an open non-read handle?

With sufficiently recent Perl you can make the warning fatal without
%SIG:

eval {
use warnings FATAL => 'io';
my $s = <$x>;
};
my $readable = not $@;

The main problem with this approach is, if the file *is* readable, you
have read (lost) a line from it. You will usually have to thread it back
into the read loop, or use tell/seek to restore the position.

I don't know of a simple method to ask a file handle if it's readable.
Normally, you know what type of handle to expect. If you don't, it's
probably time for a re-design so you do. The contortions of finding
out later are not worth the effort.

Anno
 
S

Sisyphus

Anno said:
if ( defined fileno $x ) {
# it's an open file handle
}

Anno

from 'perldoc -f fileno':
(Filehandles connected to memory objects via new features of
"open" may return undefined even though they are open.)

I don't know if/how that impacts on the OP's requirements - or on Anno's
solution, for that matter.

Cheers,
Rob
 
B

Brian McCauley

Sisyphus said:
from 'perldoc -f fileno':
(Filehandles connected to memory objects via new features of
"open" may return undefined even though they are open.)

I was going to point that out too but experimentation shows that in
practice they return -1. This "feels right" so I suspect it will not
change in future and I suspect perlfunc will catch up sooner or later.

Of course fileno() on a tied handle could return anything or even die.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,816
Latest member
nipsseyhussle

Latest Threads

Top