bio-mummer 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/bin/delta2gvcf.rb +161 -109
- data/lib/bio-mummer/mummer.rb +20 -20
- data/test/test_bio-mummer.rb +2 -2
- metadata +2 -3
- data/.document +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 299d153188c65b1881bf1635b7389276ab1733f2
|
4
|
+
data.tar.gz: 3e3bf43c9c1551715d82c40bfd6c1b151f58dc2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c397099eb1478ceb5bc65d9657c64cfbe1bd02d2d0ce8e91a878065d1cf24407553d2f9609f8102af8b361d30b9048a499c4863a2b0772462f1977ae7d4d75ea
|
7
|
+
data.tar.gz: 3b1cdf0711552be2cdbfb3d1ad309d5d8abcdf7bbdae096cbcf439c6a9da2bba181b1085088ff4e1dcf1f8f84839186337977b048f7a89700b8c800717c71501
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/bin/delta2gvcf.rb
CHANGED
@@ -20,6 +20,7 @@ class OptParser
|
|
20
20
|
opts.on("-d", "--delta FILENAME", "Delta file generated by nucmer") do |fn|
|
21
21
|
pn = Pathname.new(fn)
|
22
22
|
if pn.size?
|
23
|
+
options.samplename = pn.basename(".delta")
|
23
24
|
options.delta = pn
|
24
25
|
match = pn.each_line.first.match(/(?<ref>\/.*) (?<qry>\/.*)/)
|
25
26
|
if match
|
@@ -38,6 +39,10 @@ class OptParser
|
|
38
39
|
exit(1)
|
39
40
|
end
|
40
41
|
end
|
42
|
+
|
43
|
+
opts.on("-s", "--sample SAMPLENAME", "gVCF Sample name") do |samplename|
|
44
|
+
options.samplename = samplename
|
45
|
+
end
|
41
46
|
end
|
42
47
|
opt_parser.parse!(args)
|
43
48
|
return options
|
@@ -45,7 +50,6 @@ class OptParser
|
|
45
50
|
end
|
46
51
|
options = OptParser.parse(ARGV)
|
47
52
|
|
48
|
-
# Open the Delta File
|
49
53
|
d = BioMummer::DeltaFile.new(StringIO.new(`delta-filter -r -q #{options.delta}`))
|
50
54
|
|
51
55
|
puts '##fileformat=VCFv4.1
|
@@ -57,125 +61,173 @@ puts '##fileformat=VCFv4.1
|
|
57
61
|
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
|
58
62
|
##FORMAT=<ID=MIN_DP,Number=1,Type=Integer,Description="Minimum DP observed within the GVCF block">
|
59
63
|
##FORMAT=<ID=PL,Number=G,Type=Integer,Description="Normalized, Phred-scaled likelihoods for genotypes as defined in the VCF specification">'
|
60
|
-
|
61
64
|
options.ref.each do |name, seq|
|
62
65
|
puts "##contig=<ID=#{name},length=#{seq.length}>"
|
63
66
|
end
|
64
|
-
puts "
|
67
|
+
puts '##INFO=<ID=BaseQRankSum,Number=1,Type=Float,Description="Z-score from Wilcoxon rank sum test of Alt Vs. Ref base qualities">
|
68
|
+
##INFO=<ID=ClippingRankSum,Number=1,Type=Float,Description="Z-score From Wilcoxon rank sum test of Alt vs. Ref number of hard clipped bases">
|
69
|
+
##INFO=<ID=DP,Number=1,Type=Integer,Description="Approximate read depth; some reads may have been filtered">
|
70
|
+
##INFO=<ID=DS,Number=0,Type=Flag,Description="Were any of the samples downsampled?">
|
71
|
+
##INFO=<ID=END,Number=1,Type=Integer,Description="Stop position of the interval">
|
72
|
+
##INFO=<ID=HaplotypeScore,Number=1,Type=Float,Description="Consistency of the site with at most two segregating haplotypes">
|
73
|
+
##INFO=<ID=InbreedingCoeff,Number=1,Type=Float,Description="Inbreeding coefficient as estimated from the genotype likelihoods per-sample when compared against the Hardy-Weinberg expectation">
|
74
|
+
##INFO=<ID=MLEAC,Number=A,Type=Integer,Description="Maximum likelihood expectation (MLE) for the allele counts (not necessarily the same as the AC), for each ALT allele, in the same order as listed">
|
75
|
+
##INFO=<ID=MLEAF,Number=A,Type=Float,Description="Maximum likelihood expectation (MLE) for the allele frequency (not necessarily the same as the AF), for each ALT allele, in the same order as listed">
|
76
|
+
##INFO=<ID=MQ,Number=1,Type=Float,Description="RMS Mapping Quality">
|
77
|
+
##INFO=<ID=MQ0,Number=1,Type=Integer,Description="Total Mapping Quality Zero Reads">
|
78
|
+
##INFO=<ID=MQRankSum,Number=1,Type=Float,Description="Z-score From Wilcoxon rank sum test of Alt vs. Ref read mapping qualities">
|
79
|
+
##INFO=<ID=ReadPosRankSum,Number=1,Type=Float,Description="Z-score from Wilcoxon rank sum test of Alt vs. Ref read position bias">'
|
80
|
+
puts "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT\t#{options.samplename}"
|
65
81
|
|
66
82
|
d.alignments
|
67
|
-
.group_by{|
|
68
|
-
.
|
83
|
+
.group_by{ |alignment| alignment.refname }
|
84
|
+
.sort_by{ |refname, alignments| refname }
|
69
85
|
.each do |refname, alignments|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
86
|
+
|
87
|
+
clusters = Enumerator.new do |yielder|
|
88
|
+
# We sweep along each of the reference sequences. The cursor tracks
|
89
|
+
# our position as we go so we don't concatenate regions that are
|
90
|
+
# actually overlapping.
|
91
|
+
cursor = 1
|
92
|
+
|
93
|
+
# The =alignments= object is an array of BioMummer::Alignment
|
94
|
+
# objects that all match a particular scaffold.
|
95
|
+
alignments
|
96
|
+
.sort_by{ |alignment| alignment.refstart }.
|
97
|
+
each do |aln|
|
98
|
+
# Create Bio::Sequence::NA subsequences for the reference and
|
99
|
+
# query. They are initially unaligned.
|
100
|
+
refSeq = options.ref[aln.refname].subseq(aln.refstart, aln.refstop)
|
101
|
+
qrySeq = options.qry[aln.qryname].subseq(aln.qrystart, aln.qrystop)
|
102
|
+
qrySeq.complement! unless aln.strand
|
103
|
+
|
104
|
+
# Do we have uncovered bases before the alignment starts? These
|
105
|
+
# are detected as gaps between the cursor and the alignment start
|
106
|
+
# site in the reference.
|
107
|
+
gap_size = aln.refstart - cursor
|
108
|
+
overlap_size = 0
|
109
|
+
if gap_size > 0
|
110
|
+
# There is a stretch of reference bases without an alignment
|
111
|
+
gapSeq = options.ref[aln.refname].subseq(cursor, aln.refstart - 1)
|
112
|
+
gapSeq
|
113
|
+
.chars
|
114
|
+
.zip(("-" * gapSeq.length).chars, Range.new(cursor, aln.refstart, true))
|
115
|
+
.each{ |ary| yielder << ary }
|
116
|
+
cursor = aln.refstart
|
100
117
|
else
|
101
|
-
|
102
|
-
end
|
103
|
-
end.drop_while do |varClass, arr|
|
104
|
-
if varClass != "INS"
|
105
|
-
overlap, overlap2 = overlap - arr.length , overlap
|
118
|
+
overlap_size = cursor - aln.refstart
|
106
119
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
120
|
+
|
121
|
+
# Nucmer records insertions and deletions as a series of positive
|
122
|
+
# and negative integers corresponding to how many steps along the
|
123
|
+
# alignment until you get to the next gap in the reference
|
124
|
+
# sequence (positive integer) or how many steps until the next gap
|
125
|
+
# in the query (negative integer). BioMummer exposes these as the
|
126
|
+
# alignments 'distances' array.
|
127
|
+
# We walk along the Bio::Sequence::NA objects and insert gaps
|
128
|
+
# (".") when needed. We store our current position in the
|
129
|
+
# reference and the query in a two-element array.
|
130
|
+
aln.distances.inject([0,0]) do |mem, distance_to_gap|
|
131
|
+
if distance_to_gap > 0
|
132
|
+
qrySeq.insert(mem[0] + distance_to_gap - 1, ".")
|
133
|
+
[mem[0] + distance_to_gap, mem[1] + distance_to_gap]
|
113
134
|
else
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
puts [refname,
|
118
|
-
cursor,
|
119
|
-
".",
|
120
|
-
refBase,
|
121
|
-
"<NON_REF>",
|
122
|
-
'.',
|
123
|
-
'.',
|
124
|
-
"END=#{cursor + arr.length - 1 - overlap2};ALTSCAFF=#{a.queryname};RLEN=#{arr.length};OVERLAP2=#{overlap2}",
|
125
|
-
"GT:DP:GQ:MIN_DP:PL",
|
126
|
-
"0:200:200:200:0,800"].join("\t")
|
127
|
-
cursor += arr.length - overlap2
|
128
|
-
overlap2 = 0
|
129
|
-
when "SNP"
|
130
|
-
arr.each do |snp|
|
131
|
-
puts [refname,
|
132
|
-
cursor,
|
133
|
-
".",
|
134
|
-
snp.first.upcase,
|
135
|
-
[snp.last.upcase, "<NON_REF>"].join(","),
|
136
|
-
'.',
|
137
|
-
'.',
|
138
|
-
"END=#{cursor};ALTSCAFF=#{a.queryname}",
|
139
|
-
"GT:DP:GQ:MIN_DP:PL",
|
140
|
-
"1:200:200:200:800,0,800"].join("\t")
|
141
|
-
cursor += 1
|
135
|
+
refSeq.insert(mem[1] - distance_to_gap - 1, ".")
|
136
|
+
[mem[0] - distance_to_gap, mem[1] - distance_to_gap]
|
142
137
|
end
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
# cursor += arr.length
|
154
|
-
when "INS"
|
155
|
-
refBase = options.ref[refname][cursor-2].upcase
|
156
|
-
puts [refname,
|
157
|
-
cursor-1,
|
158
|
-
".",
|
159
|
-
refBase,
|
160
|
-
[(refBase + arr.map{|a| a.last}.join).upcase, "<NON_REF>"].join(","),
|
161
|
-
'.',
|
162
|
-
'.',
|
163
|
-
"END=#{cursor - 1};ALTSCAFF=#{a.queryname};STRAND=#{a.strand}",
|
164
|
-
"GT:DP:GQ:MIN_DP:PL",
|
165
|
-
"1:200:200:200:800,0,800"].join("\t")
|
166
|
-
when "DEL"
|
167
|
-
puts [refname,
|
168
|
-
cursor,
|
169
|
-
".",
|
170
|
-
arr.map{|a| a.first.upcase}.join,
|
171
|
-
".,<NON_REF>",
|
172
|
-
'.',
|
173
|
-
'.',
|
174
|
-
"END=#{cursor + arr.length - 1};ALTSCAFF=#{a.queryname}",
|
175
|
-
"GT:DP:GQ:MIN_DP:PL",
|
176
|
-
"1:200:200:200:800,0,800"].join("\t")
|
177
|
-
cursor += arr.length
|
138
|
+
end
|
139
|
+
|
140
|
+
if overlap_size < refSeq.length
|
141
|
+
i = aln.refstart - 1
|
142
|
+
positions = refSeq.chars.map{ |base| base == '.' ? i : i+=1 }
|
143
|
+
refSeq
|
144
|
+
.chars
|
145
|
+
.zip(qrySeq.chars, positions)
|
146
|
+
.drop(overlap_size)
|
147
|
+
.each{ |ary| yielder << ary }
|
178
148
|
end
|
179
149
|
end
|
180
150
|
end
|
151
|
+
|
152
|
+
cursor = 0
|
153
|
+
stolen_zipped = [nil, nil, nil]
|
154
|
+
chunked = clusters.find_all do |refBase, qryBase, position|
|
155
|
+
if position > cursor || (position == cursor && refBase == ".")
|
156
|
+
cursor = position
|
157
|
+
true
|
158
|
+
else
|
159
|
+
false
|
160
|
+
end
|
161
|
+
end.chunk do |refBase, qryBase, position|
|
162
|
+
# Classify runs of identiry, insertions, deletions or SNPs.
|
163
|
+
if refBase == qryBase
|
164
|
+
:NO_VARIATION
|
165
|
+
elsif qryBase == "-"
|
166
|
+
:NO_COVERAGE
|
167
|
+
elsif qryBase == '.'
|
168
|
+
:DELETION
|
169
|
+
elsif refBase == '.'
|
170
|
+
:INSERTION
|
171
|
+
else
|
172
|
+
:SNP
|
173
|
+
end
|
174
|
+
end.to_a
|
175
|
+
|
176
|
+
chunked.each_cons(2) do |current, upcoming|
|
177
|
+
cur_class = current.first
|
178
|
+
cur_zipped = current.last
|
179
|
+
nxt_class = upcoming.first
|
180
|
+
|
181
|
+
if nxt_class == :INSERTION || nxt_class == :DELETION
|
182
|
+
stolen_zipped = cur_zipped.pop
|
183
|
+
next if cur_zipped.length == 0
|
184
|
+
end
|
185
|
+
|
186
|
+
case cur_class
|
187
|
+
when :NO_COVERAGE
|
188
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{cur_zipped.first.first.upcase}\t<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t0:0:0:0,0"
|
189
|
+
when :NO_VARIATION
|
190
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{cur_zipped.first.first.upcase}\t<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t0:1:200:0,800"
|
191
|
+
when :SNP
|
192
|
+
cur_zipped.each do |refBase, qryBase, position|
|
193
|
+
puts "#{refname}\t#{position}\t.\t#{refBase.upcase}\t#{qryBase.upcase},<NON_REF>\t.\t.\tEND=#{position}\tGT:DP:GQ:PL\t1:1:200:800,0,800"
|
194
|
+
end
|
195
|
+
when :INSERTION
|
196
|
+
refSeq, qrySeq = cur_zipped.unshift(stolen_zipped).transpose.map{|seq| seq.reject{|c|c=='.'}.join.upcase }
|
197
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{refSeq}\t#{qrySeq},<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t1:1:200:800,0,800"
|
198
|
+
when :DELETION
|
199
|
+
refSeq, qrySeq = cur_zipped.unshift(stolen_zipped).transpose.map{|seq| seq.reject{|c|c=='.'}.join.upcase }
|
200
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{refSeq}\t#{qrySeq},<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t1:1:200:800,0,800"
|
201
|
+
end
|
202
|
+
cursor = [cursor, cur_zipped.last.last].max
|
203
|
+
end
|
204
|
+
|
205
|
+
# We iterated over the entries in a window of length two, outputting
|
206
|
+
# the first in the pair. This leaves the last entry unobserved, so
|
207
|
+
# we take special care to output it here
|
208
|
+
cur_class, cur_zipped = chunked.last
|
209
|
+
case cur_class
|
210
|
+
when :NO_COVERAGE
|
211
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{cur_zipped.first.first.upcase}\t<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t0:0:0:0,0"
|
212
|
+
when :NO_VARIATION
|
213
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{cur_zipped.first.first.upcase}\t<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t0:1:200:0,800"
|
214
|
+
when :SNP
|
215
|
+
cur_zipped.each do |refBase, qryBase, position|
|
216
|
+
puts "#{refname}\t#{position}\t.\t#{refBase.upcase}\t#{qryBase.upcase},<NON_REF>\t.\t.\tEND=#{position}\tGT:DP:GQ:PL\t1:1:200:800,0,800"
|
217
|
+
end
|
218
|
+
when :INSERTION
|
219
|
+
refSeq, qrySeq = cur_zipped.unshift(stolen_zipped).transpose.map{|seq| seq.reject{|c|c=='.'}.join.upcase }
|
220
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{refSeq}\t#{qrySeq},<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t1:1:200:800,0,800"
|
221
|
+
when :DELETION
|
222
|
+
refSeq, qrySeq = cur_zipped.unshift(stolen_zipped).transpose.map{|seq| seq.reject{|c|c=='.'}.join.upcase }
|
223
|
+
puts "#{refname}\t#{cur_zipped.first.last}\t.\t#{refSeq}\t#{qrySeq},<NON_REF>\t.\t.\tEND=#{cur_zipped.last.last}\tGT:DP:GQ:PL\t1:1:200:800,0,800"
|
224
|
+
end
|
225
|
+
|
226
|
+
# It's likely that the alignments don't run to the end of the
|
227
|
+
# scaffold, so we fill in to the scaffold end with the 'no coverage'
|
228
|
+
# entry
|
229
|
+
remaining = options.ref[refname].length - cursor
|
230
|
+
if remaining > 0
|
231
|
+
puts "#{refname}\t#{cursor+1}\t.\t#{options.ref[refname][cursor].upcase}\t<NON_REF>\t.\t.\tEND=#{options.ref[refname].length}\tGT:DP:GQ:PL\t0:0:0:0,0"
|
232
|
+
end
|
181
233
|
end
|
data/lib/bio-mummer/mummer.rb
CHANGED
@@ -3,15 +3,15 @@ require 'stringio'
|
|
3
3
|
module BioMummer
|
4
4
|
|
5
5
|
class Alignment
|
6
|
-
attr_accessor :refname, :
|
6
|
+
attr_accessor :refname, :qryname, :refstart, :refstop, :qrystart, :qrystop, :strand, :distances
|
7
7
|
|
8
|
-
def initialize(refname,
|
8
|
+
def initialize(refname, qryname, refstart, refstop, qrystart, qrystop, strand, distances)
|
9
9
|
@refname = refname
|
10
|
-
@
|
10
|
+
@qryname = qryname
|
11
11
|
@refstart = refstart
|
12
12
|
@refstop = refstop
|
13
|
-
@
|
14
|
-
@
|
13
|
+
@qrystart = qrystart
|
14
|
+
@qrystop = qrystop
|
15
15
|
@strand = strand
|
16
16
|
@distances = distances
|
17
17
|
end
|
@@ -35,13 +35,13 @@ module BioMummer
|
|
35
35
|
|
36
36
|
def ref_to_query(ref_position)
|
37
37
|
position_in_alignment = ref_position - refstart + 1
|
38
|
-
|
38
|
+
qrypos = nil
|
39
39
|
if position_in_alignment >= deltas.length
|
40
|
-
|
40
|
+
qrypos = @qrystart - 1 + position_in_alignment + deltas.last
|
41
41
|
elsif deltas[position_in_alignment-1]
|
42
|
-
|
42
|
+
qrypos = @qrystart - 1 + position_in_alignment + deltas[position_in_alignment-1]
|
43
43
|
end
|
44
|
-
!@strand &&
|
44
|
+
!@strand && qrypos ? @qrystart + @qrystop - qrypos : qrypos
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -64,21 +64,21 @@ module BioMummer
|
|
64
64
|
|
65
65
|
def parse(string)
|
66
66
|
string.split("\n").slice_before(/^>/).flat_map do |block|
|
67
|
-
refname,
|
67
|
+
refname, qryname = block.shift.match(/>(.*) (.*) \d+ \d+/).captures
|
68
68
|
block.slice_before(/\d+ \d+ \d+ \d+/).map do |alignment|
|
69
|
-
refstart, refstop,
|
69
|
+
refstart, refstop, qrystart, qrystop = alignment
|
70
70
|
.shift
|
71
71
|
.match(/(\d+) (\d+) (\d+) (\d+) /)
|
72
72
|
.captures
|
73
73
|
.map{ |c| c.to_i }
|
74
74
|
alignment.pop
|
75
75
|
Alignment.new(refname,
|
76
|
-
|
76
|
+
qryname,
|
77
77
|
refstart,
|
78
78
|
refstop,
|
79
|
-
[
|
80
|
-
[
|
81
|
-
|
79
|
+
[qrystart, qrystop].min,
|
80
|
+
[qrystart, qrystop].max,
|
81
|
+
qrystart < qrystop,
|
82
82
|
alignment.map{ |i| i.to_i })
|
83
83
|
end
|
84
84
|
end
|
@@ -110,13 +110,13 @@ module BioMummer
|
|
110
110
|
a.refname == refname && a.refstart <= startpos && a.refstop >= endpos
|
111
111
|
end
|
112
112
|
if a
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
if
|
113
|
+
qryname = a.qryname
|
114
|
+
qrystart = a.ref_to_query(startpos)
|
115
|
+
qrystop = a.ref_to_query(endpos)
|
116
|
+
if qrystart.nil? || qrystop.nil?
|
117
117
|
return nil
|
118
118
|
else
|
119
|
-
return [
|
119
|
+
return [qryname, qrystart, qrystop, a.strand]
|
120
120
|
end
|
121
121
|
else
|
122
122
|
return nil
|
data/test/test_bio-mummer.rb
CHANGED
@@ -15,8 +15,8 @@ class TestBioMummer < MiniTest::Test
|
|
15
15
|
assert_kind_of Fixnum, @report.alignments.first.refstart
|
16
16
|
assert_equal 1, @report.alignments.first.refstart
|
17
17
|
assert_equal 2435, @report.alignments.first.refstop
|
18
|
-
assert_equal 1, @report.alignments.first.
|
19
|
-
assert_equal 2435, @report.alignments.first.
|
18
|
+
assert_equal 1, @report.alignments.first.qrystart
|
19
|
+
assert_equal 2435, @report.alignments.first.qrystop
|
20
20
|
end
|
21
21
|
|
22
22
|
should "do basic coordinate transforms on the positive strand" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bio-mummer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- robsyme
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: shoulda
|
@@ -105,7 +105,6 @@ extra_rdoc_files:
|
|
105
105
|
- README.md
|
106
106
|
- README.rdoc
|
107
107
|
files:
|
108
|
-
- .document
|
109
108
|
- .travis.yml
|
110
109
|
- Gemfile
|
111
110
|
- LICENSE.txt
|