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

Hi all,

I'm trying to write a kind of wrapper for Tie::File to allow it to manage different data formats (not only lines, or simple paragraphs). The idea is to access data records from a file as if they were in an array.

So far, the module looks like this:

package Tie::File::AnyData; use strict; use warnings; use Tie::File; sub TIEARRAY { my ($pack,$file,%opts) = @_; if (defined $opts{'code'}){ my $code = $opts{'code'}; delete $opts{'code'}; *Tie::File::get_next_rec = $code; no warnings 'redefine'; *Tie::File::_read_record = sub { my ($self) = @_; my $rec; $rec = Tie::File::get_next_rec ( $self->{'fh'} ); return $rec; } } Tie::File::TIEARRAY("Tie::File",$file,%opts); } 1;

The idea is to pass an anonymous subroutine that is able to retrieve the data from the file one record by one. Then, we redefine the original _read_record subroutine (that is present in Tie::File) to use this code.

This module can be used, for example, in the following way:

use Tie::File::AnyData; my $coderef = sub{ ## Code to retrieve one by one the records of a given format }; tie my @data, 'Tie::File::AnyData', $file, code => $coderef; ## Use the tied array

The code seems to work ok (as far as my tests can tell), but has one big limitation: you can not work with 2 data formats at the same time, because a second call to "tie" will override the get_next_rec subroutine:

my $format1 = sub { ## Subroutine that reads records with format 1 } my $format2 = sub { ## Subroutine that reads records with format 2 } tie my @dataf1, 'Tie::File::AnyData', $file_format1, code => $format1; + ## Creates get_next_rec and redefines _read_record tie my @dataf2, 'Tie::File::AnyData', $file_format2, code => $format2; + ## Re-defines get_next_rec!!

I think that this can be solved with some kind of polymorphism, but I don't know exactly how. Any suggestion in solving this would be highly appreciated

Thanks in advance!

citromatik

Replies are listed 'Best First'.
Re: dynamic polymorphism
by kyle (Abbot) on Sep 11, 2007 at 12:14 UTC

    Let me start by noticing that Tie::File says explicitly that it doesn't support subclassing.

    That said, you can probably get what you want by saving the user's code ref in your object's instance instead of in the symbol table. In TIEARRAY, say something like:

    $self->{_get_next_rec} = $opts{code} if ref $opts{code} eq 'CODE'; *Tie::File::_read_record = sub { my ($self) = @_; my $rec = $self->{_get_next_rec}->( $self->{fh} ); return $rec; };

    This way each object has its own code, and _read_record calls it.