AcePerl
view release on metacpan or search on metacpan
Ace/Sequence.pm view on Meta::CPAN
['OFFSET','OFF'],
['LENGTH','LEN'],
'REFSEQ',
['DATABASE','DB'],
],@_);
# Object must have a parent sequence and/or a reference
# sequence. In some cases, the parent sequence will be the
# object itself. The reference sequence is used to set up
# the frame of reference for the coordinate system.
# fetch the sequence object if we don't have it already
croak "Please provide either a Sequence object or a database and name"
unless ref($seq) || ($seq && $db);
# convert start into offset
$offset = $start - 1 if defined($start) and !defined($offset);
# convert stop/end into length
$length = ($end > $start) ? $end - $offset : $end - $offset - 2
if defined($end) && !defined($length);
# if just a string is passed, try to fetch a Sequence object
my $obj = ref($seq) ? $seq : $db->fetch('Sequence'=>$seq);
unless ($obj) {
Ace->error("No Sequence named $obj found in database");
return;
}
# get parent coordinates and length of this sequence
# the parent is an Ace Sequence object in the "+" strand
my ($parent,$p_offset,$p_length,$strand) = find_parent($obj);
return unless $parent;
# handle negative strands
my $r_strand = $strand;
my $r_offset = $p_offset;
$offset ||= 0;
$offset *= -1 if $strand < 0;
# handle feature objects
$offset += $obj->offset if $obj->can('smapped');
# get source
my $source = $obj->can('smapped') ? $obj->source : $obj;
# store the object into our instance variables
my $self = bless {
obj => $source,
offset => $offset,
length => $length || $p_length,
parent => $parent,
p_offset => $p_offset,
refseq => [$source,$r_offset,$r_strand],
strand => $strand,
absolute => 0,
automerge => 1,
},$pack;
# set the reference sequence
eval { $self->refseq($refseq) } or return if defined $refseq;
# wheww!
return $self;
}
# return the "source" object that the user offset from
sub source {
$_[0]->{obj};
}
# return the parent object
sub parent { $_[0]->{parent} }
# return the length
#sub length { $_[0]->{length} }
sub length {
my $self = shift;
my ($start,$end) = ($self->start,$self->end);
return $end - $start + ($end > $start ? 1 : -1); # for stupid 1-based adjustments
}
sub reversed { return shift->strand < 0; }
sub automerge {
my $self = shift;
my $d = $self->{automerge};
$self->{automerge} = shift if @_;
$d;
}
# return reference sequence
sub refseq {
my $self = shift;
my $prev = $self->{refseq};
if (@_) {
my $refseq = shift;
my $arrayref;
BLOCK: {
last BLOCK unless defined ($refseq);
if (ref($refseq) && ref($refseq) eq 'ARRAY') {
$arrayref = $refseq;
last BLOCK;
}
if (ref($refseq) && ($refseq->can('smapped'))) {
croak "Reference sequence has no common ancestor with sequence"
unless $self->parent eq $refseq->parent;
my ($a,$b,$c) = @{$refseq->{refseq}};
# $b += $refseq->offset;
$b += $refseq->offset;
$arrayref = [$refseq,$b,$refseq->strand];
last BLOCK;
}
# look up reference sequence in database if we aren't given
# database object already
$refseq = $self->db->fetch('Sequence' => $refseq)
Ace/Sequence.pm view on Meta::CPAN
return ($tl,$offset,$strand < 0 ? ($length,'-1') : ($length,'+1') ) if $length;
}
sub _get_toplevel {
my $obj = shift;
my $class = $obj->class;
my $name = $obj->name;
my $smap = $obj->db->raw_query("gif smap -from $class:$name");
my ($parent,$pstart,$pstop,$tstart,$tstop,$map_type) =
$smap =~ /^SMAP\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.+)/;
$parent ||= '';
$parent =~ s/^Sequence://; # remove this in next version of Acedb
return ($parent,$pstart,$pstop);
}
# create subroutine that filters GFF files for certain feature types
sub _make_filter {
my $self = shift;
my $automerge = $self->automerge;
# parse out the filter
my %filter;
foreach (@_) {
my ($type,$filter) = split(':',$_,2);
if ($automerge && lc($type) eq 'transcript') {
@filter{'exon','intron','Sequence','cds'} = ([undef],[undef],[undef],[undef]);
} elsif ($automerge && lc($type) eq 'clone') {
@filter{'Clone_left_end','Clone_right_end','Sequence'} = ([undef],[undef],[undef]);
} else {
push @{$filter{$type}},$filter;
}
}
# create pattern-match sub
my $sub;
my $promiscuous; # indicates that there is a subtype without a type
if (%filter) {
my $s = "sub { my \@d = split(\"\\t\",\$_[0]);\n";
for my $type (keys %filter) {
my $expr;
my $subtypes = $filter{$type};
if ($type ne '') {
for my $st (@$subtypes) {
$expr .= defined $st ? "return 1 if \$d[2]=~/$type/i && \$d[1]=~/$st/i;\n"
: "return 1 if \$d[2]=~/$type/i;\n"
}
} else { # no type, only subtypes
$promiscuous++;
for my $st (@$subtypes) {
next unless defined $st;
$expr .= "return 1 if \$d[1]=~/$st/i;\n";
}
}
$s .= $expr;
}
$s .= "return;\n }";
$sub = eval $s;
croak $@ if $@;
} else {
$sub = sub { 1; }
}
return ($sub,$promiscuous ? [] : [keys %filter]);
}
# turn a GFF file and a filter into a list of Ace::Sequence::Feature objects
sub _make_features {
my $self = shift;
my ($gff,$filter) = @_;
my ($r,$r_offset,$r_strand) = $self->refseq;
my $parent = $self->parent;
my $abs = $self->absolute;
if ($abs) {
$r_offset = 0;
$r = $parent;
$r_strand = '+1';
}
my @features = map {Ace::Sequence::Feature->new($parent,$r,$r_offset,$r_strand,$abs,$_)}
grep !m@^(?:\#|//)@ && $filter->($_),split("\n",$gff);
}
# low level GFF call, no changing absolute to relative coordinates
sub _gff {
my $self = shift;
my ($opt,$db) = @_;
my $data = $self->_query("seqfeatures -version 2 $opt",$db);
$data =~ s/\0+\Z//;
return $data; #blasted nulls!
}
# shortcut for running a gif query
sub _query {
my $self = shift;
my $command = shift;
my $db = shift || $self->db;
my $parent = $self->parent;
my $start = $self->start(1);
my $end = $self->end(1);
($start,$end) = ($end,$start) if $start > $end; #flippity floppity
my $coord = "-coords $start $end";
# BAD BAD HACK ALERT - CHECKS THE QUERY THAT IS PASSED DOWN
# ALSO MAKES THINGS INCOMPATIBLE WITH PRIOR 4.9 servers.
# my $opt = $command =~ /seqfeatures/ ? '-nodna' : '';
my $opt = '-noclip';
my $query = "gif seqget $parent $opt $coord ; $command";
warn $query if $self->debug;
return $db->raw_query("gif seqget $parent $opt $coord ; $command");
}
# utility function -- reverse complement
sub _complement {
( run in 0.739 second using v1.01-cache-2.11-cpan-98e64b0badf )