Class | Bio::RestrictionEnzyme::Analysis
In: | lib/bio/util/restriction_enzyme/analysis.rb lib/bio/util/restriction_enzyme/analysis_basic.rb
Parent: | Object

### Methods

create_enzyme_actions cut cut cut_and_return_by_permutations cut_without_permutations cut_without_permutations find_match_locations fragments_for_display permute

### Public Class methods

cut( sequence, *args )

See cut instance method

[Source]

        # File lib/bio/util/restriction_enzyme/analysis.rb, line 20
    20:   def self.cut( sequence, *args )
    21:     self.new.cut( sequence, *args )
    22:   end

cut_without_permutations( sequence, *args )

See cut_without_permutations instance method

[Source]

        # File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 20
    20:   def self.cut_without_permutations( sequence, *args )
    21:     self.new.cut_without_permutations( sequence, *args )
    22:   end

### Public Instance methods

cut( sequence, *args )

See main documentation for Bio::RestrictionEnzyme

`cut` takes into account permutations of cut variations based on competitiveness of enzymes for an enzyme cutsite or enzyme bindsite on a sequence.

Example:

FIXME add output

      Bio::RestrictionEnzyme::Analysis.cut('gaattc', 'EcoRI')

_same as:_

      Bio::RestrictionEnzyme::Analysis.cut('gaattc', 'g^aattc')

Arguments

- `sequence`: `String` kind of object that will be used as a nucleic acid sequence.
- `args`: Series of enzyme names, enzymes sequences with cut marks, or RestrictionEnzyme objects.

Returns: | Bio::RestrictionEnzyme::Fragments object populated with Bio::RestrictionEnzyme::Fragment objects. (Note: unrelated to Bio::RestrictionEnzyme::Range::SequenceRange::Fragments) or a `Symbol` containing an error code

[Source]

        # File lib/bio/util/restriction_enzyme/analysis.rb, line 45
    45:   def cut( sequence, *args )
    46:     view_ranges = false
    47:
    48:     args.select { |i| i.class == Hash }.each do |hsh|
    49:       hsh.each do |key, value|
    50:         if key == :view_ranges
    51:           unless ( value.kind_of?(TrueClass) or value.kind_of?(FalseClass) )
    52:             raise ArgumentError, "view_ranges must be set to true or false, currently #{value.inspect}."
    53:           end
    54:           view_ranges = value
    55:         end
    56:       end
    57:     end
    58:
    59:     res = cut_and_return_by_permutations( sequence, *args )
    60:     return res if res.class == Symbol
    61:     # Format the fragments for the user
    62:     fragments_for_display( res, view_ranges )
    63:   end

cut_without_permutations( sequence, *args )

See main documentation for Bio::RestrictionEnzyme

Bio::RestrictionEnzyme.cut is preferred over this!

USE AT YOUR OWN RISK

This is a simpler version of method `cut`. `cut` takes into account permutations of cut variations based on competitiveness of enzymes for an enzyme cutsite or enzyme bindsite on a sequence. This does not take into account those possibilities and is therefore faster, but less likely to be accurate.

This code is mainly included as an academic example without having to wade through the extra layer of complexity added by the permutations.

Example:

FIXME add output

      Bio::RestrictionEnzyme::Analysis.cut_without_permutations('gaattc', 'EcoRI')

_same as:_

      Bio::RestrictionEnzyme::Analysis.cut_without_permutations('gaattc', 'g^aattc')

Arguments

- `sequence`: `String` kind of object that will be used as a nucleic acid sequence.
- `args`: Series of enzyme names, enzymes sequences with cut marks, or RestrictionEnzyme objects.

Returns: | Bio::RestrictionEnzyme::Fragments object populated with Bio::RestrictionEnzyme::Fragment objects. (Note: unrelated to Bio::RestrictionEnzyme::Range::SequenceRange::Fragments)

