511 lines
14 KiB
HTML
511 lines
14 KiB
HTML
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<HTML><HEAD><TITLE>Man page of IO::WrapTie</TITLE>
|
|
</HEAD><BODY>
|
|
<H1>IO::WrapTie</H1>
|
|
Section: User Contributed Perl Documentation (3pm)<BR>Updated: 2019-02-28<BR><A HREF="#index">Index</A>
|
|
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<A NAME="lbAB"> </A>
|
|
<H2>NAME</H2>
|
|
|
|
IO::WrapTie - wrap tieable objects in IO::Handle interface
|
|
<P>
|
|
|
|
This is currently Alpha code, released for comments.
|
|
<BR> Please give me your feedback!
|
|
<A NAME="lbAC"> </A>
|
|
<H2>SYNOPSIS</H2>
|
|
|
|
|
|
|
|
First of all, you'll need <B>tie()</B>, so:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
require 5.004;
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
<I>Function interface (experimental).</I>
|
|
Use this with any existing class...
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
use IO::WrapTie;
|
|
use FooHandle; ### implements TIEHANDLE interface
|
|
|
|
### Suppose we want a "FooHandle->new(&FOO_RDWR, 2)".
|
|
### We can instead say...
|
|
|
|
$FH = wraptie('FooHandle', &FOO_RDWR, 2);
|
|
|
|
### Now we can use...
|
|
print $FH "Hello, "; ### traditional operator syntax...
|
|
$FH->print("world!\n"); ### ...and OO syntax as well!
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
<I></I><FONT SIZE="-1"><I>OO</I></FONT><I> interface (preferred).</I>
|
|
You can inherit from the IO::WrapTie::Slave mixin to get a
|
|
nifty <TT>"new_tie()"</TT> constructor...
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
#------------------------------
|
|
package FooHandle; ### a class which can TIEHANDLE
|
|
|
|
use IO::WrapTie;
|
|
@ISA = qw(IO::WrapTie::Slave); ### inherit new_tie()
|
|
...
|
|
|
|
|
|
#------------------------------
|
|
package main;
|
|
|
|
$FH = FooHandle->new_tie(&FOO_RDWR, 2); ### $FH is an IO::WrapTie::Master
|
|
print $FH "Hello, "; ### traditional operator syntax
|
|
$FH->print("world!\n"); ### OO syntax
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
See IO::Scalar as an example. It also shows you how to create classes
|
|
which work both with and without 5.004.
|
|
<A NAME="lbAD"> </A>
|
|
<H2>DESCRIPTION</H2>
|
|
|
|
|
|
|
|
Suppose you have a class <TT>"FooHandle"</TT>, where...
|
|
<DL COMPACT>
|
|
<DT id="1">•<DD>
|
|
<B>FooHandle does not inherit from IO::Handle;</B> that is, it performs
|
|
filehandle-like I/O, but to something other than an underlying
|
|
file descriptor. Good examples are IO::Scalar (for printing to a
|
|
string) and IO::Lines (for printing to an array of lines).
|
|
<DT id="2">•<DD>
|
|
<B>FooHandle implements the </B><FONT SIZE="-1"><B>TIEHANDLE</B></FONT><B> interface</B> (see perltie);
|
|
that is, it provides methods <FONT SIZE="-1">TIEHANDLE, GETC, PRINT, PRINTF,
|
|
READ,</FONT> and <FONT SIZE="-1">READLINE.</FONT>
|
|
<DT id="3">•<DD>
|
|
<B>FooHandle implements the traditional </B><FONT SIZE="-1"><B>OO</B></FONT><B> interface</B> of
|
|
FileHandle and IO::Handle; i.e., it contains methods like <B>getline()</B>,
|
|
<B>read()</B>, <B>print()</B>, <B>seek()</B>, <B>tell()</B>, <B>eof()</B>, etc.
|
|
</DL>
|
|
<P>
|
|
|
|
Normally, users of your class would have two options:
|
|
<DL COMPACT>
|
|
<DT id="4">•<DD>
|
|
<B>Use only </B><FONT SIZE="-1"><B>OO</B></FONT><B> syntax,</B> and forsake named I/O operators like 'print'.
|
|
<DT id="5">•<DD>
|
|
<B>Use with tie,</B> and forsake treating it as a first-class object
|
|
(i.e., class-specific methods can only be invoked through the underlying
|
|
object via <B>tied()</B>... giving the object a ``split personality'').
|
|
</DL>
|
|
<P>
|
|
|
|
But now with IO::WrapTie, you can say:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
$WT = wraptie('FooHandle', &FOO_RDWR, 2);
|
|
$WT->print("Hello, world\n"); ### OO syntax
|
|
print $WT "Yes!\n"; ### Named operator syntax too!
|
|
$WT->weird_stuff; ### Other methods!
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
And if you're authoring a class like FooHandle, just have it inherit
|
|
from <TT>"IO::WrapTie::Slave"</TT> and that first line becomes even prettier:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
$WT = FooHandle->new_tie(&FOO_RDWR, 2);
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
<B>The bottom line:</B> now, almost any class can look and work exactly like
|
|
an IO::Handle... and be used both with <FONT SIZE="-1">OO</FONT> and non-OO filehandle syntax.
|
|
<A NAME="lbAE"> </A>
|
|
<H2>HOW IT ALL WORKS</H2>
|
|
|
|
|
|
|
|
<A NAME="lbAF"> </A>
|
|
<H3>The data structures</H3>
|
|
|
|
|
|
|
|
Consider this example code, using classes in this distribution:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
use IO::Scalar;
|
|
use IO::WrapTie;
|
|
|
|
$WT = wraptie('IO::Scalar',\$s);
|
|
print $WT "Hello, ";
|
|
$WT->print("world!\n");
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
In it, the <B>wraptie()</B> function creates a data structure as follows:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
* $WT is a blessed reference to a tied filehandle
|
|
$WT glob; that glob is tied to the "Slave" object.
|
|
| * You would do all your i/o with $WT directly.
|
|
|
|
|
|
|
|
| ,---isa--> IO::WrapTie::Master >--isa--> IO::Handle
|
|
V /
|
|
.-------------.
|
|
| |
|
|
| | * Perl i/o operators work on the tied object,
|
|
| "Master" | invoking the TIEHANDLE methods.
|
|
| | * Method invocations are delegated to the tied
|
|
| | slave.
|
|
`-------------'
|
|
|
|
|
tied(*$WT) | .---isa--> IO::WrapTie::Slave
|
|
V /
|
|
.-------------.
|
|
| |
|
|
| "Slave" | * Instance of FileHandle-like class which doesn't
|
|
| | actually use file descriptors, like IO::Scalar.
|
|
| IO::Scalar | * The slave can be any kind of object.
|
|
| | * Must implement the TIEHANDLE interface.
|
|
`-------------'
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
<I></I><FONT SIZE="-1"><I>NOTE:</I></FONT><I></I> just as an IO::Handle is really just a blessed reference to a
|
|
<I>traditional</I> filehandle glob... so also, an IO::WrapTie::Master
|
|
is really just a blessed reference to a filehandle
|
|
glob <I>which has been tied to some ``slave'' class.</I>
|
|
<A NAME="lbAG"> </A>
|
|
<H3>How <B>wraptie()</B> works</H3>
|
|
|
|
|
|
|
|
<DL COMPACT>
|
|
<DT id="6">1.<DD>
|
|
The call to function <TT>"wraptie(SLAVECLASS, TIEARGS...)"</TT> is
|
|
passed onto <TT>"IO::WrapTie::Master::new()"</TT>.
|
|
Note that class IO::WrapTie::Master is a subclass of IO::Handle.
|
|
<DT id="7">2.<DD>
|
|
The <TT>"IO::WrapTie::Master::new"</TT> method creates a new IO::Handle object,
|
|
reblessed into class IO::WrapTie::Master. This object is the <I>master</I>,
|
|
which will be returned from the constructor. At the same time...
|
|
<DT id="8">3.<DD>
|
|
The <TT>"new"</TT> method also creates the <I>slave</I>: this is an instance
|
|
of <FONT SIZE="-1">SLAVECLASS</FONT> which is created by tying the master's IO::Handle
|
|
to <FONT SIZE="-1">SLAVECLASS</FONT> via <TT>"tie(HANDLE, SLAVECLASS, TIEARGS...)"</TT>.
|
|
This call to <TT>"tie()"</TT> creates the slave in the following manner:
|
|
<DT id="9">4.<DD>
|
|
Class <FONT SIZE="-1">SLAVECLASS</FONT> is sent the message <TT>"TIEHANDLE(TIEARGS...)"</TT>; it
|
|
will usually delegate this to <TT>"SLAVECLASS::new(TIEARGS...)"</TT>, resulting
|
|
in a new instance of <FONT SIZE="-1">SLAVECLASS</FONT> being created and returned.
|
|
<DT id="10">5.<DD>
|
|
Once both master and slave have been created, the master is returned
|
|
to the caller.
|
|
</DL>
|
|
<A NAME="lbAH"> </A>
|
|
<H3>How I/O operators work (on the master)</H3>
|
|
|
|
|
|
|
|
Consider using an i/o operator on the master:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
print $WT "Hello, world!\n";
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
Since the master ($WT) is really a [blessed] reference to a glob,
|
|
the normal Perl i/o operators like <TT>"print"</TT> may be used on it.
|
|
They will just operate on the symbol part of the glob.
|
|
<P>
|
|
|
|
Since the glob is tied to the slave, the slave's <FONT SIZE="-1">PRINT</FONT> method
|
|
(part of the <FONT SIZE="-1">TIEHANDLE</FONT> interface) will be automatically invoked.
|
|
<P>
|
|
|
|
If the slave is an IO::Scalar, that means IO::Scalar::PRINT will be
|
|
invoked, and that method happens to delegate to the <TT>"print()"</TT> method
|
|
of the same class. So the <I>real</I> work is ultimately done by
|
|
<B>IO::Scalar::print()</B>.
|
|
<A NAME="lbAI"> </A>
|
|
<H3>How methods work (on the master)</H3>
|
|
|
|
|
|
|
|
Consider using a method on the master:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
$WT->print("Hello, world!\n");
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
Since the master ($WT) is blessed into the class IO::WrapTie::Master,
|
|
Perl first attempts to find a <TT>"print()"</TT> method there. Failing that,
|
|
Perl next attempts to find a <TT>"print()"</TT> method in the superclass,
|
|
IO::Handle. It just so happens that there <I>is</I> such a method;
|
|
that method merely invokes the <TT>"print"</TT> i/o operator on the self object...
|
|
and for that, see above!
|
|
<P>
|
|
|
|
But let's suppose we're dealing with a method which <I>isn't</I> part
|
|
of IO::Handle... for example:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
my $sref = $WT->sref;
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
In this case, the intuitive behavior is to have the master delegate the
|
|
method invocation to the slave (now do you see where the designations
|
|
come from?). This is indeed what happens: IO::WrapTie::Master contains
|
|
an <FONT SIZE="-1">AUTOLOAD</FONT> method which performs the delegation.
|
|
<P>
|
|
|
|
So: when <TT>"sref()"</TT> can't be found in IO::Handle, the <FONT SIZE="-1">AUTOLOAD</FONT> method
|
|
of IO::WrapTie::Master is invoked, and the standard behavior of
|
|
delegating the method to the underlying slave (here, an IO::Scalar)
|
|
is done.
|
|
<P>
|
|
|
|
Sometimes, to get this to work properly, you may need to create
|
|
a subclass of IO::WrapTie::Master which is an effective master for
|
|
<I>your</I> class, and do the delegation there.
|
|
<A NAME="lbAJ"> </A>
|
|
<H2>NOTES</H2>
|
|
|
|
|
|
|
|
<B>Why not simply use the object's </B><FONT SIZE="-1"><B>OO</B></FONT><B> interface?</B>
|
|
<BR> Because that means forsaking the use of named operators
|
|
like <B>print()</B>, and you may need to pass the object to a subroutine
|
|
which will attempt to use those operators:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
$O = FooHandle->new(&FOO_RDWR, 2);
|
|
$O->print("Hello, world\n"); ### OO syntax is okay, BUT....
|
|
|
|
sub nope { print $_[0] "Nope!\n" }
|
|
X nope($O); ### ERROR!!! (not a glob ref)
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
<B>Why not simply use tie()?</B>
|
|
<BR> Because (1) you have to use <B>tied()</B> to invoke methods in the
|
|
object's public interface (yuck), and (2) you may need to pass
|
|
the tied symbol to another subroutine which will attempt to treat
|
|
it in an OO-way... and that will break it:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
tie *T, 'FooHandle', &FOO_RDWR, 2;
|
|
print T "Hello, world\n"; ### Operator is okay, BUT...
|
|
|
|
tied(*T)->other_stuff; ### yuck! AND...
|
|
|
|
sub nope { shift->print("Nope!\n") }
|
|
X nope(\*T); ### ERROR!!! (method "print" on unblessed ref)
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
<B>Why a master and slave?
|
|
<BR> Why not simply write FooHandle to inherit from IO::Handle?</B>
|
|
<BR> I tried this, with an implementation similar to that of IO::Socket.
|
|
The problem is that <I>the whole point is to use this with objects
|
|
that don't have an underlying file/socket descriptor.</I>.
|
|
Subclassing IO::Handle will work fine for the <FONT SIZE="-1">OO</FONT> stuff, and fine with
|
|
named operators <I>if</I> you <B>tie()</B>... but if you just attempt to say:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
$IO = FooHandle->new(&FOO_RDWR, 2);
|
|
print $IO "Hello!\n";
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
you get a warning from Perl like:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
Filehandle GEN001 never opened
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
because it's trying to do system-level i/o on an (unopened) file
|
|
descriptor. To avoid this, you apparently have to <B>tie()</B> the handle...
|
|
which brings us right back to where we started! At least the
|
|
IO::WrapTie mixin lets us say:
|
|
<P>
|
|
|
|
|
|
|
|
<PRE>
|
|
$IO = FooHandle->new_tie(&FOO_RDWR, 2);
|
|
print $IO "Hello!\n";
|
|
|
|
</PRE>
|
|
|
|
|
|
<P>
|
|
|
|
and so is not <I>too</I> bad. <TT>":-)"</TT>
|
|
<A NAME="lbAK"> </A>
|
|
<H2>WARNINGS</H2>
|
|
|
|
|
|
|
|
Remember: this stuff is for doing FileHandle-like i/o on things
|
|
<I>without underlying file descriptors</I>. If you have an underlying
|
|
file descriptor, you're better off just inheriting from IO::Handle.
|
|
<P>
|
|
|
|
<B>Be aware that new_tie() always returns an instance of a
|
|
kind of IO::WrapTie::Master...</B> it does <B>not</B> return an instance
|
|
of the i/o class you're tying to!
|
|
<P>
|
|
|
|
Invoking some methods on the master object causes <FONT SIZE="-1">AUTOLOAD</FONT> to delegate
|
|
them to the slave object... so it <I>looks</I> like you're manipulating a
|
|
``FooHandle'' object directly, but you're not.
|
|
<P>
|
|
|
|
I have not explored all the ramifications of this use of <B>tie()</B>.
|
|
<I>Here there be dragons</I>.
|
|
<A NAME="lbAL"> </A>
|
|
<H2>VERSION</H2>
|
|
|
|
|
|
|
|
<TT>$Id:</TT> WrapTie.pm,v 1.2 2005/02/10 21:21:53 dfs Exp $
|
|
<A NAME="lbAM"> </A>
|
|
<H2>AUTHOR</H2>
|
|
|
|
|
|
|
|
<DL COMPACT>
|
|
<DT id="11">Primary Maintainer<DD>
|
|
|
|
|
|
Dianne Skoll (<I><A HREF="mailto:dfs@roaringpenguin.com">dfs@roaringpenguin.com</A></I>).
|
|
<DT id="12">Original Author<DD>
|
|
|
|
|
|
Eryq (<I><A HREF="mailto:eryq@zeegee.com">eryq@zeegee.com</A></I>).
|
|
President, ZeeGee Software Inc (<I><A HREF="http://www.zeegee.com">http://www.zeegee.com</A></I>).
|
|
<P>
|
|
</DL>
|
|
|
|
<HR>
|
|
<A NAME="index"> </A><H2>Index</H2>
|
|
<DL>
|
|
<DT id="13"><A HREF="#lbAB">NAME</A><DD>
|
|
<DT id="14"><A HREF="#lbAC">SYNOPSIS</A><DD>
|
|
<DT id="15"><A HREF="#lbAD">DESCRIPTION</A><DD>
|
|
<DT id="16"><A HREF="#lbAE">HOW IT ALL WORKS</A><DD>
|
|
<DL>
|
|
<DT id="17"><A HREF="#lbAF">The data structures</A><DD>
|
|
<DT id="18"><A HREF="#lbAG">How <B>wraptie()</B> works</A><DD>
|
|
<DT id="19"><A HREF="#lbAH">How I/O operators work (on the master)</A><DD>
|
|
<DT id="20"><A HREF="#lbAI">How methods work (on the master)</A><DD>
|
|
</DL>
|
|
<DT id="21"><A HREF="#lbAJ">NOTES</A><DD>
|
|
<DT id="22"><A HREF="#lbAK">WARNINGS</A><DD>
|
|
<DT id="23"><A HREF="#lbAL">VERSION</A><DD>
|
|
<DT id="24"><A HREF="#lbAM">AUTHOR</A><DD>
|
|
</DL>
|
|
<HR>
|
|
This document was created by
|
|
<A HREF="/cgi-bin/man/man2html">man2html</A>,
|
|
using the manual pages.<BR>
|
|
Time: 00:05:46 GMT, March 31, 2021
|
|
</BODY>
|
|
</HTML>
|