-
-# Error class for all exceptions to do with Genbank/EMBL/DDBJ feature table locators.
-class LocatorError < StandardError; end
-
-class Locator
- attr_accessor :locator, :seq, :subseq
-
- def initialize(locator, seq)
- @locator = locator
- @seq = seq
- @subseq = Seq.new(nil, "", "dna")
- parse_locator(locator)
- end
-
- def strand
- if @locator.match("complement")
- return "-"
- else
- return "+"
- end
- end
-
- def s_beg
- if @locator =~ /(\d+)/
- return $1.to_i - 1
- end
- end
-
- def s_end
- if @locator.reverse =~ /(\d+)/
- return $1.reverse.to_i - 1
- end
- end
-
- private
-
- # Method that uses recursion to parse a locator string from a feature
- # table and fetches the appropriate subsequence. the operators
- # join(), complement(), and order() are handled.
- # the locator string is broken into a comma separated lists, and
- # modified if the parens donnot balance. otherwise the comma separated
- # list of ranges are stripped from operators, and the subsequence are
- # fetched and handled according to the operators.
- # SNP locators are also dealt with (single positions).
- def parse_locator(locator, join = nil, comp = nil, order = nil)
- intervals = locator.split(",")
-
- unless balance_parens?(intervals.first) # locator includes a join/comp/order of several ranges
- case locator
- when /^join\((.*)\)$/
- locator = $1
- join = true
- when /^complement\((.*)\)$/
- locator = $1
- comp = true
- when /^order\((.*)\)$/
- locator = $1
- order = true
- end
-
- parse_locator(locator, join, comp, order)
- else
- intervals.each do |interval|
- case interval
- when /^join\((.*)\)$/
- locator = $1
- join = true
- parse_locator(locator, join, comp, order)
- when /^complement\((.*)\)$/
- locator = $1
- comp = true
- parse_locator(locator, join, comp, order)
- when /^order\((.*)\)$/
- locator = $1
- order = true
- parse_locator(locator, join, comp, order)
- when /^[<>]?(\d+)[^\d]+(\d+)$/
- int_beg = $1.to_i - 1
- int_end = $2.to_i - 1
-
- newseq = Seq.new(nil, @seq.seq[int_beg...int_end], "dna")
-
- unless newseq.seq.nil?
- newseq.revcomp if comp
-
- @subseq.seq << (order ? " " + newseq.seq : newseq.seq)
- end
- when /^(\d+)$/
- pos = $1.to_i - 1
-
- newseq = Seq.new(nil, @seq.seq[pos], "dna")
-
- unless newseq.seq.nil?
- newseq.revcomp if comp
-
- @subseq.seq << (order ? " " + newseq.seq : newseq.seq)
- end
- else
- $stderr.puts "WARNING: Could not match locator -> #{locator}";
- @subseq.seq << ""
- end
- end
- end
-
- return @subseq
- end
-
- def balance_parens?(locator)
- parens = 0
-
- locator.each_char do |char|
- case char
- when '(' then parens += 1
- when ')' then parens -= 1
- end
- end
-
- if parens == 0
- return true
- else
- return false
- end
- end
-end
-
-