package BITS::Training::Primer;
use strict;
use Bio::Seq;
use Bio::Tools::IUPAC;
use FreezeThaw qw/freeze thaw/;
sub new {
my ( $class, $sequence ) = @_;
my $obj;
# this allows to pass a Bio::Seq object or a sequence string
if ( ref $sequence && $sequence->isa('Bio::Seq') ) {
$obj = $sequence;
$sequence = $obj->seq;
}
else {
$obj = Bio::Seq->new( -seq => $sequence, -alphabet => 'dna' );
}
my $self = {
_obj => $obj,
_degenerate => ( $sequence =~ /[^ACGT]/i ? 1 : 0 ),
_composition => {
A => $sequence =~ tr/A/A/, # count number of A's
C => $sequence =~ tr/C/C/, # count number of C's
G => $sequence =~ tr/G/G/, # count number of G's
T => $sequence =~ tr/T/T/ # count number of T's
},
_tm => undef,
};
bless $self, ref($class) || $class;
}
sub getSequence {
my $self = shift;
return $self->{_obj}->seq;
}
sub getSeqObject {
my $self = shift;
# don't want to temper with the embedded seq object
# return a copy instead
my ($seq) = thaw( freeze( $self->{_obj} ) );
return $seq;
}
sub getLength {
my $self = shift;
return $self->{_obj}->length;
}
sub isDegenerate {
my $self = shift;
return $self->{_degenerate};
}
sub numberOf {
my $self = shift;
my $nt = shift;
$nt = uc $nt;
return
exists $self->{_composition}->{$nt} ? $self->{_composition}->{$nt} : 0;
}
sub getTm {
my $self = shift;
# if called the first time
# _tm attribute is not set
# so, calculate and set the attribute first
unless ( defined $self->{_tm} ) {
$self->_calculateTm();
}
return $self->{_tm};
}
sub getUniquePrimers() {
my $self = shift;
if ( !$self->isDegenerate ) {
return wantarray ? ($self) : $self;
}
my $stream = Bio::Tools::IUPAC->new( -seq => $self->{_obj} );
my @uniques = ();
while ( my $unique_seq = $stream->next_seq ) {
push @uniques, $self->new($unique_seq); # directly pass the seq object as argument for the constructor
}
return wantarray ? @uniques : \@uniques;
}
sub _calculateTm {
my $self = shift;
my $sum = 0;
my @uniques = $self->getUniquePrimers;
foreach my $primer (@uniques) {
$sum +=
( $primer->numberOf('A') + $primer->numberOf('T') ) * 2 +
( $primer->numberOf('G') + $primer->numberOf('C') ) * 4;
}
$self->{_tm} = $sum / @uniques;
}
'Just Another True Value';