[Source]

        # File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 54
    54:   def cut_without_permutations( sequence, *args )
    55:     return fragments_for_display( {} ) if !sequence.kind_of?(String) or sequence.empty?
    56:     sequence = Bio::Sequence::NA.new( sequence )
    57:
    58:     # create_enzyme_actions returns two seperate array elements, they're not
    59:     # needed separated here so we put them into one array
    60:     enzyme_actions = create_enzyme_actions( sequence, *args ).flatten
    61:     return fragments_for_display( {} ) if enzyme_actions.empty?
    62:
    63:     # Primary and complement strands are both measured from '0' to 'sequence.size-1' here
    64:     sequence_range = Bio::RestrictionEnzyme::Range::SequenceRange.new( 0, 0, sequence.size-1, sequence.size-1 )
    65:
    66:     # Add the cuts to the sequence_range from each enzyme_action
    67:     enzyme_actions.each do |enzyme_action|
    68:       enzyme_action.cut_ranges.each do |cut_range|
    69:         sequence_range.add_cut_range(cut_range)
    70:       end
    71:     end
    72:
    73:     # Fill in the source sequence for sequence_range so it knows what bases
    74:     # to use
    75:     sequence_range.fragments.primary = sequence
    76:     sequence_range.fragments.complement = sequence.forward_complement
    77:
    78:     # Format the fragments for the user
    79:     fragments_for_display( {0 => sequence_range} )
    80:   end

### Protected Instance methods

create_enzyme_actions( sequence, *args )

Creates an array of EnzymeActions based on the DNA sequence and supplied enzymes.

Arguments

- `sequence`: The string of DNA to match the enzyme recognition sites against
- `args`:: The enzymes to use.

Returns: | `Array` with the first element being an array of EnzymeAction objects that `sometimes_cut`, and are subject to competition. The second is an array of EnzymeAction objects that `always_cut` and are not subject to competition.

[Source]

         # File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 119
    119:   def create_enzyme_actions( sequence, *args )
    120:     all_enzyme_actions = []
    121:
    122:     args.each do |enzyme|
    123:       enzyme = Bio::RestrictionEnzyme.new(enzyme) unless enzyme.class == Bio::RestrictionEnzyme::DoubleStranded
    124:
    125:       # make sure pattern is the proper size
    126:       # for more info see the internal documentation of
    127:       # Bio::RestrictionEnzyme::DoubleStranded.create_action_at
    128:       pattern = Bio::Sequence::NA.new(
    129:         Bio::RestrictionEnzyme::DoubleStranded::AlignedStrands.align(
    130:           enzyme.primary, enzyme.complement
    131:         ).primary
    132:       ).to_re
    133:
    134:       find_match_locations( sequence, pattern ).each do |offset|
    135:         all_enzyme_actions << enzyme.create_action_at( offset )
    136:       end
    137:     end
    138:
    139:     # FIXME VerticalCutRange should really be called VerticalAndHorizontalCutRange
    140:
    141:     # * all_enzyme_actions is now full of EnzymeActions at specific locations across
    142:     #   the sequence.
    143:     # * all_enzyme_actions will now be examined to see if any EnzymeActions may
    144:     #   conflict with one another, and if they do they'll be made note of in
    145:     #   indicies_of_sometimes_cut.  They will then be remove FIXME
    146:     # * a conflict occurs if another enzyme's bind site is compromised do due
    147:     #   to another enzyme's cut.  Enzyme's bind sites may overlap and not be
    148:     #   competitive, however neither bind site may be part of the other
    149:     #   enzyme's cut or else they do become competitive.
    150:     #
    151:     # Take current EnzymeAction's entire bind site and compare it to all other
    152:     # EzymeAction's cut ranges.  Only look for vertical cuts as boundaries
    153:     # since trailing horizontal cuts would have no influence on the bind site.
    154:     #
    155:     # If example Enzyme A makes this cut pattern (cut range 2..5):
    156:     #
    157:     # 0 1 2|3 4 5 6 7
    158:     #      +-----+
    159:     # 0 1 2 3 4 5|6 7
    160:     #
    161:     # Then the bind site (and EnzymeAction range) for Enzyme B would need it's
    162:     # right side to be at index 2 or less, or it's left side to be 6 or greater.
    163:
    164:     competition_indexes = Set.new
    165:
    166:     all_enzyme_actions[0..-2].each_with_index do |current_enzyme_action, i|
    167:       next if competition_indexes.include? i
    168:       next if current_enzyme_action.cut_ranges.empty?  # no cuts, some enzymes are like this (ex. CjuI)
    169:
    170:       all_enzyme_actions[i+1..-1].each_with_index do |comparison_enzyme_action, j|
    171:         j += (i + 1)
    172:         next if competition_indexes.include? j
    173:         next if comparison_enzyme_action.cut_ranges.empty?  # no cuts
    174:
    175:         if (current_enzyme_action.right <= comparison_enzyme_action.cut_ranges.min_vertical) or
    176:            (current_enzyme_action.left > comparison_enzyme_action.cut_ranges.max_vertical)
    177:           # no conflict
    178:         else
    179:           competition_indexes += [i, j] # merge both indexes into the flat set
    180:         end
    181:       end
    182:     end
    183:
    184:     sometimes_cut = all_enzyme_actions.values_at( *competition_indexes )
    185:     always_cut = all_enzyme_actions
    186:     always_cut.delete_if {|x| sometimes_cut.include? x }
    187:
    188:     [sometimes_cut, always_cut]
    189:   end

