lib/scaffolder/region.rb in scaffolder-0.2.6 vs lib/scaffolder/region.rb in scaffolder-0.4.0
- old
+ new
@@ -1,138 +1,276 @@
-Scaffolder::Region = Struct.new(:entry_type,:sequence)
+require 'scaffolder'
+
+class Scaffolder::Region
+ include Scaffolder::Errors
+
+ class << self
+ include Scaffolder::Errors
+
+ # @return [Scaffolder::Region] Returns subclassed instances of
+ # Scaffolder::Region by name
+ def [](type)
+ self.const_get(type.capitalize)
+ end
+
+ # Links the specification of values in the scaffold file to the assignment
+ # of instance variables.
+ #
+ # @param [Symbol] Define attributes for this type of scaffold
+ # region. Attributes are read from the scaffold file and stored as
+ # instance variables.
+ # @param [Hash] options Attribute options.
+ # @option options [Object,Proc] Default Specify a default value for this
+ # attribute if a value is not defined in the scaffold file.
+ # @example Simple specification
+ # class MyRegion < Scaffolder::Region
+ # attribute :value # "value" usable as a keyword in the scaffold file
+ # end
+ # @example Specification with a default value
+ # attribute :value, :default => 1
+ # @example Specification with where proc is evaluated for the default
+ # attribute :value, :default => lamdba{ Time.now.to_s }
+ # @example Specification with proc where the region instance is avaiable
+ # attribute :value, :default => lamdba{|s| s.other_variable + 1 }
+ def attribute(name,options = {})
+ define_method(name) do |*arg|
+ var = "@#{name}"
+ default = options[:default]
+ unless arg.first # Is an argument is passed to the method?
+ value = instance_variable_get(var)
+ return value if value
+ return default.respond_to?(:call) ? default.call(self) : default
+ end
+ instance_variable_set(var,arg.first)
+ end
+ end
+
+ # Parse each key-value pair in the scaffold hash calling the corresponding
+ # attribute method for the key and passing the value as an argument.
+ #
+ # @param [Hash] region_data Key-Value pairs of the data required to define
+ # this scaffolder region.
+ # @return [Scaffolder::Region] Returns an region object where the
+ # instance variables have been assigned according to the region data
+ # hash.
+ # @raise [UnknownAttributeError] If a keyword in the scaffold file does not
+ # have a corresponding attribute in the class.
+ # @see Scaffolder::Region.attribute
+ def generate(region_data)
+ region = self.new
+ region_data.each_pair do |attribute,value|
+ begin
+ region.send(attribute.to_sym,value)
+ rescue NoMethodError => e
+ raise UnknownAttributeError.new(e)
+ end
+ end
+ region
+ end
+
+ end
+
+ # The raw sequence for this region.
+ #
+ # @param [String]
+ # @return [String]
+ attribute :raw_sequence
+
+ # Trim the start of sequence to this position. Default is 1.
+ #
+ # @param [Interger]
+ # @return [Interger]
+ attribute :start, :default => 1
+
+ # Trim the end of sequence to this position. Default is the sequence length..
+ #
+ # @param [Interger]
+ # @return [Interger]
+ attribute :stop, :default => lambda{|s| s.sequence_hook.length}
+
+
+ # Should the sequence be reverse complemented. Reverse complementation is
+ # performed after the start and end of the sequence has been trimmed.
+ #
+ # @param [Boolean]
+ # @return [Boolean]
+ attribute :reverse
+
+ # Override this to manipulate the sequence before it's subsequenced, reverse
+ # complemented etc. by Scaffolder::Region#sequence.
+ #
+ # @return [String] The value of the raw_sequence attribute
+ # @see Scaffolder::Region#sequence
+ def sequence_hook
+ raw_sequence
+ end
+
+ # The name of the class. Useful for selecting specific region types.
+ #
+ # @return [Symbol]
+ def entry_type
+ self.class.name.split('::').last.downcase.to_sym
+ end
+
+ # Returns the value of the Scaffolder::Region#raw_sequence after
+ # subsequencing and reverse complementation (if specified in the
+ # scaffold file).
+ #
+ # @return [String] Sequence after all modifications
+ # @raise [CoordinateError] if the start position is less than 1.
+ # @raise [CoordinateError] if the stop position is greater than the sequence
+ # length.
+ # @raise [CoordinateError] if the start position is greater than the stop
+ # position.
+ def sequence
+ seq = sequence_hook
+
+ raise CoordinateError.new if start < 1
+ raise CoordinateError.new if stop > seq.length
+ raise CoordinateError.new if start > stop
+
+ seq = seq[(start-1)..(stop-1)]
+ seq = Bio::Sequence::NA.new(seq).reverse_complement if reverse
+ seq.to_s.upcase
+ end
+
+ require 'scaffolder/region/unresolved'
+ require 'scaffolder/region/insert'
+ require 'scaffolder/region/sequence'
+end