PerlIO-via-SeqIO

 view release on metacpan or  search on metacpan

lib/PerlIO/via/SeqIO.pm  view on Meta::CPAN

	push @IO::Handle::ISA, 'IO::Handle::_viaSeqIO';
    }
    return;
}

our %MODE_SYM = (
    'r' => '<',
    'w' => '>',
    'a' => '>>',
    'r+' => '+<',
    'w+' => '+>',
    'a+' => '+>>'
    );

# init the layer:

sub PUSHED {
#    no strict qw(refs);
    my $self = { 
	'instance' => $INSTANCE,	
	'mode' => $_[1],
	'perl_mode' => $MODE_SYM{$_[1]},
	'format' => (split(m{::}, $_[0]))[-1],
	'eot'    => 0,
	'fh'     => undef,
	'fileno' => undef,
	'source' => undef,
	'engine' => undef,
	'inited' => 0
    };
    $self->{self} = $self; weaken $self->{self};
    $self->{format} = '' if $self->{format} eq 'SeqIO';
    bless ( $self, $_[0] );
}

# the problem: if OPEN is specified in a via module, 
# you never see the filehandle in subsequent via method
# calls (FILL, WRITE, etc.); yet we need to have access
# to the handle returned by open...however, if we do not
# define OPEN, all via method calls recieve the filehandle
# provided by the lower-level open.
# the hack: fileno() is called at the end of the lower-level
# open call; so the via FILENO provides a hook that receives
# the lower-level filehandle. We pre-empt FILENO one time to
# do our setup machinations on the real filehandle.

# grab the opened filehandle using FILENO (called at the 
# end of open() !)
sub FILENO {
    no strict qw(refs);
    my ($self,$fh) = @_;
    if (!$self->{inited}) {
	# if the secret dup is here, use it
	$fh = $PerlIO::via::SeqIO::__seqio_DUP || $fh;
	$self->{fileno} = fileno($fh); # nec to kick fileno hooks
	$self->{eot} = 0;
	for ($self->{mode}) {
	    m/r/ && do {
		$self->{source} =
		    Bio::SeqIO->new( -fh=>$fh, -format=>$self->{format} );
		$self->{format} ||= (split m/::/,ref($self->{source}))[-1];
		last;
	    };
	    m/w|a/ && do {
		$self->set_write_format($self->{format});
		last;
	    };
	    do { #huh?
		croak "failed(INIT): Don't understand mode '".$self->{mode}."'";
	    };
	}
	# connect the via object to the filehandle
	$fh->via_o($self); 
	$INSTANCE++;
	$self->{inited} = 1;
    }
    return $self->{fileno} || -1;
}

sub set_write_format {
    my ($self, $format) = @_;
    unless (grep( /^$format$/, @PerlIO::via::SeqIO::SUPPORTED_FORMATS)) {
	carp("The format '$format' isn't supported; current format unchanged");
	return;
    }
    unless ($self->{mode}  =~ /\+|w/) {
	carp("Can't set format; handle not open for writing");
	return;
    }
    $self->{format} = $format;
    $self->{io_string} = IO::String->new();
    $self->{engine} = Bio::SeqIO->new(-fh=>$self->{io_string},
				  -format=>$self->{format});
    $self->{engine}->_flush_on_write(1);
    return 1;
}

# the FILL/_readline crosstalk allows true "line-by-line" parsing with
# angle brackets. It's a hack, but the lower-level doesn't respect
# $/, as has been advertised (as far as I can tell)

sub FILL {
    my ($self, $fh) = @_;
    my $line;
    my $sep = $/;
    if ($self->{eot} == 0) {
	$self->{eot} = 1;
	$line = $self->_readline;
	$line && $sep && $line =~ s/$sep$//;
	return $line;
    }
    else { # EOT
	$self->{eot} = 0; # clear flag
#	$DB::single=1;
	if ($/) {
	    return "$/"; # kick out of FILL loop
	    # TODO: figure out why this doesn't work in ActiveState, when
	    # reading via gzip.
	}
	else {
	    return $self->_readline($fh);

lib/PerlIO/via/SeqIO.pm  view on Meta::CPAN

	}
	my $seq = Bio::Seq->new();
	$seq->id( $_->display_id || $_->id );
	$seq->primary_seq( $_ );
	push @ret, $seq;
    }
    return wantarray ? @ret : $ret[0];
}

1;

# tied handle class for special filehandle 2-argument opens
# see comments to open()

package _viaSeqIO_FH;
use strict;
use warnings;
use Config;
our %__SUB_FH;
our $AUTOLOAD;

sub TIEHANDLE { bless ( { sub_fh => undef, via_o => undef }, $_[0] ) }

sub PRINT {
    my ($self, @args) = @_;
    # use the via object's write method on the sub-handle:
    foreach (@args) {
	$self->via_o->WRITE( $_, $self->sub_fh);
    }
    return 1;
}

sub sub_fh {
    my ($self, $fh) = @_;
    if ($fh) {
	#kludge for ActivePerl:
	if ($Config{cf_email} =~ /ActiveState/) { 
	    push @IO::Handle::ISA, 'IO::Seekable';
	}
	return $__SUB_FH{$fh->fileno} = $fh;
    }
    return unless defined $self->fileno;
    return $__SUB_FH{$self->fileno};
}

sub via_o {
    my ($self, $o) = @_;
    if ($o) {
	$self->{via_o} = $o;
	Scalar::Util::weaken($self->{via_o});
    }
    return $self->{via_o};
}

# use AUTOLOAD to perform handle operations on the 
# subhandle, but delegate the work back to the 
# via class (is this Laziness, or laziness?)

sub AUTOLOAD {
    my ($self,@args) = @_;
    my $func = lc ((split m/::/, $AUTOLOAD)[-1]);
    # specials
    $func = uc $func if $func =~ /destroy/;

    for ($func) {
	# delegate these back to the via object:
	m/readline/ && do {
	    return wantarray ? 
		($self->via_o->_readline($self->sub_fh)) :
		$self->via_o->_readline($self->sub_fh);
	};
	m/fileno/ && do {
	    return unless $self->via_o;
	    return $self->via_o->FILENO();
	};
	m/flush/ && do {
	    return $self->via_o->FLUSH($self->sub_fh);
	};
	m/close/ && do {
	    return $self->via_o->CLOSE($self->sub_fh);
	};
        # otherwise, use the native methods of the sub-handle:
	do { 
	    return unless $self->sub_fh;
	    return $self->sub_fh->$func(@args);
	};
    }
}

# pollute IO::Handle slightly differently ( to avoid unauthorized
# release error)
package IO::Handle::_viaSeqIO;
use strict;
use warnings;
use Scalar::Util qw(weaken);

our %__VIA_O;

sub via_o {
    my ($self, $o) = @_;
    my $key = $self->fileno;
    if ($o) {
	$__VIA_O{$key} = $o;
	weaken($__VIA_O{$key});
    }
    return $__VIA_O{$key};
}

# want to call this off the filehandle to keep the 
# interface simple...

sub set_write_format {
    my ($self, $format) = @_;
    return unless $self->via_o;
    # delegate
    return $self->via_o->set_write_format($format);
}


1;
__END__



( run in 1.090 second using v1.01-cache-2.11-cpan-71847e10f99 )