PerlIO-via-SeqIO

 view release on metacpan or  search on metacpan

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

	return (wantarray ? $fh->getlines : $fh->getline);
    }
    # on EOF, return undef.
}

sub WRITE {
    my ($self, $buf, $fh) = @_;
    my $ios = $self->{io_string};
    my $ret = 0;
    # following may not work, if a Bio...=HASH... is broken up 
    # by buffering...
    my @input = split( /(Bio::.*?=HASH\(0x[0-9a-f]+\)\s)/, $buf ); 
    foreach my $item (@input) {
	if ($item =~ /HASH/) { # string rep of object
	    $item = $OBJS{$item};
	    $self->{engine}->write_seq($item);
	    $ios->pos(0); # seek to top
	    my $line = join('', <$ios>);
	    $ios->pos(0); ${$ios->string_ref}=''; 
	    $ret += $fh->write($line, length $line);
	    undef $OBJS{$item}; # clean up
	}
	else { # write the raw buffer
	    $fh->write($item, length($item)) if $item;
	}
    }
    $ret;
}

sub FLUSH {
    my ($self, $fh) = @_;
#    $DB::single=1;
    return $fh ? $fh->flush : 0;
#    return $fh->flush if !defined $self->{mode} or $self->{mode} =~ /w|a|\+/;
    return -1;
}

sub CLOSE {
    my ($self, $fh) = @_;
    return $fh->close;
}

# This open() is an optional (exported on explicit demand) replacement
# for the core, that provides for the redirection of STDIN/STDOUT/DATA
# through the via(SeqIO) layer. When this open is active, ordinary uses
# of open should be passed through unharmed (tests are in 001_passthru.t)

# to emulate redirection, which PerlIO::via doesn't do yet, the 
# special filehandle is tied to an internal tied class.
# This is truly spaghettified, because the tied handle needs access to 
# the via object's goodies, but it seems to work (002_seqio.t)

sub open  {
    no strict qw(refs);
    my ($fh, $mode, $file) = @_;
    if ($file or $mode !~ /:via\(SeqIO(?:::[a-zA-Z_]+)?\)/) {
	#passthru
	# if !defined $file, parse $mode according to presence of &...
	if ($fh) {
	    if ( $fh =~ /^[A-Z]+$/ ) {
		$fh = *{(caller)[0]."::$fh"};
	    }
	}
	if ($file) {
	    if ( $file =~ /^[A-Z]+$/) {
		$file = *{(caller)[0]."::$file"};
	    }
	    return CORE::open($fh || $_[0],$_[1],$file);
	}
	else {
	    $_[0] ? 
		($_[0] = PerlIO::Util->open($_[1])) : 
		CORE::open($fh || $_[0],$_[1]);

	}
    }
    # deal with special filehandles with 2-argument opens
    if ($fh and $fh =~ /(DATA|STD(?:IN|OUT))/) {
	no strict qw(refs);
	my $dup = gensym;
	my $bareword = $1;
	my $redirect = ($bareword =~ /OUT/ ? ">&" : "<&");
	# get a pristine copy of DATA/STDIN/STDOUT
	$fh = *{(caller)[0]."::$bareword"};
	CORE::open($dup, $redirect, $fh) or croak($!);
	if ($bareword =~ /OUT/) {
	    $| && $dup->autoflush(1);
	}
	# now, need to make everything output to the duplicated
	# handle; may need to use ties after all (to make real
	# writes to the subordinate handle only...)
	
	# provide dummy file to CORE::open
	my ($dumh, $file) = tempfile("dumXXXX", UNLINK=>1);
	close($dumh);
	# secretly pass the dup
	$PerlIO::via::SeqIO::__seqio_DUP = $dup;
	# kick PUSHED
	CORE::open( $dumh, $mode, $file) or croak( $! );
	undef $PerlIO::via::SeqIO::__seqio_DUP;

	tie $fh, '_viaSeqIO_FH';
	(tied $fh)->sub_fh($dup);
	# private pointer for tied object...
	(tied $fh)->via_o( $dumh->via_o );
	return 1;
	
    }
    else { # passthru
	$DB::single=1;
	($mode, $file) = $mode =~ /(\+?(?:<|>)?>?&?)(.*)/;
	$file =~ /^[A-Z]+$/ and $file = *{(caller)[0]."::$file"};
	$_[0] = PerlIO::Util->open($mode,$file);
    }
    1;
}

# seq object converter

sub T {
    my @objs = @_;
    my @ret;
    foreach my $s (@objs) {
	unless (defined $s and ref($s) and
		($s->isa('Bio::SeqI') || $s->isa('Bio::Seq') || 
		 $s->isa('Bio::PrimarySeq'))) {
	    carp "Item undefined or not a sequence object; returning an undef";
	    push @ret, undef;
	    next;
	}
	$s->isa('Bio::PrimarySeq') and $s = _pseq_to_seq($s);
	push @ret, sprintf("%s\n", $s);
	$OBJS{$ret[-1]} = $s;
    }
    return wantarray ? @ret : $ret[0];
}

# object getter ...

sub O {
    no strict qw(refs);
    my $sym = shift;
    $sym ||= $_; 
    for ($sym) {
	m/Bio/ && do {
	    return $OBJS{$sym}; last;
	};
	m/via/ && do {
	    return (tied $sym)->via_o; last;
	};
	m/^[A-Z]+$/ && do {
	    $sym = (caller)[0]."::$sym";
	    return (tied *$sym)->via_o if (tied *$sym);
	    return;
	    last;
	};
    }
    croak("Don't understand the arg");
}

# wrap Bio::PrimarySeqs (incl. Bio::LocatableSeqs) in a Bio::Seq
# for Bio::SeqIO use

sub _pseq_to_seq {
    my @pseqs = @_;
    my @ret;
    foreach (@pseqs) {
	unless (defined $_ && ref($_) && $_->isa('Bio::PrimarySeq')) {
	    push @ret, undef;
	    next;
	}
	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;



( run in 2.153 seconds using v1.01-cache-2.11-cpan-364913b4093 )