Bio-App-SELEX-RNAmotifAnalysis

 view release on metacpan or  search on metacpan

lib/Bio/App/SELEX/Stockholm.pm  view on Meta::CPAN

=head2 to_file

    $stock->to_file ($filename);

Writes a Stockholm object to a file.

=cut

# to_file method
sub to_file {
    my ( $self, $filename, $maxcols ) = @_;

    local *FILE;
    open FILE, ">$filename"
      or croak "Couldn't open '$filename' for writing: $!";
    print FILE $self->to_string($maxcols);
    close FILE or croak "Couldn't close '$filename': $!";

    return $filename;
}

=head2 to_string

    print $stock->to_string ($maxcols)
    print $stock->to_string ($maxcols, ARG1=>VAL1, ARG2=>VAL2 ...)
    print $stock->to_string (MAXCOLS=>$maxcols, ARG1=>VAL1, ARG2=>VAL2 ...)

Returns the object as a Stockholm-formatted string.

ARGs can include...
        MAXCOLS    -- limit maximum number of columns (can also be specified as a single scalar arg)
        NOSEQDATA  -- don\'t print any sequence data (can be used this to compress output)

=cut

# to_string method
# Usage:
#        $stock->to_string ($maxcols)
#        $stock->to_string ($maxcols, ARG1=>VAL1, ARG2=>VAL2 ...)
#        $stock->to_string (MAXCOLS=>$maxcols, ARG1=>VAL1, ARG2=>VAL2 ...)
# Args:
#        MAXCOLS    -- limit maximum number of columns (can also be specified as a single scalar arg)
#        NOSEQDATA  -- don't print any sequence data ("windowlicker.pl" uses this to compress output)
sub to_string {
    my ( $self, @args ) = @_;
    my ( %args, $maxcols );
    if ( @args % 2 == 1 ) {
        $maxcols = shift @args;
        %args    = @args;
    }
    else {
        %args    = @args;
        $maxcols = $args{'MAXCOLS'};
    }
    $maxcols = 80 unless defined $maxcols;    # default 80-column output

    # init output array
    my @out;
    push @out, "# STOCKHOLM 1.0";

    # determine alignment columns, legend columns & effective columns per line
    my $acols   = $self->columns;
    my $lcols   = $self->lcols;
    my $colstep = $maxcols < 1 ? $acols : $maxcols - $lcols - 1;
    $colstep = $maxcols
      if $colstep < 1;    # protect against negative and 0 colstep...

    # GF lines
    # check for gfOrder (insane, fragile Stockholm line ordering strikes again)
    if ( @{ $self->gfOrder } == map { (@$_) } values %{ $self->gf } )
    {                     # gfOrder same number of lines as #=GF block?
        my %gfCursor = map ( ( $_ => 0 ), keys %{ $self->gf } );
        foreach my $feature ( @{ $self->gfOrder } ) {
            push @out,
              $self->prettify(
                $lcols,
                "#=GF $feature",
                $self->gf_($feature)->[ $gfCursor{$feature}++ ]
              );
        }
    }
    else {
        @{ $self->gfOrder } = ();    # gfOrder is useless, so flush it
        foreach my $feature ( sort { $a cmp $b } keys %{ $self->gf } ) {
            push @out,
              $self->prettify(
                $lcols,
                "#=GF $feature",
                @{ $self->gf_($feature) }
              );
        }
    }

    # GS lines
    my @gs_seqname = @{ $self->seqname };
    my %gs_seqname_hash = map ( ( $_ => 1 ),
        grep ( !exists $self->seqdata->{$_},
            map ( keys( %{ $self->gs_($_) } ), keys %{ $self->gs } ) ) );
    push @gs_seqname, keys %gs_seqname_hash;
    foreach my $feature ( sort { $a cmp $b } keys %{ $self->gs } ) {
        my $hash = $self->gs_($feature);
        foreach my $seqname ( grep ( exists( $hash->{$_} ), @gs_seqname ) ) {
            push @out,
              $self->prettify(
                $lcols,
                "#=GS $seqname $feature",
                @{ $hash->{$seqname} }
              );
        }
    }

    my @gcfeat          = sort { $a cmp $b } keys %{ $self->gc };
    my @gr_seqname      = @{ $self->seqname };
    my %gr_seqname_hash = map ( ( $_ => 1 ),
        grep ( !exists $self->seqdata->{$_},
            map ( keys( %{ $self->gr_($_) } ), keys %{ $self->gr } ) ) );
    push @gr_seqname, keys %gr_seqname_hash;

    # Loop over columns
    for ( my $col = 0 ; $col < $acols ; $col += $colstep ) {

lib/Bio/App/SELEX/Stockholm.pm  view on Meta::CPAN


=head2 gr

    my $gr = $stock->gr->{FEATURE}->{SEQNAME};
    my $gr = $stock->gr_FEATURE->{SEQNAME};

Returns the line beginning '#=GR SEQNAME FEATURE ...'

=cut


# catch all methods by default
sub AUTOLOAD {
    my ($self, @args) = @_;
    my $sub = our $AUTOLOAD;
    $sub =~ s/.*:://;

    # check for DESTROY
    return if $sub eq "DESTROY";

    # check for GF, GC, GS, GR tag_feature accessors
    # e.g. $self->GF_ID
    # can also use $self->GF_('ID')
    if ($sub =~ /^(gf|gc|gs|gr)_(\S*)$/i) {
	my ($tag, $feature) = ($1, $2);
	$tag = lc $tag;
	$feature = shift(@args) unless length $feature;
	my $hash = $self->{$tag};
	if (@args) {
	    $hash->{$feature} = shift(@args);   # TODO: check ref-type of arg
	}
	cluck "Warning: ignoring extra arguments to ${tag}_$feature"
	    if @args > 0;
	if (!defined $hash->{$feature}) {
	    $hash->{$feature} = 
		$tag eq "gf" ? [] :
		$tag eq "gc" ? "" :
		$tag eq "gs" ? {} :
		$tag eq "gr" ? {} :
		croak "Unreachable";
	}
	return $hash->{$feature};
    }

    # check for ordinary accessors
    if (exists $self->{$sub}) {
	croak "Usage: $sub() or $sub(newValue)" if @args > 1;
	return
	    @args
	    ? $self->{$sub} = $args[0]
	    : $self->{$sub};
    }

    # croak
    croak "Unsupported method: $sub";
}


# pretty print line(s)
sub prettify {
    my ($self, $lcols, $legend, @data) = @_;
    # This horribly inefficient/redundant series of transformations comes out with something I like (IH, 7/24/07)
    # Trim it down? pah! Like I have nothing better to do
    $legend = sprintf ("% ${lcols}s", $legend);
    $legend =~ s/^(\s+)(\#=\S\S)(\s+\S+)$/$2$1$3/;
    $legend =~ s/^(\s+)(\#=\S\S\s+\S+)(\s+\S+)$/$2$1$3/;
    $legend =~ s/^(\s\s\s\s\s)(\s+)([^\#]\S+)/$1$3$2/;
    return map ("$legend $_", @data);
    # (pukes into cold coffee cup)
}

# legend width (subtract this from maxcols-1 to get number of columns available for sequence display)
sub lcols {
    my ($self) = @_;
    my $lcols = max ($self->maxNameLen,
		     map(length("#=GF $_"), keys(%{$self->gf})),
		     map(length("#=GC $_"), keys(%{$self->gc})));
    while (my ($gr_key, $gr_hash) = each %{$self->gr}) {
	$lcols = max ($lcols, map(length("#=GR $gr_key $_"), keys(%$gr_hash)));
    }
    while (my ($gs_key, $gs_hash) = each %{$self->gs}) {
	$lcols = max ($lcols, map(length("#=GS $gs_key $_"), keys(%$gs_hash)));
    }
    return $lcols;
}

# safer version of substr (doesn't complain if startpoint outside of string)
sub safe_substr {
    my ($string, $start, $len) = @_;
    return "" if !defined($string) || $start > length $string;
    if (defined $len) {
      return substr ($string, $start, $len);
    } else {
      return substr ($string, $start);  # print from $start to end if no length specified
    }
}

=head2 add_gf

    $stock->add_gf (FEATURE, $line)
    $stock->add_gf (FEATURE, $line1, $line2, ...)
    $stock->add_gf (FEATURE, @lines)
    $stock->add_gf (FEATURE, "$line1\n$line2\n$...")

Add '#=GF FEATURE' annotation, preserving the order of the '#=GF' lines
(damn those crazy context-sensitive Stockholm semantics!)

Each list entry gets printed on its own line.

=cut

# Add #=GF annotation, preserving the order of the #=GF lines
# (damn those crazy context-sensitive Stockholm semantics!)
#
# Usage:
#        $stock->add_gf ($gfFeature, $line);
#        $stock->add_gf ($gfFeature, $line1, $line2, ...);
#        $stock->add_gf ($gfFeature, @lines);
#        $stock->add_gf ($gfFeature, "$line1\n$line2\n$...");
#
# Each list entry gets printed on its own line.
#
sub add_gf {
    my ($self, $feature, @data) = @_;
    unless (@data > 0) {
	carp "Missing parameters to 'add_gf'; nothing will be done";
	return;
    }

    foreach my $line (map {$_ eq '' ? '' : split ("\n", $_, -1)} @data) {
	push @{$self->gf_($feature)}, $line;
	push @{$self->gfOrder}, $feature;



( run in 1.224 second using v1.01-cache-2.11-cpan-f889d44b568 )