Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re^3: Un "tie"ing a "tie"

by dpuu (Chaplain)
on Apr 17, 2006 at 22:39 UTC ( #543942=note: print w/ replies, xml ) Need Help??


in reply to Re^2: Un "tie"ing a "tie"
in thread Un "tie"ing a "tie"

Instead of just doing timestamps, perhaps a generic "send output lines to this sub" routine is more useful:

=head1 NAME FileHandle::Sub - an output filehandle that sends each line of output +to a user-specified CODE block =head1 SYNOPSIS use FileHandle::Sub; # grep my $fh = FileHandle::Sub::open { /token/ and print }; # prefix my $fh = FileHandle::Sub::open { s/^/scalar localtime/e; print }; =head1 DESCRIPTION Each line of output sent to this file handle will be passed to the COD +E block supplied to C<open>. =cut package FileHandle::Sub; { require 5.8.0; use strict; use warnings; sub open (&) { local *FH; tie *FH, __PACKAGE__, @_ or return; return *FH; } sub TIEHANDLE { my($class, $code) = @_; bless [$code, ""], $class; } sub _emit { my ($self, $txt) = @_; my ($code, $prev) = @$self; if ($txt =~ /\n$/) { local $_ = $prev . $txt; $code->($_); $prev = ""; } else { $prev .= $txt; } $self->[1] = $prev; } sub PRINT { my ($self, @txt) = @_; local $_; for my $txt (@txt) { _emit($self, $_) for $txt =~ /[^\n]*\n?/g; } } sub PRINTF { my ($self, $fmt, @args) = @_; PRINT $self, sprintf $fmt, @args; } sub CLOSE { my ($self) = @_; local $_ = $self->[1]; if (length) { $self->[0]->($_); } $self->[1] = ""; } sub DESTROY { &CLOSE } } 1;
--Dave
Opinions my own; statements of fact may be in error.


Comment on Re^3: Un "tie"ing a "tie"
Download Code
Re^4: Un "tie"ing a "tie"
by ikegami (Pope) on Apr 17, 2006 at 22:55 UTC

    Good idea. My code was just an example. There are problems with the implementation, though.

    • For starters, you cannot easily replace an existing file handle, so you failed to address the original question.

    • No support for $,.

    • No support for $\.

    • No error code is returned. People won't be able to use this module when error checking is being done.

    • No support for write, binmode, etc. People won't be able to use this module when these are called with the filehandle.

    • Only your open function requires 5.8.0, and it could easily be rewritten to avoid that requirement.

    • Using $/ as the line terminator would be better than \n because it would give more flexibility to the caller at no cost.

    • _emit for //g would be more efficient as _emit while //g.

      Obviously I agree that the implementation is incomplete; and yes, it is orthogonal to the OP's question. A user of a module like this would be responsible for managing their own filehandles -- as earlier answers said: store a dup of STDOUT.

      Support for all the special variables needs a little thought, because they are dynamically scoped. I'd probably want to capture their values in the "open" function and store those values in the object. But, OTOH, maybe someone changing the values dynamically knows what they're doing.

      I'm not sure that binmode is required for this filehandle. All it does is call a user-defined perl function for each line (implicitly text). If that code prints to a "real" filehandle, then it is that filehandle that needs to support binmode.

      I'd be interested to know how to rewrite the "open" function to avoid needing 5.8.x -- the requirement exists because of bugs in 5.6.x, so the simplest (and safest) thing it to require a version of perl that works reliably with tied filehandles.

      The conclusion I'd draw from this is that filehandles aren't as simple as we'd like -- because there's more underlying complexity than initially apparent.

      --Dave
      Opinions my own; statements of fact may be in error.

        I spent time addressing all these concerns in my post. I find it weird that you chose to disreguard them when suggesting an improvement.

        Support for all the special variables needs a little thought, because they are dynamically scoped. I'd probably want to capture their values in the "open" function and store those values in the object.

        Actually, it's much simpler than that. Inherit PRINT and PRINTF from Tie::Handle, and override WRITE like I did.

        I'm not sure that binmode is required for this filehandle. All it does is call a user-defined perl function for each line (implicitly text). If that code prints to a "real" filehandle, then it is that filehandle that needs to support binmode.

        It should have a dummy in case you want to use the handle somewhere that calls binmode. As is, it can't be used as a replacement for a normal file handle, which is the whole reason to use tie.

        I'd be interested to know how to rewrite the "open" function to avoid needing 5.8.x -- the requirement exists because of bugs in 5.6.x, so the simplest (and safest) thing it to require a version of perl that works reliably with tied filehandles.

        See wrap in my post. It works fine in 5.6.1.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://543942]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (15)
As of 2014-12-18 17:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (58 votes), past polls