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/Gemfile +15 -0
- data/LICENSE +1 -1
- data/README.rdoc +29 -17
- data/Rakefile +22 -41
- data/VERSION +1 -1
- data/cucumber.yml +2 -0
- data/features/insert.feature +15 -0
- data/features/sequence.feature +20 -0
- data/features/step_definitions/scaffolder_steps.rb +48 -0
- data/features/support/env.rb +30 -0
- data/lib/scaffolder/errors.rb +6 -0
- data/lib/scaffolder/region/insert.rb +51 -0
- data/lib/scaffolder/region/sequence.rb +74 -0
- data/lib/scaffolder/region/unresolved.rb +23 -0
- data/lib/scaffolder/region.rb +139 -1
- data/lib/scaffolder.rb +197 -33
- data/scaffolder.gemspec +61 -43
- data/test/helper.rb +18 -3
- data/test/test_insert.rb +35 -43
- data/test/test_region.rb +143 -4
- data/test/test_scaffolder.rb +78 -47
- data/test/test_sequence.rb +61 -84
- data/test/test_unresolved.rb +23 -0
- data/yard/attribute_handler.rb +12 -0
- metadata +102 -45
- data/.gitignore +0 -22
- data/lib/scaffolder/insert.rb +0 -32
- data/lib/scaffolder/sequence.rb +0 -50
- data/test/data/sequences.fna +0 -4
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
group :default do
|
4
|
+
gem "bio", "~> 1.4"
|
5
|
+
end
|
6
|
+
|
7
|
+
group :development do
|
8
|
+
gem "bundler", "~> 1.0"
|
9
|
+
gem "shoulda", "~> 2.11"
|
10
|
+
gem "mocha", "~> 0.9"
|
11
|
+
gem "yard", "~> 0.6"
|
12
|
+
gem "cucumber", "~> 0.9"
|
13
|
+
gem "jeweler", "~> 1.5"
|
14
|
+
gem "redgreen", "~> 1.2"
|
15
|
+
end
|
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,25 +1,37 @@
|
|
1
|
-
|
1
|
+
== Synopsis
|
2
2
|
|
3
|
-
|
3
|
+
A simple genome scaffolder API for merging sequence contigs to build a continuous
|
4
|
+
draft sequence. The draft sequence is constructed through specifying the order of
|
5
|
+
contigs in in human-readable YAML files. Since the draft genome is specified by the
|
6
|
+
scaffold YAML it is easy to remove or manipulate already sequences. In addition as
|
7
|
+
the scaffold file is easy to edit and is ideal for version control and
|
8
|
+
repeatability.
|
4
9
|
|
5
|
-
==
|
6
|
-
|
7
|
-
* Fork the project.
|
8
|
-
* Make your feature addition or bug fix.
|
9
|
-
* Add tests for it. This is important so I don't break it in a
|
10
|
-
future version unintentionally.
|
11
|
-
* Commit, do not mess with rakefile, version, or history.
|
12
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
-
* Send me a pull request. Bonus points for topic branches.
|
10
|
+
== Feature List
|
14
11
|
|
15
|
-
|
12
|
+
* Construct a draft sequence scaffold using human-readable and versionable
|
13
|
+
plain text files.
|
14
|
+
* A simple and extensible Ruby API to traverse the scaffold.
|
15
|
+
|
16
|
+
== Installing
|
17
|
+
|
18
|
+
Ruby and RubyGems are required to use scaffolder. Scaffolder is installed on
|
19
|
+
the command line using:
|
16
20
|
|
17
|
-
|
21
|
+
$ gem install scaffolder
|
18
22
|
|
19
|
-
==
|
23
|
+
== Documentation
|
20
24
|
|
21
|
-
|
25
|
+
See the Scaffolder class for getting started with Scaffolder.
|
22
26
|
|
23
|
-
|
27
|
+
== Contact
|
28
|
+
|
29
|
+
Scaffolder was developed by Michael Barton (www.michaelbarton.me.uk). Pull
|
30
|
+
requests, patches and bug reports are welcome. The source code is available on
|
31
|
+
github[http://github.com/michaelbarton/scaffolder]. Bug reports and feature
|
32
|
+
requests may also be made there.
|
33
|
+
|
34
|
+
== Copyright
|
24
35
|
|
25
|
-
|
36
|
+
Scaffolder © 2010 by Michael Barton. Scaffolder is licensed under the MIT
|
37
|
+
license. Please see the LICENSE document for more information.
|
data/Rakefile
CHANGED
@@ -1,26 +1,25 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
2
10
|
require 'rake'
|
3
11
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
gem.add_dependency "bio", ">= 0"
|
14
|
-
gem.add_development_dependency "rr", ">= 0.10.11"
|
15
|
-
gem.add_development_dependency "shoulda", ">= 0"
|
16
|
-
gem.add_development_dependency "redgreen", ">= 0"
|
17
|
-
gem.add_development_dependency "yard", ">= 0"
|
18
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
19
|
-
end
|
20
|
-
Jeweler::GemcutterTasks.new
|
21
|
-
rescue LoadError
|
22
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
gem.name = "scaffolder"
|
15
|
+
gem.homepage = "http://www.michaelbarton.me.uk/scaffolder/"
|
16
|
+
gem.license = "MIT"
|
17
|
+
gem.summary = %Q{Genome scaffolding for human beings.}
|
18
|
+
gem.description = %Q{Organise sequence contigs into genome scaffolds using simple human-readable YAML files.}
|
19
|
+
gem.email = "mail@michaelbarton.me.uk"
|
20
|
+
gem.authors = ["Michael Barton"]
|
23
21
|
end
|
22
|
+
Jeweler::RubygemsDotOrgTasks.new
|
24
23
|
|
25
24
|
require 'rake/testtask'
|
26
25
|
Rake::TestTask.new(:test) do |test|
|
@@ -29,28 +28,10 @@ Rake::TestTask.new(:test) do |test|
|
|
29
28
|
test.verbose = true
|
30
29
|
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
Rcov::RcovTask.new do |test|
|
35
|
-
test.libs << 'test'
|
36
|
-
test.pattern = 'test/**/test_*.rb'
|
37
|
-
test.verbose = true
|
38
|
-
end
|
39
|
-
rescue LoadError
|
40
|
-
task :rcov do
|
41
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
42
|
-
end
|
43
|
-
end
|
31
|
+
require 'cucumber/rake/task'
|
32
|
+
Cucumber::Rake::Task.new(:features)
|
44
33
|
|
45
|
-
|
34
|
+
require 'yard'
|
35
|
+
YARD::Rake::YardocTask.new
|
46
36
|
|
47
37
|
task :default => :test
|
48
|
-
|
49
|
-
begin
|
50
|
-
require 'yard'
|
51
|
-
YARD::Rake::YardocTask.new
|
52
|
-
rescue LoadError
|
53
|
-
task :yardoc do
|
54
|
-
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
55
|
-
end
|
56
|
-
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/cucumber.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: The insert keyword
|
2
|
+
In order to place close gaps in the scaffold
|
3
|
+
A user can use the insert keyword
|
4
|
+
|
5
|
+
Scenario: A scaffold with a single insert keyword
|
6
|
+
Given the scaffold file has the sequences:
|
7
|
+
| name | nucleotides |
|
8
|
+
| seq | ATGCCGCGTAA |
|
9
|
+
And the first scaffold sequence has the inserts:
|
10
|
+
| name | nucleotides | open | close |
|
11
|
+
| ins | AAAA | 4 | 6 |
|
12
|
+
When creating a scaffolder object
|
13
|
+
Then the scaffold should contain 1 sequence entries
|
14
|
+
Then the scaffold should contain 1 insert entries
|
15
|
+
And the scaffold sequence should be ATGAAAACGTAA
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Feature: The sequence keyword
|
2
|
+
In order to place contigs the scaffold
|
3
|
+
A user can use the sequence keyword
|
4
|
+
|
5
|
+
Scenario: A scaffold with a single sequence keyword
|
6
|
+
Given the scaffold file has the sequences:
|
7
|
+
| name | nucleotides |
|
8
|
+
| seq | ATGCC |
|
9
|
+
When creating a scaffolder object
|
10
|
+
Then the scaffold should contain 1 sequence entries
|
11
|
+
And the scaffold sequence should be ATGCC
|
12
|
+
|
13
|
+
Scenario: A scaffold with a two sequence keywords
|
14
|
+
Given the scaffold file has the sequences:
|
15
|
+
| name | nucleotides |
|
16
|
+
| seq1 | ATGCC |
|
17
|
+
| seq2 | ATGCC |
|
18
|
+
When creating a scaffolder object
|
19
|
+
Then the scaffold should contain 2 sequence entries
|
20
|
+
And the scaffold sequence should be ATGCCATGCC
|
@@ -0,0 +1,48 @@
|
|
1
|
+
Given /^the scaffold file has the sequences:$/ do |sequences|
|
2
|
+
@entries ||= Array.new
|
3
|
+
@sequences ||= Array.new
|
4
|
+
|
5
|
+
sequences.hashes.each do |seq|
|
6
|
+
@entries << {'sequence' => {'source' => seq['name']}}
|
7
|
+
end
|
8
|
+
sequences.hashes.map do |seq|
|
9
|
+
@sequences << {:name => seq['name'], :sequence => seq['nucleotides']}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Given /^the first scaffold sequence has the inserts:$/ do |inserts|
|
14
|
+
sequence = @entries.detect{|s| s.keys.first == 'sequence' }
|
15
|
+
sequence['sequence']['inserts'] = (inserts.hashes.map do |insert|
|
16
|
+
i = {'source' => insert['name']}
|
17
|
+
i['open'] = insert['open'].to_i if insert['open']
|
18
|
+
i['close'] = insert['close'].to_i if insert['close']
|
19
|
+
i
|
20
|
+
end)
|
21
|
+
inserts.hashes.map do |insert|
|
22
|
+
@sequences << {:name => insert['name'], :sequence => insert['nucleotides']}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^creating a scaffolder object$/ do
|
27
|
+
@scf_file = write_scaffold_file(@entries)
|
28
|
+
@seq_file = write_sequence_file(@sequences)
|
29
|
+
|
30
|
+
@scaffold = Scaffolder.new(YAML.load(File.read(@scf_file)),@seq_file)
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^the scaffold should contain (.*) sequence entries$/ do |n|
|
34
|
+
@scaffold.select{|s| s.entry_type == :sequence}.length.should == n.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
Then /^the scaffold should contain (.*) insert entries$/ do |n|
|
38
|
+
@scaffold.select{|s| s.entry_type == :sequence}.inject(0) do |count,seq|
|
39
|
+
count =+ seq.inserts.length
|
40
|
+
end.should == n.to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
And /^the scaffold sequence should be (.*)$/ do |sequence|
|
44
|
+
generated_sequence = @scaffold.inject(String.new) do |build,entry|
|
45
|
+
build << entry.sequence
|
46
|
+
end
|
47
|
+
generated_sequence.should == sequence
|
48
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
rescue Bundler::BundlerError => e
|
5
|
+
$stderr.puts e.message
|
6
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
+
exit e.status_code
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'tempfile'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
|
13
|
+
require 'scaffolder'
|
14
|
+
|
15
|
+
def write_sequence_file(*sequences)
|
16
|
+
file = Tempfile.new("sequence").path
|
17
|
+
File.open(file,'w') do |tmp|
|
18
|
+
sequences.flatten.each do |sequence|
|
19
|
+
seq = Bio::Sequence.new(sequence[:sequence])
|
20
|
+
tmp.print(seq.output(:fasta,:header => sequence[:name]))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
file
|
24
|
+
end
|
25
|
+
|
26
|
+
def write_scaffold_file(scaffold)
|
27
|
+
file = Tempfile.new("scaffold").path
|
28
|
+
File.open(file,'w'){|tmp| tmp.print(YAML.dump(scaffold))}
|
29
|
+
file
|
30
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Inserts are used to additional usually smaller sequences to larger sequences.
|
2
|
+
# The attributes in the sequence class are used to specify where the host
|
3
|
+
# sequence is 'opened' and 'closed' to add the insert. Either one of these two
|
4
|
+
# attributes may be ommitted. Omitting the 'open' attribute will cause the
|
5
|
+
# insert open position to be calculated based on the close minus the sequence
|
6
|
+
# length. The reverse is true if the close position is ommittted.
|
7
|
+
#
|
8
|
+
# @see Scaffolder::Region::Sequence Scaffolder::Region::Sequence for an
|
9
|
+
# example on adding inserts to a sequence.
|
10
|
+
class Scaffolder::Region::Insert < Scaffolder::Region
|
11
|
+
|
12
|
+
# Fasta identifier for the insert sequence
|
13
|
+
#
|
14
|
+
# @param [String]
|
15
|
+
# @return [String]
|
16
|
+
attribute :source
|
17
|
+
|
18
|
+
# Open position where insert is added. Default is close position minus the
|
19
|
+
# sequence length.
|
20
|
+
#
|
21
|
+
# @param [Integer]
|
22
|
+
# @return [Integer]
|
23
|
+
attribute :open,
|
24
|
+
:default => lambda{|s| s.close - s.sequence_hook.length - 1 }
|
25
|
+
|
26
|
+
# End position where insert is added. Default is open position plus the
|
27
|
+
# sequence length.
|
28
|
+
#
|
29
|
+
# @param [Integer]
|
30
|
+
# @return [Integer]
|
31
|
+
attribute :close,
|
32
|
+
:default => lambda{|s| s.open + s.sequence_hook.length - 1 }
|
33
|
+
|
34
|
+
# Insertion position as a Range
|
35
|
+
#
|
36
|
+
# @return [Range]
|
37
|
+
# @raise [CoordinateError] if both the open and close positions are nil.
|
38
|
+
def position
|
39
|
+
raise CoordinateError if @close.nil? && @open.nil?
|
40
|
+
open-1..close-1
|
41
|
+
end
|
42
|
+
|
43
|
+
# Inserts are comaprable by close position.
|
44
|
+
#
|
45
|
+
# @return [Integer]
|
46
|
+
# @param [Scaffolder::Region::Insert]
|
47
|
+
def <=>(other)
|
48
|
+
self.close <=> other.close
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Class for inserting fasta sequence into the genome scaffold. The
|
2
|
+
# #raw_sequence method is also responsible for applying each of the sequence
|
3
|
+
# inserts to the original sequence. The following example specifies the
|
4
|
+
# insertion of a sequence identified by the fasta header 'sequence1'. The
|
5
|
+
# example also outlines and insert to be added to the sequence in the region
|
6
|
+
# between 3 and 10.
|
7
|
+
#
|
8
|
+
# - sequence:
|
9
|
+
# source: 'sequence1'
|
10
|
+
# inserts:
|
11
|
+
# -
|
12
|
+
# source: 'insert1'
|
13
|
+
# open: 3
|
14
|
+
# close: 10
|
15
|
+
class Scaffolder::Region::Sequence < Scaffolder::Region
|
16
|
+
|
17
|
+
# Fasta identifier for this sequence
|
18
|
+
#
|
19
|
+
# @param [String]
|
20
|
+
# @return [String]
|
21
|
+
attribute :source
|
22
|
+
|
23
|
+
# Array of inserts to add to this sequence. Each array entry may be either a
|
24
|
+
# Scaffolder::Region:Inserts or a corresponding to the attributes of an
|
25
|
+
# Insert. In the case of the latter each hash is used to generate a new
|
26
|
+
# Scaffolder::Region::Insert instance.
|
27
|
+
#
|
28
|
+
# @return [Array] Array of Scaffolder::Region::Insert
|
29
|
+
# @param [Array] inserts Accepts an array of either
|
30
|
+
# Scaffolder::Region::Insert or a hash of insert keyword data.
|
31
|
+
def inserts(inserts=nil)
|
32
|
+
if inserts.nil?
|
33
|
+
@inserts || Array.new
|
34
|
+
else
|
35
|
+
@inserts = inserts.map do |insert|
|
36
|
+
if insert.instance_of? Insert
|
37
|
+
insert
|
38
|
+
else
|
39
|
+
Insert.generate(insert)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# attribute :inserts, :default => Array.new
|
46
|
+
|
47
|
+
# Adds each of the sequence inserts to the raw sequence. Updates the sequence
|
48
|
+
# length each time an insert is added to reflect the change.
|
49
|
+
#
|
50
|
+
# @return [String] original sequence with inserts added.
|
51
|
+
# @raise [CoordinateError] if any insert open position is greater than the
|
52
|
+
# length of the original sequence
|
53
|
+
# @raise [CoordinateError] if any insert close position is less than one
|
54
|
+
# @raise [CoordinateError] if any insert open position is greater than the
|
55
|
+
# close position
|
56
|
+
def sequence_hook
|
57
|
+
# Set the sequence stop positon if not defined as the stop
|
58
|
+
# position is updated as each insert is added
|
59
|
+
@stop ||= raw_sequence.length
|
60
|
+
|
61
|
+
return inserts.sort.reverse.inject(raw_sequence) do |seq,insert|
|
62
|
+
raise CoordinateError if insert.open > raw_sequence.length
|
63
|
+
raise CoordinateError if insert.close < 1
|
64
|
+
raise CoordinateError if insert.open > insert.close
|
65
|
+
|
66
|
+
before_size = seq.length
|
67
|
+
seq[insert.position] = insert.sequence
|
68
|
+
diff = seq.length - before_size
|
69
|
+
stop(stop + diff)
|
70
|
+
|
71
|
+
seq
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This class is used to insert unreolved sequence regions in to the genome
|
2
|
+
# build. The unresolved region is filled with N characters. The example below
|
3
|
+
# with insert the characters 'NNNNN' into the genome build.
|
4
|
+
#
|
5
|
+
# - unresolved:
|
6
|
+
# length: 5
|
7
|
+
#
|
8
|
+
class Scaffolder::Region::Unresolved < Scaffolder::Region
|
9
|
+
|
10
|
+
# The length of the unresolved region
|
11
|
+
# @return [Integer]
|
12
|
+
# @param [Integer]
|
13
|
+
attribute :length
|
14
|
+
|
15
|
+
# Calculate unresolved region sequence
|
16
|
+
# @return [String] a string of Ns equal to length attribute
|
17
|
+
# @raise [CoordinateError] if the length attribute is nil
|
18
|
+
def sequence_hook
|
19
|
+
raise CoordinateError if length.nil?
|
20
|
+
'N' * length
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/scaffolder/region.rb
CHANGED
@@ -1 +1,139 @@
|
|
1
|
-
|
1
|
+
require 'scaffolder'
|
2
|
+
|
3
|
+
class Scaffolder::Region
|
4
|
+
include Scaffolder::Errors
|
5
|
+
|
6
|
+
class << self
|
7
|
+
include Scaffolder::Errors
|
8
|
+
|
9
|
+
# @return [Scaffolder::Region] Returns subclassed instances of
|
10
|
+
# Scaffolder::Region by name
|
11
|
+
def [](type)
|
12
|
+
self.const_get(type.capitalize)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Links the specification of values in the scaffold file to the assignment
|
16
|
+
# of instance variables.
|
17
|
+
#
|
18
|
+
# @param [Symbol] Define attributes for this type of scaffold
|
19
|
+
# region. Attributes are read from the scaffold file and stored as
|
20
|
+
# instance variables.
|
21
|
+
# @param [Hash] options Attribute options.
|
22
|
+
# @option options [Object,Proc] Default Specify a default value for this
|
23
|
+
# attribute if a value is not defined in the scaffold file.
|
24
|
+
# @example Simple specification
|
25
|
+
# class MyRegion < Scaffolder::Region
|
26
|
+
# attribute :value # "value" usable as a keyword in the scaffold file
|
27
|
+
# end
|
28
|
+
# @example Specification with a default value
|
29
|
+
# attribute :value, :default => 1
|
30
|
+
# @example Specification with where proc is evaluated for the default
|
31
|
+
# attribute :value, :default => lamdba{ Time.now.to_s }
|
32
|
+
# @example Specification with proc where the region instance is avaiable
|
33
|
+
# attribute :value, :default => lamdba{|s| s.other_variable + 1 }
|
34
|
+
def attribute(name,options = {})
|
35
|
+
define_method(name) do |*arg|
|
36
|
+
var = "@#{name}"
|
37
|
+
default = options[:default]
|
38
|
+
unless arg.first # Is an argument is passed to the method?
|
39
|
+
value = instance_variable_get(var)
|
40
|
+
return value if value
|
41
|
+
return default.respond_to?(:call) ? default.call(self) : default
|
42
|
+
end
|
43
|
+
instance_variable_set(var,arg.first)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Parse each key-value pair in the scaffold hash calling the corresponding
|
48
|
+
# attribute method for the key and passing the value as an argument.
|
49
|
+
#
|
50
|
+
# @param [Hash] region_data Key-Value pairs of the data required to define
|
51
|
+
# this scaffolder region.
|
52
|
+
# @return [Scaffolder::Region] Returns an region object where the
|
53
|
+
# instance variables have been assigned according to the region data
|
54
|
+
# hash.
|
55
|
+
# @raise [UnknownAttributeError] If a keyword in the scaffold file does not
|
56
|
+
# have a corresponding attribute in the class.
|
57
|
+
# @see Scaffolder::Region.attribute
|
58
|
+
def generate(region_data)
|
59
|
+
region = self.new
|
60
|
+
region_data.each_pair do |attribute,value|
|
61
|
+
begin
|
62
|
+
region.send(attribute.to_sym,value)
|
63
|
+
rescue NoMethodError => e
|
64
|
+
raise UnknownAttributeError.new(e)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
region
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
# The raw sequence for this region.
|
73
|
+
#
|
74
|
+
# @param [String]
|
75
|
+
# @return [String]
|
76
|
+
attribute :raw_sequence
|
77
|
+
|
78
|
+
# Trim the start of sequence to this position. Default is 1.
|
79
|
+
#
|
80
|
+
# @param [Interger]
|
81
|
+
# @return [Interger]
|
82
|
+
attribute :start, :default => 1
|
83
|
+
|
84
|
+
# Trim the end of sequence to this position. Default is the sequence length..
|
85
|
+
#
|
86
|
+
# @param [Interger]
|
87
|
+
# @return [Interger]
|
88
|
+
attribute :stop, :default => lambda{|s| s.sequence_hook.length}
|
89
|
+
|
90
|
+
|
91
|
+
# Should the sequence be reverse complemented. Reverse complementation is
|
92
|
+
# performed after the start and end of the sequence has been trimmed.
|
93
|
+
#
|
94
|
+
# @param [Boolean]
|
95
|
+
# @return [Boolean]
|
96
|
+
attribute :reverse
|
97
|
+
|
98
|
+
# Override this to manipulate the sequence before it's subsequenced, reverse
|
99
|
+
# complemented etc. by Scaffolder::Region#sequence.
|
100
|
+
#
|
101
|
+
# @return [String] The value of the raw_sequence attribute
|
102
|
+
# @see Scaffolder::Region#sequence
|
103
|
+
def sequence_hook
|
104
|
+
raw_sequence
|
105
|
+
end
|
106
|
+
|
107
|
+
# The name of the class. Useful for selecting specific region types.
|
108
|
+
#
|
109
|
+
# @return [Symbol]
|
110
|
+
def entry_type
|
111
|
+
self.class.name.split('::').last.downcase.to_sym
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns the value of the Scaffolder::Region#raw_sequence after
|
115
|
+
# subsequencing and reverse complementation (if specified in the
|
116
|
+
# scaffold file).
|
117
|
+
#
|
118
|
+
# @return [String] Sequence after all modifications
|
119
|
+
# @raise [CoordinateError] if the start position is less than 1.
|
120
|
+
# @raise [CoordinateError] if the stop position is greater than the sequence
|
121
|
+
# length.
|
122
|
+
# @raise [CoordinateError] if the start position is greater than the stop
|
123
|
+
# position.
|
124
|
+
def sequence
|
125
|
+
seq = sequence_hook
|
126
|
+
|
127
|
+
raise CoordinateError.new if start < 1
|
128
|
+
raise CoordinateError.new if stop > seq.length
|
129
|
+
raise CoordinateError.new if start > stop
|
130
|
+
|
131
|
+
seq = seq[(start-1)..(stop-1)]
|
132
|
+
seq = Bio::Sequence::NA.new(seq).reverse_complement if reverse
|
133
|
+
seq.to_s.upcase
|
134
|
+
end
|
135
|
+
|
136
|
+
require 'scaffolder/region/unresolved'
|
137
|
+
require 'scaffolder/region/insert'
|
138
|
+
require 'scaffolder/region/sequence'
|
139
|
+
end
|