scaffolder 0.2.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/scaffolder.rb CHANGED
@@ -1,51 +1,215 @@
1
1
  require 'delegate'
2
2
  require 'bio'
3
3
 
4
+ # == Quick start
5
+ #
6
+ # Given a fasta file containing two sequences.
7
+ #
8
+ # >seqA
9
+ # GCGCGC
10
+ # >seqB
11
+ # ATATAT
12
+ #
13
+ # A simple genome scaffold containing the two sequences is specified as a YAML
14
+ # formatted text file shown below. Each dash (-) indicates a region in the
15
+ # scaffold. In the example below the keyword *sequence* inserts a sequence from
16
+ # the fasta file, the keyword *source* identifies that seqA should be used.
17
+ #
18
+ # ---
19
+ # - sequence:
20
+ # source: 'seqA'
21
+ # - sequence:
22
+ # source: 'seqB'
23
+ #
24
+ # The scaffolder API can then be used as follows to generate a complete
25
+ # sequence.
26
+ #
27
+ # scaffold = Scaffolder.new('scaffold.yml','sequences.fasta')
28
+ # sequence = scaffold.inject(String.new) do |build,entry|
29
+ # build << entry.sequence
30
+ # end
31
+ # puts sequence # Prints GCGCGCATATAT
32
+ #
33
+ # == The Scaffold File
34
+ #
35
+ # The above example is simplified to demonstrates basic usage. The sections
36
+ # below outline the types of regions that can be used in the scaffold file.
37
+ #
38
+ # === Sequence Regions
39
+ #
40
+ # Contigs sequences in the scaffold are specified using the *sequence* keyword.
41
+ # The *source* keyword should specifies the sequence to use from the fasta file
42
+ # and should match the first space delimited word in the fasta header.
43
+ #
44
+ # ==== Sub-Sequences
45
+ #
46
+ # When generating a scaffolder only a subset of a sequence may be required.
47
+ # Inserting sub-sequences into the scaffold is specified using the *start* and
48
+ # *stop* keywords. All of the sequence before the start coordinate is ignored
49
+ # and all of sequence after the stop coordinate is ignored, meaning only the
50
+ # sequence between the start and stop position inclusively is used in the
51
+ # scaffold.
52
+ #
53
+ # ---
54
+ # - sequence:
55
+ # source: 'sequence1'
56
+ # start: 42
57
+ # stop: 1764
58
+ #
59
+ # ==== Reverse Complementation
60
+ #
61
+ # The *reverse* keyword specifies that the selected sequence is reversed
62
+ # complemented.
63
+ #
64
+ # ---
65
+ # - sequence:
66
+ # source: 'sequence1'
67
+ # reverse: true
68
+ #
69
+ # === Insert Regions
70
+ #
71
+ # Sequence contigs may contain gaps, for example where the sequence could not
72
+ # be correctly resolved during assembly. Additional sequencing may however
73
+ # produce sequences that can be used to fill these gaps. These inserts can be
74
+ # added to a sequence using the *insert* keyword and specifying a YAML array of
75
+ # the inserts. Multiple inserts can be specified, each separated by a dash (-)
76
+ # followed by a new line.
77
+ #
78
+ # ---
79
+ # - sequence:
80
+ # source: 'sequence1'
81
+ # inserts:
82
+ # -
83
+ # source: 'insert1'
84
+ # open: 3
85
+ # close: 10
86
+ #
87
+ # ==== Insert Position
88
+ #
89
+ # The location where an insert is added to a sequence is defined by either the
90
+ # *open*, *close* keywords, or both. This defines where the host sequence is
91
+ # 'opened' and 'closed' to add the insert. If only one parameter is used, for
92
+ # example using *open*, then the close position is determined from the length
93
+ # of the insert sequence and vice versa.
94
+ #
95
+ # ==== Insert Sub-Sequence
96
+ #
97
+ # An insert can be subsequenced in the same way as a sequence using the *start*
98
+ # and *stop* keywords. Similarly the insert sequence can be reverse completed
99
+ # using the *reverse* keyword.
100
+ #
101
+ # ---
102
+ # - sequence:
103
+ # source: 'sequence1'
104
+ # inserts:
105
+ # -
106
+ # source: 'insert1'
107
+ # open: 3
108
+ # close: 10
109
+ # start: 8
110
+ # stop: 16
111
+ # reverse: true
112
+ #
113
+ #
114
+ # === Unresolved Regions
115
+ #
116
+ # There may be regions in between sequences in the genome which are unknown but
117
+ # which the approximate length is. These can be specified in the scaffold file
118
+ # using the *unresolved* keyword. Unresolved regions are filled with 'N'
119
+ # nucleotide characters equal to the value specified by the *length* keyword.
120
+ #
121
+ # ---
122
+ # - unresolved:
123
+ # length: 10
124
+ #
125
+ # === Scaffold File Processing Order
126
+ #
127
+ # The scaffolder API processes the regions in YAML scaffold file as follows:
128
+ #
129
+ # * Each region in the scaffold in processed in the order specified in the
130
+ # scaffolder file.
131
+ # * If the region is a sequence and inserts are specified, the inserts are
132
+ # sorted by stop position, then processed from last to first. Each insert is
133
+ # processed as follows:
134
+ #
135
+ # * The insert is subsequenced if specified.
136
+ # * The insert is reverse complemented if specified.
137
+ # * The insert is added to each host sequence replacing the region of
138
+ # sequence specified by the open and close co-ordinates.
139
+ # * The host sequence stop position is extended by the difference in length
140
+ # that the insert sequence fills. For example if a 5 base pair insert fills
141
+ # a 4 base region, the host sequence stop position is increased by the
142
+ # difference: 1.
143
+ # * The region is subsequenced if specified.
144
+ # * The region is reverse complemented if specified.
145
+ #
146
+ # === WARNING
147
+ #
148
+ # Inserts with overlapping *open* and *close* regions in the same sequence will
149
+ # cause unexpected behaviour and should be avoided.
150
+ #
4
151
  class Scaffolder < DelegateClass(Array)
