gfa 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/LICENSE +201 -0
- data/README.md +100 -0
- data/Rakefile +16 -0
- data/lib/gfa.rb +4 -0
- data/lib/gfa/common.rb +45 -0
- data/lib/gfa/field.rb +49 -0
- data/lib/gfa/field/char.rb +10 -0
- data/lib/gfa/field/float.rb +10 -0
- data/lib/gfa/field/hex.rb +10 -0
- data/lib/gfa/field/numarray.rb +16 -0
- data/lib/gfa/field/sigint.rb +10 -0
- data/lib/gfa/field/string.rb +10 -0
- data/lib/gfa/generator.rb +31 -0
- data/lib/gfa/graph.rb +100 -0
- data/lib/gfa/parser.rb +45 -0
- data/lib/gfa/record.rb +90 -0
- data/lib/gfa/record/containment.rb +24 -0
- data/lib/gfa/record/header.rb +13 -0
- data/lib/gfa/record/link.rb +50 -0
- data/lib/gfa/record/path.rb +18 -0
- data/lib/gfa/record/segment.rb +22 -0
- data/lib/gfa/version.rb +7 -0
- data/test/common_test.rb +34 -0
- data/test/field_test.rb +50 -0
- data/test/parser_test.rb +47 -0
- data/test/record_test.rb +73 -0
- data/test/test_helper.rb +6 -0
- metadata +39 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8388ee28f1d71339d701b32e2a4fa1538b0f391f
|
4
|
+
data.tar.gz: 520590efdc7170cf805db8427574e6e6fb5a8ac1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8e8366d01006fbffc22ae49f3b4d619d8e8fbf25ef2c6173b427f05382a28c8a9efd7798f791d05c890e3057d3115ca8d3a6bc6d330551bf0915569c89ecc5c
|
7
|
+
data.tar.gz: c6bcd711d7841585e6452cca87564b5d2e41a673e1bc4869df632db6193b928bbc6374ca370d8033db8df70e377234f3aa0a5f3a9ae96c56f053b771dff78060
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
The Artistic License 2.0
|
2
|
+
|
3
|
+
Copyright (c) 2016 Luis M Rodriguez-R
|
4
|
+
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
6
|
+
of this license document, but changing it is not allowed.
|
7
|
+
|
8
|
+
Preamble
|
9
|
+
|
10
|
+
This license establishes the terms under which a given free software
|
11
|
+
Package may be copied, modified, distributed, and/or redistributed.
|
12
|
+
The intent is that the Copyright Holder maintains some artistic
|
13
|
+
control over the development of that Package while still keeping the
|
14
|
+
Package available as open source and free software.
|
15
|
+
|
16
|
+
You are always permitted to make arrangements wholly outside of this
|
17
|
+
license directly with the Copyright Holder of a given Package. If the
|
18
|
+
terms of this license do not permit the full use that you propose to
|
19
|
+
make of the Package, you should contact the Copyright Holder and seek
|
20
|
+
a different licensing arrangement.
|
21
|
+
|
22
|
+
Definitions
|
23
|
+
|
24
|
+
"Copyright Holder" means the individual(s) or organization(s)
|
25
|
+
named in the copyright notice for the entire Package.
|
26
|
+
|
27
|
+
"Contributor" means any party that has contributed code or other
|
28
|
+
material to the Package, in accordance with the Copyright Holder's
|
29
|
+
procedures.
|
30
|
+
|
31
|
+
"You" and "your" means any person who would like to copy,
|
32
|
+
distribute, or modify the Package.
|
33
|
+
|
34
|
+
"Package" means the collection of files distributed by the
|
35
|
+
Copyright Holder, and derivatives of that collection and/or of
|
36
|
+
those files. A given Package may consist of either the Standard
|
37
|
+
Version, or a Modified Version.
|
38
|
+
|
39
|
+
"Distribute" means providing a copy of the Package or making it
|
40
|
+
accessible to anyone else, or in the case of a company or
|
41
|
+
organization, to others outside of your company or organization.
|
42
|
+
|
43
|
+
"Distributor Fee" means any fee that you charge for Distributing
|
44
|
+
this Package or providing support for this Package to another
|
45
|
+
party. It does not mean licensing fees.
|
46
|
+
|
47
|
+
"Standard Version" refers to the Package if it has not been
|
48
|
+
modified, or has been modified only in ways explicitly requested
|
49
|
+
by the Copyright Holder.
|
50
|
+
|
51
|
+
"Modified Version" means the Package, if it has been changed, and
|
52
|
+
such changes were not explicitly requested by the Copyright
|
53
|
+
Holder.
|
54
|
+
|
55
|
+
"Original License" means this Artistic License as Distributed with
|
56
|
+
the Standard Version of the Package, in its current version or as
|
57
|
+
it may be modified by The Perl Foundation in the future.
|
58
|
+
|
59
|
+
"Source" form means the source code, documentation source, and
|
60
|
+
configuration files for the Package.
|
61
|
+
|
62
|
+
"Compiled" form means the compiled bytecode, object code, binary,
|
63
|
+
or any other form resulting from mechanical transformation or
|
64
|
+
translation of the Source form.
|
65
|
+
|
66
|
+
|
67
|
+
Permission for Use and Modification Without Distribution
|
68
|
+
|
69
|
+
(1) You are permitted to use the Standard Version and create and use
|
70
|
+
Modified Versions for any purpose without restriction, provided that
|
71
|
+
you do not Distribute the Modified Version.
|
72
|
+
|
73
|
+
|
74
|
+
Permissions for Redistribution of the Standard Version
|
75
|
+
|
76
|
+
(2) You may Distribute verbatim copies of the Source form of the
|
77
|
+
Standard Version of this Package in any medium without restriction,
|
78
|
+
either gratis or for a Distributor Fee, provided that you duplicate
|
79
|
+
all of the original copyright notices and associated disclaimers. At
|
80
|
+
your discretion, such verbatim copies may or may not include a
|
81
|
+
Compiled form of the Package.
|
82
|
+
|
83
|
+
(3) You may apply any bug fixes, portability changes, and other
|
84
|
+
modifications made available from the Copyright Holder. The resulting
|
85
|
+
Package will still be considered the Standard Version, and as such
|
86
|
+
will be subject to the Original License.
|
87
|
+
|
88
|
+
|
89
|
+
Distribution of Modified Versions of the Package as Source
|
90
|
+
|
91
|
+
(4) You may Distribute your Modified Version as Source (either gratis
|
92
|
+
or for a Distributor Fee, and with or without a Compiled form of the
|
93
|
+
Modified Version) provided that you clearly document how it differs
|
94
|
+
from the Standard Version, including, but not limited to, documenting
|
95
|
+
any non-standard features, executables, or modules, and provided that
|
96
|
+
you do at least ONE of the following:
|
97
|
+
|
98
|
+
(a) make the Modified Version available to the Copyright Holder
|
99
|
+
of the Standard Version, under the Original License, so that the
|
100
|
+
Copyright Holder may include your modifications in the Standard
|
101
|
+
Version.
|
102
|
+
|
103
|
+
(b) ensure that installation of your Modified Version does not
|
104
|
+
prevent the user installing or running the Standard Version. In
|
105
|
+
addition, the Modified Version must bear a name that is different
|
106
|
+
from the name of the Standard Version.
|
107
|
+
|
108
|
+
(c) allow anyone who receives a copy of the Modified Version to
|
109
|
+
make the Source form of the Modified Version available to others
|
110
|
+
under
|
111
|
+
|
112
|
+
(i) the Original License or
|
113
|
+
|
114
|
+
(ii) a license that permits the licensee to freely copy,
|
115
|
+
modify and redistribute the Modified Version using the same
|
116
|
+
licensing terms that apply to the copy that the licensee
|
117
|
+
received, and requires that the Source form of the Modified
|
118
|
+
Version, and of any works derived from it, be made freely
|
119
|
+
available in that license fees are prohibited but Distributor
|
120
|
+
Fees are allowed.
|
121
|
+
|
122
|
+
|
123
|
+
Distribution of Compiled Forms of the Standard Version
|
124
|
+
or Modified Versions without the Source
|
125
|
+
|
126
|
+
(5) You may Distribute Compiled forms of the Standard Version without
|
127
|
+
the Source, provided that you include complete instructions on how to
|
128
|
+
get the Source of the Standard Version. Such instructions must be
|
129
|
+
valid at the time of your distribution. If these instructions, at any
|
130
|
+
time while you are carrying out such distribution, become invalid, you
|
131
|
+
must provide new instructions on demand or cease further distribution.
|
132
|
+
If you provide valid instructions or cease distribution within thirty
|
133
|
+
days after you become aware that the instructions are invalid, then
|
134
|
+
you do not forfeit any of your rights under this license.
|
135
|
+
|
136
|
+
(6) You may Distribute a Modified Version in Compiled form without
|
137
|
+
the Source, provided that you comply with Section 4 with respect to
|
138
|
+
the Source of the Modified Version.
|
139
|
+
|
140
|
+
|
141
|
+
Aggregating or Linking the Package
|
142
|
+
|
143
|
+
(7) You may aggregate the Package (either the Standard Version or
|
144
|
+
Modified Version) with other packages and Distribute the resulting
|
145
|
+
aggregation provided that you do not charge a licensing fee for the
|
146
|
+
Package. Distributor Fees are permitted, and licensing fees for other
|
147
|
+
components in the aggregation are permitted. The terms of this license
|
148
|
+
apply to the use and Distribution of the Standard or Modified Versions
|
149
|
+
as included in the aggregation.
|
150
|
+
|
151
|
+
(8) You are permitted to link Modified and Standard Versions with
|
152
|
+
other works, to embed the Package in a larger work of your own, or to
|
153
|
+
build stand-alone binary or bytecode versions of applications that
|
154
|
+
include the Package, and Distribute the result without restriction,
|
155
|
+
provided the result does not expose a direct interface to the Package.
|
156
|
+
|
157
|
+
|
158
|
+
Items That are Not Considered Part of a Modified Version
|
159
|
+
|
160
|
+
(9) Works (including, but not limited to, modules and scripts) that
|
161
|
+
merely extend or make use of the Package, do not, by themselves, cause
|
162
|
+
the Package to be a Modified Version. In addition, such works are not
|
163
|
+
considered parts of the Package itself, and are not subject to the
|
164
|
+
terms of this license.
|
165
|
+
|
166
|
+
|
167
|
+
General Provisions
|
168
|
+
|
169
|
+
(10) Any use, modification, and distribution of the Standard or
|
170
|
+
Modified Versions is governed by this Artistic License. By using,
|
171
|
+
modifying or distributing the Package, you accept this license. Do not
|
172
|
+
use, modify, or distribute the Package, if you do not accept this
|
173
|
+
license.
|
174
|
+
|
175
|
+
(11) If your Modified Version has been derived from a Modified
|
176
|
+
Version made by someone other than you, you are nevertheless required
|
177
|
+
to ensure that your Modified Version complies with the requirements of
|
178
|
+
this license.
|
179
|
+
|
180
|
+
(12) This license does not grant you the right to use any trademark,
|
181
|
+
service mark, tradename, or logo of the Copyright Holder.
|
182
|
+
|
183
|
+
(13) This license includes the non-exclusive, worldwide,
|
184
|
+
free-of-charge patent license to make, have made, use, offer to sell,
|
185
|
+
sell, import and otherwise transfer the Package with respect to any
|
186
|
+
patent claims licensable by the Copyright Holder that are necessarily
|
187
|
+
infringed by the Package. If you institute patent litigation
|
188
|
+
(including a cross-claim or counterclaim) against any party alleging
|
189
|
+
that the Package constitutes direct or contributory patent
|
190
|
+
infringement, then this Artistic License to you shall terminate on the
|
191
|
+
date that such litigation is filed.
|
192
|
+
|
193
|
+
(14) Disclaimer of Warranty:
|
194
|
+
THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
|
195
|
+
IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
|
196
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
197
|
+
NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
|
198
|
+
LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
|
199
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
200
|
+
DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
|
201
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
[![Code Climate](https://codeclimate.com/github/lmrodriguezr/gfa/badges/gpa.svg)](https://codeclimate.com/github/lmrodriguezr/gfa)
|
2
|
+
[![Test Coverage](https://codeclimate.com/github/lmrodriguezr/gfa/badges/coverage.svg)](https://codeclimate.com/github/lmrodriguezr/gfa/coverage)
|
3
|
+
[![Build Status](https://travis-ci.org/lmrodriguezr/gfa.svg?branch=master)](https://travis-ci.org/lmrodriguezr/gfa)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/gfa.svg)](https://badge.fury.io/rb/gfa)
|
5
|
+
|
6
|
+
# Graphical Fragment Assembly (GFA) for Ruby
|
7
|
+
|
8
|
+
This implementation follows the specifications of [GFA-spec][].
|
9
|
+
|
10
|
+
|
11
|
+
## Parsing GFA
|
12
|
+
|
13
|
+
To parse a file in GFA format:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require "gfa"
|
17
|
+
|
18
|
+
my_gfa = GFA.load("assembly.gfa")
|
19
|
+
```
|
20
|
+
|
21
|
+
To load GFA strings line-by-line:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require "gfa"
|
25
|
+
|
26
|
+
my_gfa = GFA.new
|
27
|
+
fh = File.open("assembly.gfa", "r")
|
28
|
+
fh.each do |ln|
|
29
|
+
my_gfa << ln
|
30
|
+
end
|
31
|
+
fh.close
|
32
|
+
```
|
33
|
+
|
34
|
+
|
35
|
+
## Saving GFA
|
36
|
+
|
37
|
+
After altering a GFA object, you can simply save it in a file as:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
my_gfa.save("alt-assembly.gfa")
|
41
|
+
```
|
42
|
+
|
43
|
+
Or line-by-line as:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
fh = File.open("alt-assembly.gfa", "w")
|
47
|
+
my_gfa.each_line do |ln|
|
48
|
+
fh.puts ln
|
49
|
+
end
|
50
|
+
fh.close
|
51
|
+
```
|
52
|
+
|
53
|
+
|
54
|
+
## Visualizing GFA
|
55
|
+
|
56
|
+
Any `GFA` object can be exported as an [`RGL`][rgl] graph using the methods
|
57
|
+
`adjacency_graph` and `implicit_graph`. For example, you can render
|
58
|
+
[tiny.gfa](https://github.com/lmrodriguezr/gfa/raw/master/data/tiny.gfa):
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
require "gfa"
|
62
|
+
require "rgl/dot"
|
63
|
+
|
64
|
+
my_gfa = GFA.load("data/tiny.gfa")
|
65
|
+
dg = my_gfa.implicit_graph
|
66
|
+
dg.write_to_graphic_file("jpg")
|
67
|
+
```
|
68
|
+
|
69
|
+
![tiny_dg](https://github.com/lmrodriguezr/gfa/raw/master/data/tiny.jpg)
|
70
|
+
|
71
|
+
If you don't care about orientation, you can also build an undirected graph
|
72
|
+
without orientation:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
ug = my_gfa.implicit_graph(orient:false)
|
76
|
+
ug.write_to_graphic_file("jpg")
|
77
|
+
```
|
78
|
+
|
79
|
+
![tiny_ug](https://github.com/lmrodriguezr/gfa/raw/master/data/tiny_undirected.jpg)
|
80
|
+
|
81
|
+
|
82
|
+
# Installation
|
83
|
+
|
84
|
+
```
|
85
|
+
gem install gfa
|
86
|
+
```
|
87
|
+
|
88
|
+
|
89
|
+
# Author
|
90
|
+
|
91
|
+
[Luis M. Rodriguez-R][lrr].
|
92
|
+
|
93
|
+
|
94
|
+
# License
|
95
|
+
|
96
|
+
[Artistic License 2.0](LICENSE).
|
97
|
+
|
98
|
+
[GFA-spec]: https://github.com/pmelsted/GFA-spec
|
99
|
+
[lrr]: http://lmrodriguezr.github.io/
|
100
|
+
[rgl]: https://github.com/monora/rgl
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), "lib")
|
4
|
+
|
5
|
+
require "gfa/version"
|
6
|
+
|
7
|
+
SOURCES = FileList["lib/**/*.rb"]
|
8
|
+
|
9
|
+
desc "Default Task"
|
10
|
+
task :default => :test
|
11
|
+
|
12
|
+
Rake::TestTask.new do |t|
|
13
|
+
t.libs << "test"
|
14
|
+
t.pattern = "test/*_test.rb"
|
15
|
+
t.verbose = true
|
16
|
+
end
|
data/lib/gfa.rb
ADDED
data/lib/gfa/common.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require "gfa/version"
|
2
|
+
require "gfa/record"
|
3
|
+
require "gfa/field"
|
4
|
+
|
5
|
+
class GFA
|
6
|
+
|
7
|
+
# Class-level
|
8
|
+
def self.assert_format(value, regex, message)
|
9
|
+
unless value =~ regex
|
10
|
+
raise "#{message}: #{value}."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Instance-level
|
15
|
+
attr :gfa_version, :records
|
16
|
+
GFA::Record.TYPES.each do |r_type|
|
17
|
+
plural = "#{r_type.downcase}s"
|
18
|
+
singular = "#{r_type.downcase}"
|
19
|
+
define_method(plural) do
|
20
|
+
records[r_type]
|
21
|
+
end
|
22
|
+
define_method(singular) do |k|
|
23
|
+
records[r_type][k]
|
24
|
+
end
|
25
|
+
define_method("add_#{singular}") do |v|
|
26
|
+
@records[r_type] << v
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@records = {}
|
32
|
+
GFA::Record.TYPES.each { |t| @records[t] = [] }
|
33
|
+
end
|
34
|
+
|
35
|
+
def empty?
|
36
|
+
records.values.all? { |r| r.empty? }
|
37
|
+
end
|
38
|
+
|
39
|
+
def eql?(gfa)
|
40
|
+
records == gfa.records
|
41
|
+
end
|
42
|
+
|
43
|
+
alias == eql?
|
44
|
+
|
45
|
+
end
|
data/lib/gfa/field.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
class GFA::Field
|
2
|
+
|
3
|
+
# Class-level
|
4
|
+
|
5
|
+
CODES = {
|
6
|
+
:A => :Char,
|
7
|
+
:i => :SigInt,
|
8
|
+
:f => :Float,
|
9
|
+
:Z => :String,
|
10
|
+
:H => :Hex,
|
11
|
+
:B => :NumArray
|
12
|
+
}
|
13
|
+
TYPES = CODES.values
|
14
|
+
|
15
|
+
TYPES.each { |t| require "gfa/field/#{t.downcase}" }
|
16
|
+
|
17
|
+
[:CODES, :TYPES].each do |x|
|
18
|
+
define_singleton_method(x) { const_get(x) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.code_class(code)
|
22
|
+
name = CODES[code.to_sym]
|
23
|
+
raise "Unknown field type: #{code}." if name.nil?
|
24
|
+
name_class(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.name_class(name)
|
28
|
+
const_get(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Instance-level
|
32
|
+
|
33
|
+
attr :value
|
34
|
+
|
35
|
+
def type ; CODES[code] ; end
|
36
|
+
|
37
|
+
def code ; self.class::CODE ; end
|
38
|
+
|
39
|
+
def regex ; self.class::REGEX ; end
|
40
|
+
|
41
|
+
def to_s(with_type=true)
|
42
|
+
"#{"#{code}:" if with_type}#{value}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def hash
|
46
|
+
value.hash
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class GFA::Field::NumArray < GFA::Field
|
2
|
+
CODE = :B
|
3
|
+
REGEX = /^[cCsSiIf](,[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)+$/
|
4
|
+
|
5
|
+
def initialize(f)
|
6
|
+
GFA.assert_format(f, regex, "Bad #{type}")
|
7
|
+
@value = f
|
8
|
+
end
|
9
|
+
|
10
|
+
def modifier ; value[0] ; end
|
11
|
+
|
12
|
+
def array ; value[2..-1].split(/,/) ; end
|
13
|
+
|
14
|
+
alias as_a array
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class GFA
|
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
|
+
def each_line(&blk)
|
10
|
+
set_version_header("1.0") if gfa_version.nil?
|
11
|
+
GFA::Record.TYPES.each do |r_type|
|
12
|
+
records[r_type].each do |record|
|
13
|
+
blk[record.to_s]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
def set_version_header(v)
|
18
|
+
unset_version
|
19
|
+
@records[:Header] << GFA::Record::Header.new("VN:Z:#{v}")
|
20
|
+
@gfa_version = v
|
21
|
+
end
|
22
|
+
def unset_version
|
23
|
+
@records[:Header].delete_if { |o| not o.fields[:VN].nil? }
|
24
|
+
@gfa_version = nil
|
25
|
+
end
|
26
|
+
def to_s
|
27
|
+
o = ""
|
28
|
+
each_line{ |ln| o += ln + "\n" }
|
29
|
+
o
|
30
|
+
end
|
31
|
+
end
|
data/lib/gfa/graph.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require "rgl/adjacency"
|
2
|
+
require "rgl/implicit"
|
3
|
+
|
4
|
+
class GFA
|
5
|
+
|
6
|
+
##
|
7
|
+
# Generates a RGL::ImplicitGraph object describing the links in the GFA.
|
8
|
+
# The +opts+ argument is a hash with any of the following key-value pairs:
|
9
|
+
#
|
10
|
+
# * :orient => bool. If false, ignores strandness of the links. By default
|
11
|
+
# true.
|
12
|
+
# * :directed => bool. If false, ignores direction of the links. By defaut
|
13
|
+
# the same value as :orient.
|
14
|
+
def implicit_graph(opts={})
|
15
|
+
rgl_implicit_graph(opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Generates a RGL::DirectedAdjacencyGraph or RGL::AdjacencyGraph object.
|
20
|
+
# The +opts+ argument is a hash with the same supported key-value pairs as
|
21
|
+
# in #implicit_graph.
|
22
|
+
def adjacency_graph(opts={})
|
23
|
+
implicit_graph(opts).to_adjacency
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def segment_names_with_orient
|
29
|
+
segments.flat_map do |s|
|
30
|
+
%w[+ -].map{ |orient| GFA::GraphVertex.idx(s, orient) }
|
31
|
+
end.to_set
|
32
|
+
end
|
33
|
+
|
34
|
+
def segment_names
|
35
|
+
segments.map do |s|
|
36
|
+
GFA::GraphVertex.idx(s, nil)
|
37
|
+
end.to_set
|
38
|
+
end
|
39
|
+
|
40
|
+
def rgl_implicit_graph(opts)
|
41
|
+
opts = rgl_implicit_options(opts)
|
42
|
+
RGL::ImplicitGraph.new do |g|
|
43
|
+
g.vertex_iterator do |b|
|
44
|
+
(opts[:orient] ? segment_names_with_orient :
|
45
|
+
segment_names).each(&b)
|
46
|
+
end
|
47
|
+
g.adjacent_iterator do |x,b|
|
48
|
+
rgl_implicit_adjacent_iterator(x,b,opts)
|
49
|
+
end
|
50
|
+
g.directed = opts[:directed]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def rgl_implicit_options(opts)
|
55
|
+
opts[:orient] = true if opts[:orient].nil?
|
56
|
+
opts[:directed] = opts[:orient] if opts[:directed].nil?
|
57
|
+
opts
|
58
|
+
end
|
59
|
+
|
60
|
+
def rgl_implicit_adjacent_iterator(x,b,opts)
|
61
|
+
links.each do |l|
|
62
|
+
if l.from?(x.segment, x.orient)
|
63
|
+
orient = opts[:orient] ? l.to_orient : nil
|
64
|
+
b.call(GFA::GraphVertex.idx(l.to, orient))
|
65
|
+
elsif opts[:orient] and l.to?(x.segment, orient_rc(x.orient))
|
66
|
+
orient = orient_rc(l.from_orient.value)
|
67
|
+
b.call(GFA::GraphVertex.idx(l.from, orient))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def orient_rc(o) o=="+" ? "-" : "+" ; end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
class GFA::GraphVertex # :nodoc:
|
78
|
+
|
79
|
+
# Class-level
|
80
|
+
@@idx = {}
|
81
|
+
def self.idx(segment, orient)
|
82
|
+
n = GFA::GraphVertex.new(segment, orient)
|
83
|
+
@@idx[n.to_s] ||= n
|
84
|
+
@@idx[n.to_s]
|
85
|
+
end
|
86
|
+
|
87
|
+
# Instance-level
|
88
|
+
attr :segment, :orient
|
89
|
+
|
90
|
+
def initialize(segment, orient)
|
91
|
+
@segment = segment.is_a?(GFA::Record::Segment) ? segment.name.value :
|
92
|
+
segment.is_a?(GFA::Field) ? segment.value : segment
|
93
|
+
@orient = orient.is_a?(GFA::Field) ? orient.value : orient
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_s
|
97
|
+
"#{segment}#{orient}"
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
data/lib/gfa/parser.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require "gfa/record"
|
2
|
+
|
3
|
+
class GFA
|
4
|
+
# Class-level
|
5
|
+
MIN_VERSION = "1.0"
|
6
|
+
MAX_VERSION = "1.0"
|
7
|
+
|
8
|
+
def self.load(file)
|
9
|
+
gfa = GFA.new
|
10
|
+
fh = File.open(file, "r")
|
11
|
+
fh.each { |ln| gfa << ln }
|
12
|
+
fh.close
|
13
|
+
gfa
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.supported_version?(v)
|
17
|
+
v.to_f >= MIN_VERSION.to_f and v.to_f <= MAX_VERSION.to_f
|
18
|
+
end
|
19
|
+
|
20
|
+
# Instance-level
|
21
|
+
def <<(obj)
|
22
|
+
obj = parse_line(obj) unless obj.is_a? GFA::Record
|
23
|
+
return if obj.nil? or obj.empty?
|
24
|
+
@records[obj.type] << obj
|
25
|
+
if obj.type==:Header and not obj.fields[:VN].nil?
|
26
|
+
set_gfa_version(obj.fields[:VN].value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_gfa_version(v)
|
31
|
+
@gfa_version = v
|
32
|
+
raise "GFA version currently unsupported: #{v}." unless
|
33
|
+
GFA::supported_version? gfa_version
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def parse_line(ln)
|
39
|
+
ln.chomp!
|
40
|
+
return nil if ln =~ /^\s*$/
|
41
|
+
cols = ln.split("\t")
|
42
|
+
GFA::Record.code_class(cols.shift).new(*cols)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/gfa/record.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
class GFA::Record
|
2
|
+
|
3
|
+
# Class-level
|
4
|
+
|
5
|
+
CODES = {
|
6
|
+
:H => :Header,
|
7
|
+
:S => :Segment,
|
8
|
+
:L => :Link,
|
9
|
+
:C => :Containment,
|
10
|
+
:P => :Path
|
11
|
+
}
|
12
|
+
REQ_FIELDS = []
|
13
|
+
OPT_FIELDS = {}
|
14
|
+
TYPES = CODES.values
|
15
|
+
|
16
|
+
TYPES.each { |t| require "gfa/record/#{t.downcase}" }
|
17
|
+
|
18
|
+
[:CODES, :REQ_FIELDS, :OPT_FIELDS, :TYPES].each do |x|
|
19
|
+
define_singleton_method(x) { const_get(x) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.code_class(code)
|
23
|
+
name = CODES[code.to_sym]
|
24
|
+
raise "Unknown record type: #{code}." if name.nil?
|
25
|
+
name_class(name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.name_class(name)
|
29
|
+
const_get(name)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Instance-level
|
33
|
+
|
34
|
+
attr :fields
|
35
|
+
|
36
|
+
def [](k) fields[k] ; end
|
37
|
+
|
38
|
+
def type ; CODES[code] ; end
|
39
|
+
|
40
|
+
def code ; self.class.const_get(:CODE) ; end
|
41
|
+
|
42
|
+
def empty? ; fields.empty? ; end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
o = [code.to_s]
|
46
|
+
self.class.REQ_FIELDS.each_index do |i|
|
47
|
+
o << fields[i+2].to_s(false)
|
48
|
+
end
|
49
|
+
fields.each do |k,v|
|
50
|
+
next if k.is_a? Integer
|
51
|
+
o << "#{k}:#{v}"
|
52
|
+
end
|
53
|
+
o.join("\t")
|
54
|
+
end
|
55
|
+
|
56
|
+
def hash
|
57
|
+
{code => fields}.hash
|
58
|
+
end
|
59
|
+
|
60
|
+
def eql?(rec)
|
61
|
+
hash == rec.hash
|
62
|
+
end
|
63
|
+
|
64
|
+
alias == eql?
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def add_field(f_tag, f_type, f_value, format=nil)
|
69
|
+
unless format.nil?
|
70
|
+
msg = (f_tag.is_a?(Integer) ? "column #{f_tag}" : "#{f_tag} field")
|
71
|
+
GFA.assert_format(f_value, format, "Bad #{type} #{msg}")
|
72
|
+
end
|
73
|
+
@fields[ f_tag ] = GFA::Field.code_class(f_type).new(f_value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_opt_field(f, known)
|
77
|
+
m = /^([A-Za-z]+):([A-Za-z]+):(.*)$/.match(f) or
|
78
|
+
raise "Cannot parse field: '#{f}'."
|
79
|
+
f_tag = m[1].to_sym
|
80
|
+
f_type = m[2].to_sym
|
81
|
+
f_value = m[3]
|
82
|
+
raise "Unknown reserved tag #{f_tag} for a #{type} record." if
|
83
|
+
known[f_tag].nil? and f_tag =~ /^[A-Z]+$/
|
84
|
+
raise "Wrong field type #{f_type} for a #{f_tag} tag," +
|
85
|
+
" expected #{known[f_tag]}" unless
|
86
|
+
known[f_tag].nil? or known[f_tag] == f_type
|
87
|
+
add_field(f_tag, f_type, f_value)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class GFA::Record::Containment < GFA::Record
|
2
|
+
CODE = :C
|
3
|
+
REQ_FIELDS = [:from, :from_orient, :to, :to_orient, :pos, :overlap]
|
4
|
+
OPT_FIELDS = {
|
5
|
+
:RC => :i,
|
6
|
+
:NM => :i
|
7
|
+
}
|
8
|
+
|
9
|
+
REQ_FIELDS.each_index do |i|
|
10
|
+
define_method(REQ_FIELDS[i]) { fields[i+2] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(from, from_orient, to, to_orient, pos, overlap, *opt_fields)
|
14
|
+
@fields = {}
|
15
|
+
add_field(2, :Z, from, /^[!-)+-<>-~][!-~]*$/)
|
16
|
+
add_field(3, :Z, from_orient, /^+|-$/)
|
17
|
+
add_field(4, :Z, to, /^[!-)+-<>-~][!-~]*$/)
|
18
|
+
add_field(5, :Z, to_orient, /^+|-$/)
|
19
|
+
add_field(6, :i, pos, /^[0-9]*$/)
|
20
|
+
add_field(7, :Z, overlap, /^\*|([0-9]+[MIDNSHPX=])+$/)
|
21
|
+
opt_fields.each{ |f| add_opt_field(f, OPT_FIELDS) }
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class GFA::Record::Link < GFA::Record
|
2
|
+
CODE = :L
|
3
|
+
REQ_FIELDS = [:from, :from_orient, :to, :to_orient, :overlap]
|
4
|
+
OPT_FIELDS = {
|
5
|
+
:MQ => :i,
|
6
|
+
:NM => :i,
|
7
|
+
:EC => :i,
|
8
|
+
:FC => :i,
|
9
|
+
:KC => :i
|
10
|
+
}
|
11
|
+
|
12
|
+
REQ_FIELDS.each_index do |i|
|
13
|
+
define_method(REQ_FIELDS[i]) { fields[i+2] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(from, from_orient, to, to_orient, overlap, *opt_fields)
|
17
|
+
@fields = {}
|
18
|
+
add_field(2, :Z, from, /^[!-)+-<>-~][!-~]*$/)
|
19
|
+
add_field(3, :Z, from_orient, /^+|-$/)
|
20
|
+
add_field(4, :Z, to, /^[!-)+-<>-~][!-~]*$/)
|
21
|
+
add_field(5, :Z, to_orient, /^+|-$/)
|
22
|
+
add_field(6, :Z, overlap, /^\*|([0-9]+[MIDNSHPX=])+$/)
|
23
|
+
opt_fields.each{ |f| add_opt_field(f, OPT_FIELDS) }
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def from?(segment, orient=nil)
|
28
|
+
links_from_to?(segment, orient, true)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to?(segment, orient=nil)
|
32
|
+
links_from_to?(segment, orient, false)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def links_from_to?(segment, orient, from)
|
38
|
+
segment = segment_name(segment)
|
39
|
+
orient = orient.value if orient.is_a? GFA::Field
|
40
|
+
base_k = from ? 2 : 4
|
41
|
+
segment==fields[base_k].value and
|
42
|
+
(orient.nil? or orient==fields[base_k + 1].value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def segment_name(segment)
|
46
|
+
segment.is_a?(GFA::Record::Segment) ? segment.name.value :
|
47
|
+
segment.is_a?(GFA::Field) ? segment.value : segment
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class GFA::Record::Path < GFA::Record
|
2
|
+
CODE = :P
|
3
|
+
REQ_FIELDS = [:path_name, :segment_name, :cigar]
|
4
|
+
OPT_FIELDS = {}
|
5
|
+
|
6
|
+
REQ_FIELDS.each_index do |i|
|
7
|
+
define_method(REQ_FIELDS[i]) { fields[i+2] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(path_name, segment_name, cigar, *opt_fields)
|
11
|
+
@fields = {}
|
12
|
+
add_field(2, :Z, path_name, /^[!-)+-<>-~][!-~]*$/)
|
13
|
+
add_field(3, :Z, segment_name, /^[!-)+-<>-~][!-~]*$/)
|
14
|
+
add_field(4, :Z, cigar, /^\*|([0-9]+[MIDNSHPX=])+$/)
|
15
|
+
opt_fields.each{ |f| add_opt_field(f, OPT_FIELDS) }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class GFA::Record::Segment < GFA::Record
|
2
|
+
CODE = :S
|
3
|
+
REQ_FIELDS = [:name, :sequence]
|
4
|
+
OPT_FIELDS = {
|
5
|
+
:LN => :i,
|
6
|
+
:RC => :i,
|
7
|
+
:FC => :i,
|
8
|
+
:KC => :i
|
9
|
+
}
|
10
|
+
|
11
|
+
REQ_FIELDS.each_index do |i|
|
12
|
+
define_method(REQ_FIELDS[i]) { fields[i+2] }
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(name, sequence, *opt_fields)
|
16
|
+
@fields = {}
|
17
|
+
add_field(2, :Z, name, /^[!-)+-<>-~][!-~]*$/)
|
18
|
+
add_field(3, :Z, sequence, /^\*|[A-Za-z=.]+$/)
|
19
|
+
opt_fields.each{ |f| add_opt_field(f, OPT_FIELDS) }
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/gfa/version.rb
ADDED
data/test/common_test.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CommonTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_assert_format
|
6
|
+
assert_raise do
|
7
|
+
GFA.assert_format("tsooq", /^.$/, "Not a char")
|
8
|
+
end
|
9
|
+
assert_nothing_raised do
|
10
|
+
GFA.assert_format("z", /^.$/, "Not a char")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_empty
|
15
|
+
gfa = GFA.new
|
16
|
+
assert(gfa.empty?)
|
17
|
+
assert_equal(GFA.new, gfa)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_record_getters
|
21
|
+
gfa = GFA.new
|
22
|
+
assert_respond_to(gfa, :headers)
|
23
|
+
assert_equal([], gfa.links)
|
24
|
+
assert_nil( gfa.segment(0) )
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_record_setters
|
28
|
+
gfa = GFA.new
|
29
|
+
assert_respond_to(gfa, :add_path)
|
30
|
+
gfa.add_containment("zooq")
|
31
|
+
assert_equal("zooq", gfa.records[:Containment].first)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/test/field_test.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class FieldTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_char
|
6
|
+
f = GFA::Field::Char.new("%")
|
7
|
+
assert_equal("%", f.value)
|
8
|
+
assert_raise do
|
9
|
+
GFA::Field::Char.new(" ")
|
10
|
+
end
|
11
|
+
assert_raise do
|
12
|
+
GFA::Field::Char.new("")
|
13
|
+
end
|
14
|
+
assert_raise do
|
15
|
+
GFA::Field::Char.new("^.^")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_sigint
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_float
|
23
|
+
f = GFA::Field::Float.new("1.3e-5")
|
24
|
+
assert_equal(1.3e-5, f.value)
|
25
|
+
assert_raise do
|
26
|
+
GFA::Field::Float.new("e-5")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_string
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_hex
|
34
|
+
f = GFA::Field::Hex.new("C3F0")
|
35
|
+
assert_equal("C3F0", f.value)
|
36
|
+
assert_raise do
|
37
|
+
GFA::Field::Hex.new("C3PO")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_numarray
|
42
|
+
f = GFA::Field::NumArray.new("i,1,2,3")
|
43
|
+
assert_equal(%w[1 2 3], f.array)
|
44
|
+
assert_equal("i", f.modifier)
|
45
|
+
assert_raise do
|
46
|
+
GFA::Field::NumArray.new("c,1,e,3")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/test/parser_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "gfa/parser"
|
3
|
+
|
4
|
+
class ParserTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_load
|
7
|
+
sample_f = File.expand_path("../fixtures/sample.gfa",__FILE__)
|
8
|
+
assert_respond_to(GFA, :load)
|
9
|
+
pre_fhs = ObjectSpace.each_object(IO).count{ |i| not i.closed? }
|
10
|
+
sample = GFA.load(sample_f)
|
11
|
+
post_fhs = ObjectSpace.each_object(IO).count{ |i| not i.closed? }
|
12
|
+
assert_equal(pre_fhs, post_fhs)
|
13
|
+
assert_equal(1, sample.headers.size)
|
14
|
+
assert_equal(6, sample.segments.size)
|
15
|
+
assert_equal(4, sample.links.size)
|
16
|
+
assert(sample.containments.empty?)
|
17
|
+
assert(sample.paths.empty?)
|
18
|
+
assert_respond_to(sample, :records)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_version_suppport
|
22
|
+
gfa = GFA.new
|
23
|
+
assert_raise { gfa.set_gfa_version("0.9") }
|
24
|
+
assert_raise { gfa.set_gfa_version("1.1") }
|
25
|
+
assert_nothing_raised { gfa.set_gfa_version("1.0") }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_line_by_line
|
29
|
+
gfa = GFA.new
|
30
|
+
assert_respond_to(gfa, :<<)
|
31
|
+
# Empty
|
32
|
+
gfa << " "
|
33
|
+
assert(gfa.empty?)
|
34
|
+
gfa << "H"
|
35
|
+
assert(gfa.empty?)
|
36
|
+
# Segment
|
37
|
+
assert_equal(0, gfa.segments.size)
|
38
|
+
gfa << "S\t1\tACTG"
|
39
|
+
assert(!gfa.empty?)
|
40
|
+
assert_equal(1, gfa.segments.size)
|
41
|
+
# Version
|
42
|
+
assert_nil(gfa.gfa_version)
|
43
|
+
gfa << GFA::Record::Header.new("VN:Z:1.0")
|
44
|
+
assert_equal("1.0", gfa.gfa_version)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/test/record_test.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class RecordTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
$rec_h = GFA::Record::Header.new("VN:Z:1.0")
|
7
|
+
$rec_p = GFA::Record::Path.new("a", "b", "*")
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_class_methods
|
11
|
+
assert_respond_to(GFA::Record, :CODES)
|
12
|
+
assert_respond_to(GFA::Record, :TYPES)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_to_s
|
16
|
+
assert_equal("H\tVN:Z:1.0", $rec_h.to_s)
|
17
|
+
assert_equal("P\ta\tb\t*", $rec_p.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_hash
|
21
|
+
other_h = GFA::Record::Header.new("VN:Z:1.0")
|
22
|
+
assert_equal($rec_h.hash, other_h.hash)
|
23
|
+
assert_equal($rec_h, other_h)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_reserved_fields
|
27
|
+
assert_nothing_raised do
|
28
|
+
GFA::Record::Path.new("a", "b", "*", "smile:Z:(-:")
|
29
|
+
GFA::Record::Header.new("Ooo:i:3")
|
30
|
+
GFA::Record::Header.new("oOo:i:2")
|
31
|
+
GFA::Record::Header.new("ooO:i:1")
|
32
|
+
end
|
33
|
+
assert_raise do
|
34
|
+
GFA::Record::Header.new("OOPS:i:3")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_header
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_segment
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_link
|
45
|
+
l = GFA::Record::Link.new("Seg1","+","Seg2","-","*","NM:i:123")
|
46
|
+
assert_equal("+", l.from_orient.value)
|
47
|
+
assert_equal(123, l[:NM].value)
|
48
|
+
assert(l.from?("Seg1"))
|
49
|
+
assert(l.from?("Seg1", "+"))
|
50
|
+
assert(l.to?("Seg2", "-"))
|
51
|
+
assert(! l.from?("Seg2"))
|
52
|
+
assert(! l.from?("Seg1", "-"))
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_containment
|
56
|
+
assert_raise do
|
57
|
+
GFA::Record::Containment.new("Seg1","+","Seg2","-","*","RC:i:123")
|
58
|
+
end
|
59
|
+
c = GFA::Record::Containment.new("Seg1","+","Seg2","-","10","*","RC:i:123")
|
60
|
+
assert_equal("+", c.from_orient.value)
|
61
|
+
assert_equal(10, c.pos.value)
|
62
|
+
assert_equal(123, c[:RC].value)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_path
|
66
|
+
assert_raise do
|
67
|
+
GFA::Record::Path.new("PathA","SegB\t","*")
|
68
|
+
end
|
69
|
+
p = GFA::Record::Path.new("PathA","SegB","*")
|
70
|
+
assert_equal("*", p.cigar.value)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gfa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luis M. Rodriguez-R
|
@@ -56,13 +56,48 @@ description: GFA is a graph representation of fragment assemblies
|
|
56
56
|
email: lmrodriguezr@gmail.com
|
57
57
|
executables: []
|
58
58
|
extensions: []
|
59
|
-
extra_rdoc_files:
|
60
|
-
|
59
|
+
extra_rdoc_files:
|
60
|
+
- README.md
|
61
|
+
files:
|
62
|
+
- lib/gfa/common.rb
|
63
|
+
- lib/gfa/field/char.rb
|
64
|
+
- lib/gfa/field/float.rb
|
65
|
+
- lib/gfa/field/hex.rb
|
66
|
+
- lib/gfa/field/numarray.rb
|
67
|
+
- lib/gfa/field/sigint.rb
|
68
|
+
- lib/gfa/field/string.rb
|
69
|
+
- lib/gfa/field.rb
|
70
|
+
- lib/gfa/generator.rb
|
71
|
+
- lib/gfa/graph.rb
|
72
|
+
- lib/gfa/parser.rb
|
73
|
+
- lib/gfa/record/containment.rb
|
74
|
+
- lib/gfa/record/header.rb
|
75
|
+
- lib/gfa/record/link.rb
|
76
|
+
- lib/gfa/record/path.rb
|
77
|
+
- lib/gfa/record/segment.rb
|
78
|
+
- lib/gfa/record.rb
|
79
|
+
- lib/gfa/version.rb
|
80
|
+
- lib/gfa.rb
|
81
|
+
- test/common_test.rb
|
82
|
+
- test/field_test.rb
|
83
|
+
- test/parser_test.rb
|
84
|
+
- test/record_test.rb
|
85
|
+
- test/test_helper.rb
|
86
|
+
- Gemfile
|
87
|
+
- Rakefile
|
88
|
+
- README.md
|
89
|
+
- LICENSE
|
61
90
|
homepage: https://github.com/lmrodriguezr/gfa
|
62
91
|
licenses: []
|
63
92
|
metadata: {}
|
64
93
|
post_install_message:
|
65
|
-
rdoc_options:
|
94
|
+
rdoc_options:
|
95
|
+
- lib
|
96
|
+
- README.md
|
97
|
+
- --main
|
98
|
+
- README.md
|
99
|
+
- --title
|
100
|
+
- Graphical Fragment Assembly (GFA) for Ruby
|
66
101
|
require_paths:
|
67
102
|
- lib
|
68
103
|
required_ruby_version: !ruby/object:Gem::Requirement
|