cut_and_return_by_permutations( sequence, *args )

See cut instance method

Arguments

- `sequence`: `String` kind of object that will be used as a nucleic acid sequence.
- `args`: Series of enzyme names, enzymes sequences with cut marks, or RestrictionEnzyme objects.

May also supply a `Hash` with the key ":max_permutations" to specificy how many permutations are allowed - a value of 0 indicates no permutations are allowed.

Returns: | `Hash` Keys are a permutation ID, values are SequenceRange objects that have cuts applied.

also may return the `Symbol` ’:sequence_empty’, ’:no_cuts_found’, or ’:too_many_permutations‘

[Source]

         # File lib/bio/util/restriction_enzyme/analysis.rb, line 78
     78:   def cut_and_return_by_permutations( sequence, *args )
     79:     my_hash = {}
     80:     maximum_permutations = nil
     81:
     82:     hashes_in_args = args.select { |i| i.class == Hash }
     83:     args.delete_if { |i| i.class == Hash }
     84:     hashes_in_args.each do |hsh|
     85:       hsh.each do |key, value|
     86:         case key
     87:         when :max_permutations, 'max_permutations', :maximum_permutations, 'maximum_permutations'
     88:           maximum_permutations = value.to_i unless value == nil
     89:         when :view_ranges
     90:         else
     91:           raise ArgumentError, "Received key #{key.inspect} in argument - I only know the key ':max_permutations' and ':view_ranges' currently.  Hash passed: #{hsh.inspect}"
     92:         end
     93:       end
     94:     end
     95:
     96:     if !sequence.kind_of?(String) or sequence.empty?
     97:       logger.warn "The supplied sequence is empty." if defined?(logger)
     98:       return :sequence_empty
     99:     end
    100:     sequence = Bio::Sequence::NA.new( sequence )
    101:
    102:     enzyme_actions, initial_cuts = create_enzyme_actions( sequence, *args )
    103:
    104:     if enzyme_actions.empty? and initial_cuts.empty?
    105:       logger.warn "This enzyme does not make any cuts on this sequence." if defined?(logger)
    106:       return :no_cuts_found
    107:     end
    108:
    109:     # * When enzyme_actions.size is equal to '1' that means there are no permutations.
    110:     # * If enzyme_actions.size is equal to '2' there is one
    111:     #   permutation ("[0, 1]")
    112:     # * If enzyme_actions.size is equal to '3' there are two
    113:     #   permutations ("[0, 1, 2]")
    114:     # * and so on..
    115:     if maximum_permutations and enzyme_actions.size > 1
    116:       if (enzyme_actions.size - 1) > maximum_permutations.to_i
    117:         logger.warn "More permutations than maximum, skipping.  Found: #{enzyme_actions.size-1}  Max: #{maximum_permutations.to_i}" if defined?(logger)
    118:         return :too_many_permutations
    119:       end
    120:     end
    121:
    122:     if enzyme_actions.size > 1
    123:       permutations = permute(enzyme_actions.size)
    124:
    125:       permutations.each do |permutation|
    126:         previous_cut_ranges = []
    127:         # Primary and complement strands are both measured from '0' to 'sequence.size-1' here
    128:         sequence_range = Bio::RestrictionEnzyme::Range::SequenceRange.new( 0, 0, sequence.size-1, sequence.size-1 )
    129:
    130:         # Add the cuts to the sequence_range from each enzyme_action contained
    131:         # in initial_cuts.  These are the cuts that have no competition so are
    132:         # not subject to permutations.
    133:         initial_cuts.each do |enzyme_action|
    134:           enzyme_action.cut_ranges.each do |cut_range|
    135:             sequence_range.add_cut_range(cut_range)
    136:           end
    137:         end
    138:
    139:         permutation.each do |id|
    140:           enzyme_action = enzyme_actions[id]
    141:
    142:           # conflict is false if the current enzyme action may cut in it's range.
    143:           # conflict is true if it cannot due to a previous enzyme action making
    144:           # a cut where this enzyme action needs a whole recognition site.
    145:           conflict = false
    146:
    147:           # If current size of enzyme_action overlaps with previous cut_range, don't cut
    148:           # note that the enzyme action may fall in the middle of a previous enzyme action
    149:           # so all cut locations must be checked that would fall underneath.
    150:           previous_cut_ranges.each do |cut_range|
    151:             next unless cut_range.class == Bio::RestrictionEnzyme::Range::VerticalCutRange  # we aren't concerned with horizontal cuts
    152:             previous_cut_left = cut_range.range.first
    153:             previous_cut_right = cut_range.range.last
    154:
    155:             # Keep in mind:
    156:             # * The cut location is to the immediate right of the base located at the index.
    157:             #   ex: at^gc -- the cut location is at index 1
    158:             # * The enzyme action location is located at the base of the index.
    159:             #   ex: atgc -- 0 => 'a', 1 => 't', 2 => 'g', 3 => 'c'
    160:             # method create_enzyme_actions has similar commentary if interested
    161:             if (enzyme_action.right <= previous_cut_left) or
    162:                (enzyme_action.left > previous_cut_right) or
    163:                (enzyme_action.left > previous_cut_left and enzyme_action.right <= previous_cut_right) # in between cuts
    164:               # no conflict
    165:             else
    166:               conflict = true
    167:             end
    168:           end
    169:
    170:           next if conflict == true
    171:           enzyme_action.cut_ranges.each { |cut_range| sequence_range.add_cut_range(cut_range) }
    172:           previous_cut_ranges += enzyme_action.cut_ranges
    173:         end # permutation.each
    174:
    175:         # Fill in the source sequence for sequence_range so it knows what bases
    176:         # to use
    177:         sequence_range.fragments.primary = sequence
    178:         sequence_range.fragments.complement = sequence.forward_complement
    179:         my_hash[permutation] = sequence_range
    180:       end # permutations.each
    181:
    182:     else # if enzyme_actions.size == 1
    183:       # no permutations, just do it
    184:       sequence_range = Bio::RestrictionEnzyme::Range::SequenceRange.new( 0, 0, sequence.size-1, sequence.size-1 )
    185:       initial_cuts.each { |enzyme_action| enzyme_action.cut_ranges.each { |cut_range| sequence_range.add_cut_range(cut_range) } }
    186:       sequence_range.fragments.primary = sequence
    187:       sequence_range.fragments.complement = sequence.forward_complement
    188:       my_hash[0] = sequence_range
    189:     end
    190:
    191:     my_hash
    192:   end

