http://qs1969.pair.com?node_id=146108

gmax has asked for the wisdom of the Perl Monks concerning the following question:

Dear fellow Monks,
I have a parser that is working just fine and uses FileHandle for its input. I need to keep the same functionality, taking input from a string instead of a file.
I thought about writing a separate sub for this purpose, but I realized that a considerable part of my program architecture had to be changed. Therefore I tried another approach, i.e. fooling the application by giving it a handle that behaves like a text file, but has a string underneath.
I couldn't find any ready-to-use solution, and so I came up with my homemade package (see below).
The StringHandle package overloads the angle operator, returning an element of the internal array, which was created by the constructor.
The returned element is removed from the array, thus imitating a sequential file reading.

Also, the code requires that the newline is kept at the end of the returned string, again for compatibility with a file input. On the technical side, the best split pattern that I found was /^/m, which returns a complete string.
A last touch of imitation was the "close" sub, which I would call for a FileHandle object, and should be in my bogus package as well, if I want to avoid an error.
#!/usr/bin/perl -w use strict; #----------------------- package StringHandle; use overload '<>' => sub { return shift @{$_[0]}; }; sub new { my $class = shift; return bless [split /^/m, $_[0]], $class; } sub close { # does nothing. Just to emulate FileHandle }; #----------------------- package main; use FileHandle; my $param = shift; my $text = undef; if ($param) { $text = new FileHandle $param || die "can't open $param\n"; } else { $text = new StringHandle "aaa\nbbb\nccc\nddd\n" || die "can't create new handle\n"; } print while <$text>; # reads from either a file or a string $text->close;
Having this StringHandle package, my script can read from either a file or a string, with the same functionality and no visible problems.
Thus, my requests:
  1. Could you think of any side effect that might affect my parser if I use this emulation?
  2. Is there any module with a ready-to-use solution?
  3. Currently, instead of using eof, I am checking if $_ is defined. How can I increase the robustness of this package to fool the eof function as well?
(Please notice that for this parser I don't need other functions such as seek and tell. Also, the string handle is not publicly interfaced. Therefore I shouldn't worry about emulating FileHandle any further.)

TIA
 _  _ _  _  
(_|| | |(_|><
 _|   

Replies are listed 'Best First'.
Re: FileHandle emulation
by merlyn (Sage) on Feb 18, 2002 at 07:03 UTC
      I just failed to find it. :)
      Thanks for the hint.
       _  _ _  _  
      (_|| | |(_|><
       _|   
      
Re: FileHandle emulation
by Zaxo (Archbishop) on Feb 18, 2002 at 07:07 UTC

    IO::String does something like what you want. It only has partial support for handle operations, for instance exotic $/ variants don't work.

    IO::Stringy is an interesting alternative which looks a bit more modern.

    After Compline,
    Zaxo

Re: FileHandle emulation
by Anonymous Monk on Feb 18, 2002 at 08:27 UTC
    there is also Tie::Scalar .... I'd like to see a benchmark between IO::String(y) and Tie::Scalar ... ;)
Re: FileHandle emulation
by particle (Vicar) on Feb 18, 2002 at 07:02 UTC
    Therefore I shouldn't worry about emulating FileHandle any further

    just a quick thought-- what about list context? might you have code like @array = <$text>; somewhere?

    ~Particle