]> git.donarmstrong.com Git - biopieces.git/blob - code_ruby/lib/maasha/locator.rb
refactoring of ruby code converting sequences types to symbols
[biopieces.git] / code_ruby / lib / maasha / locator.rb
1 # Copyright (C) 2007-2011 Martin A. Hansen.
2
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17 # http://www.gnu.org/copyleft/gpl.html
18
19 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
20
21 # This software is part of the Biopieces framework (www.biopieces.org).
22
23 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
24
25 require 'maasha/seq'
26
27 # Error class for all exceptions to do with Genbank/EMBL/DDBJ feature table locators.
28 class LocatorError < StandardError; end
29
30 # Class that handles Genbank/EMBL/DDBJ feature table locators.
31 class Locator
32   attr_accessor :locator, :seq, :subseq
33
34   # Method to initialize a locator object.
35   def initialize(locator, seq)
36     @locator = locator
37     @seq     = seq
38     @subseq  = Seq.new(nil, "", :dna)
39     parse_locator(locator)
40   end
41
42   # Method that returns the strand (+ or - ) of the locator.
43   def strand
44     if @locator.match("complement")
45       return "-"
46     else
47       return "+"
48     end
49   end
50
51   # Method that returns the begin position of the locator (0-based).
52   def s_beg
53     if @locator =~ /(\d+)/
54       return $1.to_i - 1
55     end
56   end
57
58   # Method that returns the end position of the locator (0-based).
59   def s_end
60     if @locator.reverse =~ /(\d+)/
61       return $1.reverse.to_i - 1
62     end
63   end
64
65   private
66
67   # Method that uses recursion to parse a locator string from a feature table
68   # and fetches the appropriate subsequence. The operators join(), complement(),
69   # and order() are handled. The locator string is broken into a comma separated
70   # lists, and modified if the parens donnot balance. Otherwise the comma
71   # separated list of ranges are stripped from operators, and the subsequence
72   # are fetched and handled according to the operators. SNP locators are also 
73   # dealt with (single positions).
74   def parse_locator(locator, join = nil, comp = nil, order = nil)
75     intervals = locator.split(",")
76
77     unless balance_parens?(intervals.first)   # locator includes a join/comp/order of several ranges
78       case locator
79       when /^join\((.*)\)$/
80         locator = $1
81         join    = true
82       when /^complement\((.*)\)$/
83         locator = $1
84         comp    = true
85       when /^order\((.*)\)$/
86         locator = $1
87         order   = true
88       end
89
90       parse_locator(locator, join, comp, order)
91     else
92       intervals.each do |interval|
93         case interval
94         when /^join\((.*)\)$/
95           locator = $1
96           join    = true
97           parse_locator(locator, join, comp, order)
98         when /^complement\((.*)\)$/
99           locator = $1
100           comp    = true
101           parse_locator(locator, join, comp, order)
102         when /^order\((.*)\)$/
103           locator = $1
104           order   = true
105           parse_locator(locator, join, comp, order)
106         when /^[<>]?(\d+)[^\d]+(\d+)$/
107           int_beg = $1.to_i - 1
108           int_end = $2.to_i - 1
109
110           newseq = Seq.new(nil, @seq.seq[int_beg..int_end], :dna)
111
112                                         unless newseq.seq.nil?
113                                                 newseq.reverse!.complement! if comp
114
115                                                 @subseq.seq << (order ? " " + newseq.seq : newseq.seq)
116                                         end
117         when /^(\d+)$/
118           pos = $1.to_i - 1
119
120           newseq = Seq.new(nil, @seq.seq[pos], :dna)
121
122                                         unless newseq.seq.nil?
123                 newseq.reverse!.complement! if comp 
124
125                 @subseq.seq << (order ? " " + newseq.seq : newseq.seq)
126                                         end
127         else
128           $stderr.puts "WARNING: Could not match locator -> #{locator}";
129           @subseq.seq << ""
130         end
131       end
132     end
133
134     return @subseq
135   end
136
137   # Method that checks if the parans in a locater string balances.
138   def balance_parens?(locator)
139     parens = 0
140
141     locator.each_char do |char|
142       case char
143       when '(' then parens += 1
144       when ')' then parens -= 1
145       end
146     end
147
148     if parens == 0
149       return true
150     else
151       return false
152     end
153   end
154 end
155
156
157 __END__
158