find_match_locations( string, re )

Returns an `Array` of the match indicies of a `RegExp` to a string.

Example:

      find_match_locations('abccdefeg', /[ce]/) # => [2,3,5,7]

Arguments

- `string`: The string to scan
- `re`: A RegExp to use

Returns: | `Array` with indicies of match locations

[Source]

         # File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 202
    202:   def find_match_locations( string, re )
    203:     md = string.match( re )
    204:     locations = []
    205:     counter = 0
    206:     while md
    207:       # save the match index relative to the original string
    208:       locations << (counter += md.begin(0))
    209:       # find the next match
    210:       md = string[ (counter += 1)..-1 ].match( re )
    211:     end
    212:     locations
    213:   end

fragments_for_display( hsh, view_ranges=false )

Take the fragments from SequenceRange objects generated from add_cut_range and return unique results as a Bio::RestrictionEnzyme::Analysis::Fragment object.

Arguments

- `hsh`: `Hash` Keys are a permutation ID, if any. Values are SequenceRange objects that have cuts applied.

Returns: | Bio::RestrictionEnzyme::Analysis::Fragments object populated with Bio::RestrictionEnzyme::Analysis::Fragment objects.

[Source]

         # File lib/bio/util/restriction_enzyme/analysis_basic.rb, line 93
     93:   def fragments_for_display( hsh, view_ranges=false )
     94:     ary = Fragments.new
     95:     return ary unless hsh
     96:
     97:     hsh.each do |permutation_id, sequence_range|
     98:       sequence_range.fragments.for_display.each do |fragment|
     99:         if view_ranges
    100:           ary << Bio::RestrictionEnzyme::Fragment.new(fragment.primary, fragment.complement, fragment.p_left, fragment.p_right, fragment.c_left, fragment.c_right)
    101:         else
    102:           ary << Bio::RestrictionEnzyme::Fragment.new(fragment.primary, fragment.complement)
    103:         end
    104:       end
    105:     end
    106:
    107:     ary.uniq! unless view_ranges
    108:
    109:     ary
    110:   end