5
- autoload :Region, 'scaffolder/region'
6
- autoload :Insert, 'scaffolder/insert'
7
- autoload :Sequence, 'scaffolder/sequence'
152
+ require 'scaffolder/errors'
153
+ require 'scaffolder/region'
8
154
 
155
+ include Scaffolder::Errors
156
+
157
+ # Source is a reserved keyword. The 'source' keyword identifies the
158
+ # which corresponding fasta sequence should be retreived from the fasta
159
+ # file.
160
+ SOURCE = 'source'
161
+
162
+ # Raw_sequence is a reserved keyword. The 'raw_sequence' keyword points to
163
+ # the sequence from the fasta file identified by the 'source' keyword.
164
+ RAW_SEQUENCE = 'raw_sequence'
165
+
166
+ # @param [Hash] assembly Produced from loading the scaffold file using YAML.load
167
+ # @param [String] sequence Location of the fasta file corresponding to the
168
+ # scaffold sequences
169
+ # @return [Array] Returns an array of scaffold regions
170
+ # @example
171
+ # Scaffolder.new(YAML.load('scaffold.yml'),'sequences.fasta')
9
172
  def initialize(assembly,sequence)
10
- @sequences = Hash[ *Bio::FlatFile::auto(sequence).collect { |s|
173
+ sequences = Hash[ *Bio::FlatFile::auto(sequence).collect { |s|
11
174
  [s.definition.split.first,s.seq]
12
175
  }.flatten]
13
176
 
14
177
  super(assembly.map do |entry|
15
178
  type, data = entry.keys.first, entry.values.first
16
179
 
17
- case type
18
- when 'unresolved'
19
- Scaffolder::Region.new(:unresolved,'N'*data['length'])
20
- when 'sequence'
21
- sequence = Scaffolder::Sequence.new(
22
- :name => data['source'],
23
- :start => data['start'],
24
- :end => data['end'],
25
- :reverse => data['reverse'],
26
- :sequence => fetch_sequence(data['source'])
27
- )
28
- if data['inserts']
29
- sequence.add_inserts(data['inserts'].map do |insert|
30
- Scaffolder::Insert.new(
31
- :start => insert['start'],
32
- :stop => insert['stop'],
33
- :reverse => insert['reverse'],
34
- :sequence => fetch_sequence(insert['source'])
35
- )
36
- end)
37
- end
38
- sequence
39
- else
40
- raise ArgumentError.new("Unknown tag: #{type}")
41
- end
180
+ # Source is the only reserved keyword. Fetches sequence from fasta file.
181
+ data = Scaffolder.update_with_sequence(data,sequences)
182
+
183
+ Scaffolder::Region[type].generate(data)
42
184
  end)
43
185
  end
44
186
 
45
- def fetch_sequence(name)
46
- sequence = @sequences[name]
47
- raise ArgumentError.new("Missing sequence: #{name}") unless sequence
48
- sequence
187
+ # Inserts corresponding fasta data into scaffold data hash. Every hash
188
+ # that contains the reserved 'source' keyword has the 'raw_sequence' keyword
189
+ # added for the corresponding fasta sequence from the fasta file.
190
+ # @param [Hash] data The scaffold hash
191
+ # @param [Hash] seqs A hash with identifier => sequence key/value pairs from
192
+ # the fasta sequence data.
193
+ # @return [Hash] The data hash updated with the 'raw_sequence' sequence
194
+ # keyword data.
195
+ # @raise [UnkownSequenceError] if the source keyword is used but
196
+ # there is no corresponding fasta sequence entry
197
+ def self.update_with_sequence(data,seqs)
198
+ if data.instance_of? Array
199
+ data.each{|a| update_with_sequence(a,seqs) }
200
+ else
201
+ if data[SOURCE]
202
+ sequence = seqs[data[SOURCE]]
203
+ if sequence.nil?
204
+ raise UnknownSequenceError.new("Unknown sequence: #{data[SOURCE]}")
205
+ end
206
+ data.merge!({RAW_SEQUENCE => sequence})
207
+ end
208
+ data.select{|k,v| v.respond_to? :each}.each do |key,hash|
209
+ update_with_sequence(hash,seqs)
210
+ end
211
+ end
212
+ data
49
213
  end
50
214
 
51
215
  end
data/scaffolder.gemspec CHANGED
@@ -1,51 +1,60 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{scaffolder}
8
- s.version = "0.2.6"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Barton"]
12
- s.date = %q{2010-10-10}
13
- s.description = %q{Organise genome sequence data into scaffolds using YAML configuration files.}
12
+ s.date = %q{2011-01-04}
13
+ s.description = %q{Organise sequence contigs into genome scaffolds using simple human-readable YAML files.}
14
14
  s.email = %q{mail@michaelbarton.me.uk}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.rdoc"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "lib/scaffolder.rb",
27
- "lib/scaffolder/insert.rb",
28
- "lib/scaffolder/region.rb",
29
- "lib/scaffolder/sequence.rb",
30
- "scaffolder.gemspec",
31
- "test/data/sequences.fna",
32
- "test/helper.rb",
33
- "test/test_insert.rb",
34
- "test/test_region.rb",
35
- "test/test_scaffolder.rb",
36
- "test/test_sequence.rb"
21
+ "Gemfile",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "cucumber.yml",
27
+ "features/insert.feature",
28
+ "features/sequence.feature",
29
+ "features/step_definitions/scaffolder_steps.rb",
30
+ "features/support/env.rb",
31
+ "lib/scaffolder.rb",
32
+ "lib/scaffolder/errors.rb",
33
+ "lib/scaffolder/region.rb",
34
+ "lib/scaffolder/region/insert.rb",
35
+ "lib/scaffolder/region/sequence.rb",
36
+ "lib/scaffolder/region/unresolved.rb",
37
+ "scaffolder.gemspec",
38
+ "test/helper.rb",
39
+ "test/test_insert.rb",
40
+ "test/test_region.rb",
41
+ "test/test_scaffolder.rb",
42
+ "test/test_sequence.rb",
43
+ "test/test_unresolved.rb",
44
+ "yard/attribute_handler.rb"
37
45
  ]
38
- s.homepage = %q{http://github.com/michaelbarton/scaffolder}
39
- s.rdoc_options = ["--charset=UTF-8"]
46
+ s.homepage = %q{http://www.michaelbarton.me.uk/scaffolder/}
47
+ s.licenses = ["MIT"]
40
48
  s.require_paths = ["lib"]
41
49
  s.rubygems_version = %q{1.3.7}
42
- s.summary = %q{Scaffolder for genome sequence data}
50
+ s.summary = %q{Genome scaffolding for human beings.}
43
51
  s.test_files = [
44
52
  "test/helper.rb",
45
- "test/test_insert.rb",
46
- "test/test_region.rb",
47
- "test/test_scaffolder.rb",
48
- "test/test_sequence.rb"
53
+ "test/test_insert.rb",
54
+ "test/test_region.rb",
55
+ "test/test_scaffolder.rb",
56
+ "test/test_sequence.rb",
57
+ "test/test_unresolved.rb"
49
58
  ]
50
59
 
51
60
  if s.respond_to? :specification_version then
@@ -53,24 +62,33 @@ Gem::Specification.new do |s|
53
62
  s.specification_version = 3
54
63
 
55
64
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
- s.add_runtime_dependency(%q<bio>, [">= 0"])
57
- s.add_development_dependency(%q<rr>, [">= 0.10.11"])
58
- s.add_development_dependency(%q<shoulda>, [">= 0"])
59
- s.add_development_dependency(%q<redgreen>, [">= 0"])
60
- s.add_development_dependency(%q<yard>, [">= 0"])
65
+ s.add_runtime_dependency(%q<bio>, ["~> 1.4"])
66
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
67
+ s.add_development_dependency(%q<shoulda>, ["~> 2.11"])
68
+ s.add_development_dependency(%q<mocha>, ["~> 0.9"])
69
+ s.add_development_dependency(%q<yard>, ["~> 0.6"])
70
+ s.add_development_dependency(%q<cucumber>, ["~> 0.9"])
71
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5"])
72
+ s.add_development_dependency(%q<redgreen>, ["~> 1.2"])
61
73
  else
62
- s.add_dependency(%q<bio>, [">= 0"])
63
- s.add_dependency(%q<rr>, [">= 0.10.11"])
64
- s.add_dependency(%q<shoulda>, [">= 0"])
65
- s.add_dependency(%q<redgreen>, [">= 0"])
66
- s.add_dependency(%q<yard>, [">= 0"])
74
+ s.add_dependency(%q<bio>, ["~> 1.4"])
75
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
76
+ s.add_dependency(%q<shoulda>, ["~> 2.11"])
77
+ s.add_dependency(%q<mocha>, ["~> 0.9"])
78
+ s.add_dependency(%q<yard>, ["~> 0.6"])
79
+ s.add_dependency(%q<cucumber>, ["~> 0.9"])
80
+ s.add_dependency(%q<jeweler>, ["~> 1.5"])
81
+ s.add_dependency(%q<redgreen>, ["~> 1.2"])
67
82
  end
68
83
  else
69
- s.add_dependency(%q<bio>, [">= 0"])
70
- s.add_dependency(%q<rr>, [">= 0.10.11"])
71
- s.add_dependency(%q<shoulda>, [">= 0"])
72
- s.add_dependency(%q<redgreen>, [">= 0"])
73
- s.add_dependency(%q<yard>, [">= 0"])
84
+ s.add_dependency(%q<bio>, ["~> 1.4"])
85
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
86
+ s.add_dependency(%q<shoulda>, ["~> 2.11"])
87
+ s.add_dependency(%q<mocha>, ["~> 0.9"])
88
+ s.add_dependency(%q<yard>, ["~> 0.6"])
89
+ s.add_dependency(%q<cucumber>, ["~> 0.9"])
90
+ s.add_dependency(%q<jeweler>, ["~> 1.5"])
91
+ s.add_dependency(%q<redgreen>, ["~> 1.2"])
74
92
  end
75
93
  end
76
94
 
data/test/helper.rb CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'shoulda'
4
4
  require 'redgreen'
5
- require 'rr'
5
+ require 'mocha'
6
6
 
7
7
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
8
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -10,6 +10,21 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
10
  require 'scaffolder'
11
11
 
12
12
  class Test::Unit::TestCase
13
- require 'tempfile'
14
- include RR::Adapters::TestUnit
13
+ class << self
14
+
15
+ def should_have_method_attribute(klass)
16
+ should "have method #attribute" do
17
+ assert_respond_to( klass, :attribute )
18
+ end
19
+ end
20
+
21
+ def should_have_attribute(klass, *attributes)
22
+ attributes.each do |attribute|
23
+ should "have instance attribute #{attribute}" do
24
+ assert_respond_to( klass.new, attribute )
25
+ end
26
+ end
27
+ end
28
+
29
+ end
15
30
  end
data/test/test_insert.rb CHANGED
@@ -1,58 +1,50 @@
1
1
  require 'helper'
2
2
 
3
3
  class TestInsert < Test::Unit::TestCase
4
- context Scaffolder::Insert do
5
-
6
- setup do
7
- @options = {
8
- :start => 5,
9
- :stop => 10,
10
- :sequence => "ATGCGGGC"
11
- }
12
- end
4
+ context Scaffolder::Region::Insert do
13
5
 
14
- should "correctly store the passed options" do
15
- i = Scaffolder::Insert.new @options
16
- assert_equal(i.start, @options[:start])
17
- assert_equal(i.stop, @options[:stop])
18
- assert_equal(i.sequence, @options[:sequence])
19
- end
6
+ context "attributes" do
20
7
 
21
- should "reverse the sequence when passed the reverse tag" do
22
- i = Scaffolder::Insert.new @options.merge(:reverse => true)
23
- rev = Bio::Sequence::NA.new(@options[:sequence]).reverse_complement
24
- assert_equal(i.sequence, rev.upcase)
25
- end
8
+ should_have_attribute Scaffolder::Region::Insert, :source, :open, :close
26
9
 
27
- should "correctly generate the position" do
28
- i = Scaffolder::Insert.new @options
29
- assert_equal(i.position, (@options[:start]-1)..(@options[:stop]-1))
30
- end
10
+ setup do
11
+ @length = 15
12
+ @insert = Scaffolder::Region::Insert.new
13
+ @insert.raw_sequence('N' * @length)
14
+ end
31
15
 
32
- should "estimate the sequence end position" do
33
- @options.delete(:stop)
34
- i = Scaffolder::Insert.new @options
35
- assert_equal(i.stop, @options[:start] + @options[:sequence].length - 1)
36
- end
16
+ should "return open plus sequence length as default close" do
17
+ @insert.open 5
18
+ assert_equal(@insert.close,@insert.open + @length - 1)
19
+ end
37
20
 
38
- should "estimate the sequence start position" do
39
- @options.delete(:start)
40
- i = Scaffolder::Insert.new @options
41
- assert_equal(i.start, @options[:stop] - @options[:sequence].length - 1)
42
- end
21
+ should "return close minus sequence length as default open" do
22
+ @insert.close 20
23
+ assert_equal(@insert.open,@insert.close - @length - 1)
24
+ end
25
+
26
+ should "include the insert position" do
27
+ @insert.open 5
28
+ @insert.close 10
29
+ assert_equal(@insert.position,4..9)
30
+ end
43
31
 
44
- should "throw error when neither start or stop are provided" do
45
- @options.delete(:start)
46
- @options.delete(:stop)
47
- assert_raise ArgumentError do
48
- Scaffolder::Insert.new @options
32
+ should "throw an error when neither open or close are provided" do
33
+ assert_raise(Scaffolder::Errors::CoordinateError){ @insert.position }
49
34
  end
35
+
50
36
  end
51
37
 
52
- should "be comparable by end position" do
53
- a = Scaffolder::Insert.new @options
54
- b = Scaffolder::Insert.new @options.merge(:stop => @options[:stop] + 1)
55
- c = Scaffolder::Insert.new @options.merge(:stop => @options[:stop] + 2)
38
+ should "be comparable by close position" do
39
+ a = Scaffolder::Region::Insert.new
40
+ a.close 1
41
+
42
+ b = a.clone
43
+ b.close 2
44
+
45
+ c = b.clone
46
+ c.close 3
47
+
56
48
  assert_equal([c,a,b].sort, [a,b,c])
57
49
  end
58
50
 
data/test/test_region.rb CHANGED
@@ -2,10 +2,149 @@ require 'helper'
2
2
 
3
3
  class TestScaffolder < Test::Unit::TestCase
4
4
  context Scaffolder::Region do
5
- should "be created from parameters" do
6
- region = Scaffolder::Region.new(:unresolved,'NNNN')
7
- assert_equal(region.entry_type,:unresolved)
8
- assert_equal(region.sequence,'NNNN')
5
+
6
+ context "adding instance methods with attribute method" do
7
+
8
+ setup do
9
+ @attr = :some_attribute
10
+ end
11
+
12
+ should "create a single accessor attribute" do
13
+ Scaffolder::Region.attribute @attr
14
+ assert(Scaffolder::Region.instance_methods.include? @attr.to_s)
15
+ end
16
+
17
+ should "return nil until attribute value is stored" do
18
+ Scaffolder::Region.attribute @attr
19
+ region = Scaffolder::Region.new
20
+ assert_equal(region.send(@attr),nil)
21
+ region.send(@attr,5)
22
+ assert_equal(region.send(@attr),5)
23
+ end
24
+
25
+ should "allow specification of default value" do
26
+ Scaffolder::Region.attribute @attr, :default => 1
27
+ region = Scaffolder::Region.new
28
+ assert_equal(region.send(@attr),1)
29
+ region.send(@attr,5)
30
+ assert_equal(region.send(@attr),5)
31
+ end
32
+
33
+ should "allow specification of default value using a block" do
34
+ Scaffolder::Region.attribute @attr, :default => lambda{|s| s.entry_type }
35
+ region = Scaffolder::Region.new
36
+ assert_equal(region.send(@attr),region.entry_type)
37
+ region.send(@attr,5)
38
+ assert_equal(region.send(@attr),5)
39
+ end
40
+
41
+ end
42
+
43
+ context "passing the yaml hash to the generate method" do
44
+
45
+ setup do
46
+ Scaffolder::Region.attribute(:one)
47
+ Scaffolder::Region.attribute(:two)
48
+ @tags = {'one' => 1, 'two' => 2}
49
+ end
50
+
51
+ should "should call each tag in the hash as a method to store the value" do
52
+ Scaffolder::Region.any_instance.expects(:one).with(1)
53
+ Scaffolder::Region.any_instance.expects(:two).with(2)
54
+ Scaffolder::Region.generate(@tags)
55
+ end
56
+
57
+ should "return an instantiated region object" do
58
+ region = Scaffolder::Region.generate(@tags)
59
+ assert_equal(region.one,1)
60
+ assert_equal(region.two,2)
61
+ end
62
+
63
+ should "throw UnknownAttributeError for an unknown attribute" do
64
+ assert_raise Scaffolder::Errors::UnknownAttributeError do
65
+ Scaffolder::Region.generate({:three => 3})
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ context "attributes" do
72
+
73
+ should_have_attribute Scaffolder::Region,
74
+ :start, :stop, :reverse, :raw_sequence
75
+
76
+ should "return the class name as the entry type" do
77
+ Scaffolder::Region::NewRegion = Class.new(Scaffolder::Region)
78
+ assert_equal(Scaffolder::Region::NewRegion.new.entry_type,:newregion)
79
+ end
80
+
81
+ should "return 1 as default value for start attribute" do
82
+ sequence = Scaffolder::Region.new
83
+ assert_equal(sequence.start,1)
84
+ end
85
+
86
+ should "return #raw_sequence length as default value for stop attribute" do
87
+ length = 5
88
+ sequence = Scaffolder::Region.new
89
+ sequence.raw_sequence 'N' * length
90
+ assert_equal(sequence.stop,length)
91
+ end
92
+
9
93
  end
94
+
95
+ context "generating the processed sequence" do
96
+
97
+ [:sequence_hook, :raw_sequence].each do |method|
98
+
99
+ context "using the #{method} method" do
100
+
101
+ setup do
102
+ # Test class to prevent interference with other tests
103
+ @s = Class.new(Scaffolder::Region).new
104
+ @s.class.send(:define_method,method,lambda{'ATGCCAGATAACTGACTAGCATG'})
105
+ end
106
+
107
+ should "return the sequence when no other options are passed" do
108
+ assert_equal(@s.sequence,'ATGCCAGATAACTGACTAGCATG')
109
+ end
110
+
111
+ should "reverse complement sequence when passed the reverse option" do
112
+ @s.reverse true
113
+ assert_equal(@s.sequence, 'CATGCTAGTCAGTTATCTGGCAT')
114
+ end
115
+
116
+ should "create subsequence when passed sequence coordinates" do
117
+ @s.start 5
118
+ @s.stop 20
119
+ assert_equal(@s.sequence,'CAGATAACTGACTAGC')
120
+ end
121
+
122
+ should "raise a CoordinateError when start is less than 1" do
123
+ @s.start 0
124
+ assert_raise(Scaffolder::Errors::CoordinateError){ @s.sequence }
125
+ end
126
+
127
+ should "raise a CoordinateError when stop is greater than sequence " do
128
+ @s.stop 24
129
+ assert_raise(Scaffolder::Errors::CoordinateError){ @s.sequence }
130
+ end
131
+
132
+ should "raise a CoordinateError when stop is greater than start " do
133
+ @s.start 6
134
+ @s.stop 5
135
+ assert_raise(Scaffolder::Errors::CoordinateError){ @s.sequence }
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+
142
+ end
143
+
144
+ should "instantiate return corresponding region subclass when requested" do
145
+ Scaffolder::Region::Type = Class.new
146
+ assert_equal(Scaffolder::Region['type'],Scaffolder::Region::Type)
147
+ end
148
+
10
149
  end
11
150
  end