gfa 0.1.2 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +8 -2
- data/LICENSE +2 -2
- data/README.md +23 -15
- data/Rakefile +9 -8
- data/lib/gfa/common.rb +39 -42
- data/lib/gfa/field/char.rb +2 -2
- data/lib/gfa/field/float.rb +17 -1
- data/lib/gfa/field/hex.rb +17 -1
- data/lib/gfa/field/json.rb +18 -0
- data/lib/gfa/field/numarray.rb +38 -5
- data/lib/gfa/field/sigint.rb +14 -2
- data/lib/gfa/field/string.rb +11 -3
- data/lib/gfa/field.rb +89 -19
- data/lib/gfa/generator.rb +32 -28
- data/lib/gfa/graph.rb +14 -16
- data/lib/gfa/parser.rb +31 -22
- data/lib/gfa/record/comment.rb +15 -0
- data/lib/gfa/record/containment.rb +19 -13
- data/lib/gfa/record/header.rb +11 -10
- data/lib/gfa/record/jump.rb +45 -0
- data/lib/gfa/record/link.rb +42 -42
- data/lib/gfa/record/path.rb +14 -13
- data/lib/gfa/record/segment.rb +22 -18
- data/lib/gfa/record/walk.rb +20 -0
- data/lib/gfa/record.rb +53 -33
- data/lib/gfa/record_set/comment_set.rb +3 -0
- data/lib/gfa/record_set/containment_set.rb +4 -0
- data/lib/gfa/record_set/header_set.rb +3 -0
- data/lib/gfa/record_set/jump_set.rb +3 -0
- data/lib/gfa/record_set/link_set.rb +3 -0
- data/lib/gfa/record_set/path_set.rb +4 -0
- data/lib/gfa/record_set/segment_set.rb +4 -0
- data/lib/gfa/record_set/walk_set.rb +3 -0
- data/lib/gfa/record_set.rb +99 -0
- data/lib/gfa/version.rb +1 -1
- data/lib/gfa.rb +4 -4
- data/test/common_test.rb +5 -5
- data/test/field_test.rb +52 -26
- data/test/parser_test.rb +57 -20
- data/test/record_test.rb +7 -0
- data/test/test_helper.rb +10 -5
- metadata +33 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0e8e61ff97b34654b7a660b011826ad5549f66933a91a09658facf58c3fd56b1
|
4
|
+
data.tar.gz: 8f85f07955e71cd38a9dfa28011c70433473ad6a1137ed3e6e217d63eeba20a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b9f8fd92cd30d9e4e5c0263e938169141749c7be43011b574f937c9645608d8e72189bfe9072d7321e3acdf7e8288cecf42c90abe3ceef2bf001780bdb3e472
|
7
|
+
data.tar.gz: ee33c0b9c0dc9adb2df96d95b792b060b248e2f991ed5a0e4b4c136d66f04b9be6cf5ca58462bce046c6cfd9e7fed6c4c6949cb5e8923eb71e3d5f53f0da2703
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -13,20 +13,20 @@ This implementation follows the specifications of [GFA-spec][].
|
|
13
13
|
To parse a file in GFA format:
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
require
|
16
|
+
require 'gfa'
|
17
17
|
|
18
|
-
my_gfa = GFA.load(
|
18
|
+
my_gfa = GFA.load('assembly.gfa')
|
19
19
|
```
|
20
20
|
|
21
21
|
To load GFA strings line-by-line:
|
22
22
|
|
23
23
|
```ruby
|
24
|
-
require
|
24
|
+
require 'gfa'
|
25
25
|
|
26
26
|
my_gfa = GFA.new
|
27
|
-
fh = File.open(
|
27
|
+
fh = File.open('assembly.gfa', 'r')
|
28
28
|
fh.each do |ln|
|
29
|
-
|
29
|
+
my_gfa << ln
|
30
30
|
end
|
31
31
|
fh.close
|
32
32
|
```
|
@@ -37,15 +37,15 @@ fh.close
|
|
37
37
|
After altering a GFA object, you can simply save it in a file as:
|
38
38
|
|
39
39
|
```ruby
|
40
|
-
my_gfa.save(
|
40
|
+
my_gfa.save('alt-assembly.gfa')
|
41
41
|
```
|
42
42
|
|
43
43
|
Or line-by-line as:
|
44
44
|
|
45
45
|
```ruby
|
46
|
-
fh = File.open(
|
46
|
+
fh = File.open('alt-assembly.gfa', 'w')
|
47
47
|
my_gfa.each_line do |ln|
|
48
|
-
|
48
|
+
fh.puts ln
|
49
49
|
end
|
50
50
|
fh.close
|
51
51
|
```
|
@@ -58,12 +58,12 @@ Any `GFA` object can be exported as an [`RGL`][rgl] graph using the methods
|
|
58
58
|
[tiny.gfa](https://github.com/lmrodriguezr/gfa/raw/master/data/tiny.gfa):
|
59
59
|
|
60
60
|
```ruby
|
61
|
-
require
|
62
|
-
require
|
61
|
+
require 'gfa'
|
62
|
+
require 'rgl/dot'
|
63
63
|
|
64
|
-
my_gfa = GFA.load(
|
64
|
+
my_gfa = GFA.load('data/tiny.gfa')
|
65
65
|
dg = my_gfa.implicit_graph
|
66
|
-
dg.write_to_graphic_file(
|
66
|
+
dg.write_to_graphic_file('jpg')
|
67
67
|
```
|
68
68
|
|
69
69
|
![tiny_dg](https://github.com/lmrodriguezr/gfa/raw/master/data/tiny.jpg)
|
@@ -72,8 +72,8 @@ If you don't care about orientation, you can also build an undirected graph
|
|
72
72
|
without orientation:
|
73
73
|
|
74
74
|
```ruby
|
75
|
-
ug = my_gfa.implicit_graph(orient:false)
|
76
|
-
ug.write_to_graphic_file(
|
75
|
+
ug = my_gfa.implicit_graph(orient: false)
|
76
|
+
ug.write_to_graphic_file('jpg')
|
77
77
|
```
|
78
78
|
|
79
79
|
![tiny_ug](https://github.com/lmrodriguezr/gfa/raw/master/data/tiny_undirected.jpg)
|
@@ -85,6 +85,14 @@ ug.write_to_graphic_file("jpg")
|
|
85
85
|
gem install gfa
|
86
86
|
```
|
87
87
|
|
88
|
+
Or add the following line to your Gemfile:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
gem 'gfa'
|
92
|
+
```
|
93
|
+
|
94
|
+
and run `bundle install` from your shell.
|
95
|
+
|
88
96
|
|
89
97
|
# Author
|
90
98
|
|
@@ -96,5 +104,5 @@ gem install gfa
|
|
96
104
|
[Artistic License 2.0](LICENSE).
|
97
105
|
|
98
106
|
[GFA-spec]: https://github.com/pmelsted/GFA-spec
|
99
|
-
[lrr]:
|
107
|
+
[lrr]: https://rodriguez-r.com/
|
100
108
|
[rgl]: https://github.com/monora/rgl
|
data/Rakefile
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
2
3
|
|
3
|
-
$:.unshift File.join(File.dirname(__FILE__),
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
4
5
|
|
5
|
-
require
|
6
|
+
require 'gfa/version'
|
6
7
|
|
7
|
-
SOURCES = FileList[
|
8
|
+
SOURCES = FileList['lib/**/*.rb']
|
8
9
|
|
9
|
-
desc
|
10
|
+
desc 'Default Task'
|
10
11
|
task :default => :test
|
11
12
|
|
12
13
|
Rake::TestTask.new do |t|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
t.libs << 'test'
|
15
|
+
t.pattern = 'test/*_test.rb'
|
16
|
+
t.verbose = true
|
16
17
|
end
|
data/lib/gfa/common.rb
CHANGED
@@ -1,45 +1,42 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'gfa/version'
|
2
|
+
require 'gfa/record_set'
|
3
|
+
require 'gfa/field'
|
4
4
|
|
5
5
|
class GFA
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
alias == eql?
|
44
|
-
|
6
|
+
# Class-level
|
7
|
+
def self.assert_format(value, regex, message)
|
8
|
+
unless value =~ /^(?:#{regex})$/
|
9
|
+
raise "#{message}: #{value}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Instance-level
|
14
|
+
attr :gfa_version, :records, :opts
|
15
|
+
|
16
|
+
GFA::Record.TYPES.each do |r_type|
|
17
|
+
plural = "#{r_type.downcase}s"
|
18
|
+
singular = "#{r_type.downcase}"
|
19
|
+
|
20
|
+
define_method(plural) { records[r_type] }
|
21
|
+
define_method(singular) { |k| records[r_type][k] }
|
22
|
+
define_method("add_#{singular}") { |v| @records[r_type] << v }
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(opts = {})
|
26
|
+
@records = {}
|
27
|
+
@opts = { index: true, comments: false }.merge(opts)
|
28
|
+
GFA::Record.TYPES.each do |t|
|
29
|
+
@records[t] = GFA::RecordSet.name_class(t).new(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def empty?
|
34
|
+
records.empty? || records.values.all?(&:empty?)
|
35
|
+
end
|
36
|
+
|
37
|
+
def eql?(gfa)
|
38
|
+
records == gfa.records
|
39
|
+
end
|
40
|
+
|
41
|
+
alias == eql?
|
45
42
|
end
|
data/lib/gfa/field/char.rb
CHANGED
data/lib/gfa/field/float.rb
CHANGED
@@ -1,10 +1,26 @@
|
|
1
1
|
class GFA::Field::Float < GFA::Field
|
2
2
|
CODE = :f
|
3
|
-
REGEX =
|
3
|
+
REGEX = /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/
|
4
|
+
NATIVE_FUN = :to_f
|
5
|
+
|
6
|
+
def to_f
|
7
|
+
value
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_i
|
11
|
+
value.to_i
|
12
|
+
end
|
4
13
|
|
5
14
|
def initialize(f)
|
6
15
|
GFA.assert_format(f, regex, "Bad #{type}")
|
7
16
|
@value = f.to_f
|
8
17
|
end
|
9
18
|
|
19
|
+
def equivalent?(field)
|
20
|
+
if field.is_a?(GFA::Field::NumArray)
|
21
|
+
return field.size == 1 && field.first.to_f == value
|
22
|
+
end
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
10
26
|
end
|
data/lib/gfa/field/hex.rb
CHANGED
@@ -1,10 +1,26 @@
|
|
1
1
|
class GFA::Field::Hex < GFA::Field
|
2
2
|
CODE = :H
|
3
|
-
REGEX =
|
3
|
+
REGEX = /[0-9A-F]+/
|
4
|
+
NATIVE_FUN = :to_i
|
4
5
|
|
5
6
|
def initialize(f)
|
6
7
|
GFA.assert_format(f, regex, "Bad #{type}")
|
7
8
|
@value = f
|
8
9
|
end
|
9
10
|
|
11
|
+
def to_i
|
12
|
+
value.to_i(16)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_f
|
16
|
+
to_i.to_f
|
17
|
+
end
|
18
|
+
|
19
|
+
def equivalent?(field)
|
20
|
+
if field.is_a? GFA::Field::NumArray
|
21
|
+
return field.size == 1 && field.first.to_i == value
|
22
|
+
end
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
10
26
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class GFA::Field::Json < GFA::Field
|
2
|
+
CODE = :J
|
3
|
+
REGEX = /[ !-~]+/
|
4
|
+
NATIVE_FUN = :to_s
|
5
|
+
|
6
|
+
def initialize(f)
|
7
|
+
GFA.assert_format(f, regex, "Bad #{type}")
|
8
|
+
@value = f
|
9
|
+
end
|
10
|
+
|
11
|
+
def equivalent?(field)
|
12
|
+
# TODO
|
13
|
+
# We should parse the contents when comparing two GFA::Field::Json to
|
14
|
+
# evaluate equivalencies such as 'J:{ "a" : 1 }' ~ 'J:{"a":1}' (spaces)
|
15
|
+
# or 'J:{"a":1,"b":2}' ~ 'J:{"b":2,"a":1}' (element order)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
data/lib/gfa/field/numarray.rb
CHANGED
@@ -1,16 +1,49 @@
|
|
1
1
|
class GFA::Field::NumArray < GFA::Field
|
2
2
|
CODE = :B
|
3
|
-
REGEX =
|
3
|
+
REGEX = /[cCsSiIf](,[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)+/
|
4
|
+
NATIVE_FUN = :to_a
|
4
5
|
|
5
6
|
def initialize(f)
|
6
7
|
GFA.assert_format(f, regex, "Bad #{type}")
|
7
8
|
@value = f
|
8
9
|
end
|
9
10
|
|
10
|
-
def modifier
|
11
|
+
def modifier
|
12
|
+
value[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def modifier_fun
|
16
|
+
modifier == 'f' ? :to_f : :to_i
|
17
|
+
end
|
11
18
|
|
12
|
-
def array
|
13
|
-
|
14
|
-
|
19
|
+
def array
|
20
|
+
@array ||= value[2..-1].split(',').map(&modifier_fun)
|
21
|
+
end
|
22
|
+
|
23
|
+
alias to_a array
|
15
24
|
|
25
|
+
%i[empty? size count length first last].each do |i|
|
26
|
+
define_method(i) { array.send(i) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def number_type
|
30
|
+
{
|
31
|
+
c: 'int8_t', C: 'uint8_t',
|
32
|
+
s: 'int16_t', S: 'uint16_t',
|
33
|
+
i: 'int32_t', I: 'uint32_t',
|
34
|
+
f: 'float'
|
35
|
+
}[modifier.to_sym]
|
36
|
+
end
|
37
|
+
|
38
|
+
def equivalent?(field)
|
39
|
+
return true if eql?(field)
|
40
|
+
|
41
|
+
if field.respond_to?(:to_a)
|
42
|
+
field.to_a.map(&modifier_fun) == array
|
43
|
+
elsif size == 1 && field.respond_to?(modifier_fun)
|
44
|
+
field.send(modifier_fun) == first
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
16
49
|
end
|
data/lib/gfa/field/sigint.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
1
|
class GFA::Field::SigInt < GFA::Field
|
2
2
|
CODE = :i
|
3
|
-
REGEX =
|
4
|
-
|
3
|
+
REGEX = /[-+]?[0-9]+/
|
4
|
+
NATIVE_FUN = :to_i
|
5
|
+
|
5
6
|
def initialize(f)
|
6
7
|
GFA.assert_format(f, regex, "Bad #{type}")
|
7
8
|
@value = f.to_i
|
8
9
|
end
|
9
10
|
|
11
|
+
def to_i
|
12
|
+
value
|
13
|
+
end
|
14
|
+
|
15
|
+
def equivalent?(field)
|
16
|
+
if field.is_a?(GFA::Field::NumArray)
|
17
|
+
return field.size == 1 && field.first.to_i == value
|
18
|
+
end
|
19
|
+
|
20
|
+
super
|
21
|
+
end
|
10
22
|
end
|
data/lib/gfa/field/string.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
class GFA::Field::String < GFA::Field
|
2
2
|
CODE = :Z
|
3
|
-
REGEX =
|
4
|
-
|
3
|
+
REGEX = /[ !-~]+/
|
4
|
+
NATIVE_FUN = :to_s
|
5
|
+
|
6
|
+
def to_f
|
7
|
+
value.to_f
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_i(base = 10)
|
11
|
+
value.to_i(base)
|
12
|
+
end
|
13
|
+
|
5
14
|
def initialize(f)
|
6
15
|
GFA.assert_format(f, regex, "Bad #{type}")
|
7
16
|
@value = f
|
8
17
|
end
|
9
|
-
|
10
18
|
end
|
data/lib/gfa/field.rb
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
class GFA::Field
|
2
|
-
|
3
2
|
# Class-level
|
4
|
-
|
5
3
|
CODES = {
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
4
|
+
A: :Char,
|
5
|
+
i: :SigInt,
|
6
|
+
f: :Float,
|
7
|
+
Z: :String,
|
8
|
+
J: :Json, # Excluding new-line and tab characters
|
9
|
+
H: :Hex,
|
10
|
+
B: :NumArray
|
12
11
|
}
|
13
12
|
TYPES = CODES.values
|
14
|
-
|
15
13
|
TYPES.each { |t| require "gfa/field/#{t.downcase}" }
|
16
14
|
|
17
|
-
[
|
15
|
+
%i[CODES TYPES].each do |x|
|
18
16
|
define_singleton_method(x) { const_get(x) }
|
19
17
|
end
|
20
18
|
|
@@ -27,23 +25,95 @@ class GFA::Field
|
|
27
25
|
def self.name_class(name)
|
28
26
|
const_get(name)
|
29
27
|
end
|
30
|
-
|
28
|
+
|
29
|
+
def self.[](string)
|
30
|
+
code, value = string.split(':', 2)
|
31
|
+
code_class(code).new(value)
|
32
|
+
end
|
33
|
+
|
31
34
|
# Instance-level
|
32
35
|
|
33
36
|
attr :value
|
34
37
|
|
35
|
-
def type
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
def
|
40
|
-
|
41
|
-
|
38
|
+
def type
|
39
|
+
CODES[code]
|
40
|
+
end
|
41
|
+
|
42
|
+
def code
|
43
|
+
self.class::CODE
|
44
|
+
end
|
45
|
+
|
46
|
+
def regex
|
47
|
+
self.class::REGEX
|
48
|
+
end
|
49
|
+
|
50
|
+
def native_fun
|
51
|
+
self.class::NATIVE_FUN
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_native
|
55
|
+
native_fun == :to_s ? to_s(false) : send(native_fun)
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s(with_type = true)
|
42
59
|
"#{"#{code}:" if with_type}#{value}"
|
43
60
|
end
|
44
|
-
|
61
|
+
|
45
62
|
def hash
|
46
63
|
value.hash
|
47
64
|
end
|
48
65
|
|
66
|
+
##
|
67
|
+
# Evaluate equivalency of contents. All the following fields are distinct but
|
68
|
+
# contain the same information, and are therefore considered equivalent:
|
69
|
+
# Z:123, i:123, f:123.0, B:i,123, H:7b
|
70
|
+
#
|
71
|
+
# Note that the information content is determined by the class of the first
|
72
|
+
# operator. For example:
|
73
|
+
# - 'i:123' ~ 'f:123.4' is true because values are compared as integers
|
74
|
+
# - 'f:123.4' ~ 'i:123' if false because values are compared as floats
|
75
|
+
def equivalent?(field)
|
76
|
+
return true if eql?(field) # Might be faster, so testing this first
|
77
|
+
|
78
|
+
if field.respond_to?(native_fun)
|
79
|
+
if field.is_a?(GFA::Field) && native_fun == :to_s
|
80
|
+
field.to_s(false) == to_native
|
81
|
+
else
|
82
|
+
field.send(native_fun) == to_native
|
83
|
+
end
|
84
|
+
else
|
85
|
+
field == value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Non-equivalent to +field+, same as +!equivalent?+
|
91
|
+
def !~(field)
|
92
|
+
!self.~(field)
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Same as +equivalent?+
|
97
|
+
def ~(field)
|
98
|
+
equivalent?(field)
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Evaluate equality. Note that fields with equivalent values evaluate as
|
103
|
+
# different. For example, the following fields have equivalent information,
|
104
|
+
# but they all evaluate as different: Z:123, i:123, f:123.0, B:i,123, H:7b.
|
105
|
+
# To test equivalency of contents instead, use +equivalent?+
|
106
|
+
def eql?(field)
|
107
|
+
if field.is_a?(GFA::Field)
|
108
|
+
type == field.type && value == field.value
|
109
|
+
else
|
110
|
+
field.is_a?(value.class) && value == field
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Same as +eql?+
|
116
|
+
def ==(field)
|
117
|
+
eql?(field)
|
118
|
+
end
|
49
119
|
end
|
data/lib/gfa/generator.rb
CHANGED
@@ -1,31 +1,35 @@
|
|
1
1
|
class GFA
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
def save(file)
|
3
|
+
fh = File.open(file, 'w')
|
4
|
+
each_line do |ln|
|
5
|
+
fh.puts ln
|
6
|
+
end
|
7
|
+
fh.close
|
8
|
+
end
|
9
|
+
|
10
|
+
def each_line(&blk)
|
11
|
+
set_version_header('1.1') if gfa_version.nil?
|
12
|
+
GFA::Record.TYPES.each do |r_type|
|
13
|
+
records[r_type].each do |record|
|
14
|
+
blk[record.to_s]
|
6
15
|
end
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def to_s
|
27
|
-
o = ""
|
28
|
-
each_line{ |ln| o += ln + "\n" }
|
29
|
-
o
|
30
|
-
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_version_header(v)
|
20
|
+
unset_version
|
21
|
+
@records[:Header] << GFA::Record::Header.new("VN:Z:#{v}")
|
22
|
+
@gfa_version = v
|
23
|
+
end
|
24
|
+
|
25
|
+
def unset_version
|
26
|
+
@records[:Header].delete_if { |o| !o.fields[:VN].nil? }
|
27
|
+
@gfa_version = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
o = ''
|
32
|
+
each_line { |ln| o += ln + "\n" }
|
33
|
+
o
|
34
|
+
end
|
31
35
|
end
|