permute(count, permutations = [[0]])

Returns permutation orders for a given number of elements.

Examples:

      permute(0) # => [[0]]
      permute(1) # => [[0]]
      permute(2) # => [[1, 0], [0, 1]]
      permute(3) # => [[2, 1, 0], [2, 0, 1], [1, 2, 0], [0, 2, 1], [1, 0, 2], [0, 1, 2]]
      permute(4) # => [[3, 2, 1, 0],
                       [3, 2, 0, 1],
                       [3, 1, 2, 0],
                       [3, 0, 2, 1],
                       [3, 1, 0, 2],
                       [3, 0, 1, 2],
                       [2, 3, 1, 0],
                       [2, 3, 0, 1],
                       [1, 3, 2, 0],
                       [0, 3, 2, 1],
                       [1, 3, 0, 2],
                       [0, 3, 1, 2],
                       [2, 1, 3, 0],
                       [2, 0, 3, 1],
                       [1, 2, 3, 0],
                       [0, 2, 3, 1],
                       [1, 0, 3, 2],
                       [0, 1, 3, 2],
                       [2, 1, 0, 3],
                       [2, 0, 1, 3],
                       [1, 2, 0, 3],
                       [0, 2, 1, 3],
                       [1, 0, 2, 3],
                       [0, 1, 2, 3]]

Arguments

- `count`: `Number` of different elements to be permuted
- `permutations`: ignore - for the recursive algorithm

Returns: | `Array` of `Array` objects with different possible permutation orders. See examples.

[Source]

         # File lib/bio/util/restriction_enzyme/analysis.rb, line 232
    232:   def permute(count, permutations = [[0]])
    233:     return permutations if count <= 1
    234:     new_arrays = []
    235:     new_array = []
    236:
    237:     (permutations[0].size + 1).times do |n|
    238:       new_array.clear
    239:       permutations.each { |a| new_array << a.dup }
    240:       new_array.each { |e| e.insert(n, permutations[0].size) }
    241:       new_arrays += new_array
    242:     end
    243:
    244:     permute(count-1, new_arrays)
    245:   end

[Validate]