gfa 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8388ee28f1d71339d701b32e2a4fa1538b0f391f
4
- data.tar.gz: 520590efdc7170cf805db8427574e6e6fb5a8ac1
2
+ SHA256:
3
+ metadata.gz: cde4a3e432409c7a2967832dcebd502ddc54b1f6cb25856b6d9d21ce53f67b32
4
+ data.tar.gz: 91213d63365dd3608c28e30115cbfc8621e78bbe34936832bcee2ac7e6f460fb
5
5
  SHA512:
6
- metadata.gz: c8e8366d01006fbffc22ae49f3b4d619d8e8fbf25ef2c6173b427f05382a28c8a9efd7798f791d05c890e3057d3115ca8d3a6bc6d330551bf0915569c89ecc5c
7
- data.tar.gz: c6bcd711d7841585e6452cca87564b5d2e41a673e1bc4869df632db6193b928bbc6374ca370d8033db8df70e377234f3aa0a5f3a9ae96c56f053b771dff78060
6
+ metadata.gz: 321634c28ec8927bd38286a84a02783b9f915dcbabb7941233583dda7f41b66e952ff9611c9158bd7baca09d7d3d6c254a036f1c9f2169e5e24e6e964d292e71
7
+ data.tar.gz: 3698d16ab5953ffd70bf2c102d154bc1f61e5a13a752bc317a756df13762c3668c1bf6e8144821e53e395783f36c45185249c7fc206694be19145200310c3f48
data/Gemfile CHANGED
@@ -1,3 +1,9 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
  gemspec
3
- gem "codeclimate-test-reporter", group: :test, require: nil
3
+
4
+ group :test do
5
+ gem "simplecov"
6
+ gem "codeclimate-test-reporter", "~> 1.0.0"
7
+ end
8
+
9
+ gem 'rake', '~> 13.0'
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
- The Artistic License 2.0
1
+ The Artistic License 2.0
2
2
 
3
- Copyright (c) 2016 Luis M Rodriguez-R
3
+ Copyright (c) 2016-2023 Luis M Rodriguez-R
4
4
 
5
5
  Everyone is permitted to copy and distribute verbatim copies
6
6
  of this license document, but changing it is not allowed.
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 "gfa"
16
+ require 'gfa'
17
17
 
18
- my_gfa = GFA.load("assembly.gfa")
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 "gfa"
24
+ require 'gfa'
25
25
 
26
26
  my_gfa = GFA.new
27
- fh = File.open("assembly.gfa", "r")
27
+ fh = File.open('assembly.gfa', 'r')
28
28
  fh.each do |ln|
29
- my_gfa << ln
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("alt-assembly.gfa")
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("alt-assembly.gfa", "w")
46
+ fh = File.open('alt-assembly.gfa', 'w')
47
47
  my_gfa.each_line do |ln|
48
- fh.puts ln
48
+ fh.puts ln
49
49
  end
50
50
  fh.close
51
51
  ```
@@ -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]: http://lmrodriguezr.github.io/
107
+ [lrr]: https://rodriguez-r.com/
100
108
  [rgl]: https://github.com/monora/rgl
data/Rakefile CHANGED
@@ -1,16 +1,17 @@
1
- require "rake/testtask"
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
2
3
 
3
- $:.unshift File.join(File.dirname(__FILE__), "lib")
4
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
4
5
 
5
- require "gfa/version"
6
+ require 'gfa/version'
6
7
 
7
- SOURCES = FileList["lib/**/*.rb"]
8
+ SOURCES = FileList['lib/**/*.rb']
8
9
 
9
- desc "Default Task"
10
+ desc 'Default Task'
10
11
  task :default => :test
11
12
 
12
13
  Rake::TestTask.new do |t|
13
- t.libs << "test"
14
- t.pattern = "test/*_test.rb"
15
- t.verbose = true
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,39 @@
1
- require "gfa/version"
2
- require "gfa/record"
3
- require "gfa/field"
1
+ require 'gfa/version'
2
+ require 'gfa/record'
3
+ require 'gfa/field'
4
4
 
5
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
-
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
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
26
+ @records = {}
27
+ GFA::Record.TYPES.each { |t| @records[t] = [] }
28
+ end
29
+
30
+ def empty?
31
+ records.empty? || records.values.all?(&:empty?)
32
+ end
33
+
34
+ def eql?(gfa)
35
+ records == gfa.records
36
+ end
37
+
38
+ alias == eql?
45
39
  end
@@ -6,5 +6,4 @@ class GFA::Field::Char < GFA::Field
6
6
  GFA.assert_format(f, regex, "Bad #{type}")
7
7
  @value = f
8
8
  end
9
-
10
9
  end
@@ -6,5 +6,4 @@ class GFA::Field::Float < GFA::Field
6
6
  GFA.assert_format(f, regex, "Bad #{type}")
7
7
  @value = f.to_f
8
8
  end
9
-
10
9
  end
data/lib/gfa/field/hex.rb CHANGED
@@ -6,5 +6,4 @@ class GFA::Field::Hex < GFA::Field
6
6
  GFA.assert_format(f, regex, "Bad #{type}")
7
7
  @value = f
8
8
  end
9
-
10
9
  end
@@ -0,0 +1,9 @@
1
+ class GFA::Field::Json < GFA::Field
2
+ CODE = :J
3
+ REGEX = /^[ !-~]+$/
4
+
5
+ def initialize(f)
6
+ GFA.assert_format(f, regex, "Bad #{type}")
7
+ @value = f
8
+ end
9
+ end
@@ -10,7 +10,15 @@ class GFA::Field::NumArray < GFA::Field
10
10
  def modifier ; value[0] ; end
11
11
 
12
12
  def array ; value[2..-1].split(/,/) ; end
13
-
13
+
14
14
  alias as_a array
15
15
 
16
+ def number_type
17
+ {
18
+ c: 'int8_t', C: 'uint8_t',
19
+ s: 'int16_t', S: 'uint16_t',
20
+ i: 'int32_t', I: 'uint32_t',
21
+ f: 'float'
22
+ }[modifier.to_sym]
23
+ end
16
24
  end
@@ -1,10 +1,9 @@
1
1
  class GFA::Field::SigInt < GFA::Field
2
2
  CODE = :i
3
3
  REGEX = /^[-+]?[0-9]+$/
4
-
4
+
5
5
  def initialize(f)
6
6
  GFA.assert_format(f, regex, "Bad #{type}")
7
7
  @value = f.to_i
8
8
  end
9
-
10
9
  end
@@ -1,10 +1,9 @@
1
1
  class GFA::Field::String < GFA::Field
2
2
  CODE = :Z
3
3
  REGEX = /^[ !-~]+$/
4
-
4
+
5
5
  def initialize(f)
6
6
  GFA.assert_format(f, regex, "Bad #{type}")
7
7
  @value = f
8
8
  end
9
-
10
9
  end
data/lib/gfa/field.rb CHANGED
@@ -1,17 +1,15 @@
1
1
  class GFA::Field
2
-
3
2
  # Class-level
4
-
5
3
  CODES = {
6
- :A => :Char,
7
- :i => :SigInt,
8
- :f => :Float,
9
- :Z => :String,
10
- :H => :Hex,
11
- :B => :NumArray
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
  [:CODES, :TYPES].each do |x|
data/lib/gfa/generator.rb CHANGED
@@ -1,31 +1,35 @@
1
1
  class GFA
2
- def save(file)
3
- fh = File.open(file, "w")
4
- each_line do |ln|
5
- fh.puts ln
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
- 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
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
data/lib/gfa/graph.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "rgl/adjacency"
2
- require "rgl/implicit"
1
+ require 'rgl/adjacency'
2
+ require 'rgl/implicit'
3
3
 
4
4
  class GFA
5
5
 
@@ -11,7 +11,7 @@ class GFA
11
11
  # true.
12
12
  # * :directed => bool. If false, ignores direction of the links. By defaut
13
13
  # the same value as :orient.
14
- def implicit_graph(opts={})
14
+ def implicit_graph(opts = {})
15
15
  rgl_implicit_graph(opts)
16
16
  end
17
17
 
@@ -19,7 +19,7 @@ class GFA
19
19
  # Generates a RGL::DirectedAdjacencyGraph or RGL::AdjacencyGraph object.
20
20
  # The +opts+ argument is a hash with the same supported key-value pairs as
21
21
  # in #implicit_graph.
22
- def adjacency_graph(opts={})
22
+ def adjacency_graph(opts = {})
23
23
  implicit_graph(opts).to_adjacency
24
24
  end
25
25
 
@@ -27,7 +27,7 @@ class GFA
27
27
 
28
28
  def segment_names_with_orient
29
29
  segments.flat_map do |s|
30
- %w[+ -].map{ |orient| GFA::GraphVertex.idx(s, orient) }
30
+ %w[+ -].map { |orient| GFA::GraphVertex.idx(s, orient) }
31
31
  end.to_set
32
32
  end
33
33
 
@@ -44,8 +44,8 @@ class GFA
44
44
  (opts[:orient] ? segment_names_with_orient :
45
45
  segment_names).each(&b)
46
46
  end
47
- g.adjacent_iterator do |x,b|
48
- rgl_implicit_adjacent_iterator(x,b,opts)
47
+ g.adjacent_iterator do |x, b|
48
+ rgl_implicit_adjacent_iterator(x, b, opts)
49
49
  end
50
50
  g.directed = opts[:directed]
51
51
  end
@@ -62,20 +62,20 @@ class GFA
62
62
  if l.from?(x.segment, x.orient)
63
63
  orient = opts[:orient] ? l.to_orient : nil
64
64
  b.call(GFA::GraphVertex.idx(l.to, orient))
65
- elsif opts[:orient] and l.to?(x.segment, orient_rc(x.orient))
65
+ elsif opts[:orient] && l.to?(x.segment, orient_rc(x.orient))
66
66
  orient = orient_rc(l.from_orient.value)
67
67
  b.call(GFA::GraphVertex.idx(l.from, orient))
68
68
  end
69
69
  end
70
70
  end
71
71
 
72
- def orient_rc(o) o=="+" ? "-" : "+" ; end
73
-
72
+ def orient_rc(o)
73
+ o == '+' ? '-' : '+'
74
+ end
74
75
  end
75
76
 
76
77
 
77
78
  class GFA::GraphVertex # :nodoc:
78
-
79
79
  # Class-level
80
80
  @@idx = {}
81
81
  def self.idx(segment, orient)
@@ -83,10 +83,10 @@ class GFA::GraphVertex # :nodoc:
83
83
  @@idx[n.to_s] ||= n
84
84
  @@idx[n.to_s]
85
85
  end
86
-
86
+
87
87
  # Instance-level
88
88
  attr :segment, :orient
89
-
89
+
90
90
  def initialize(segment, orient)
91
91
  @segment = segment.is_a?(GFA::Record::Segment) ? segment.name.value :
92
92
  segment.is_a?(GFA::Field) ? segment.value : segment
@@ -96,5 +96,4 @@ class GFA::GraphVertex # :nodoc:
96
96
  def to_s
97
97
  "#{segment}#{orient}"
98
98
  end
99
-
100
99
  end
data/lib/gfa/parser.rb CHANGED
@@ -1,13 +1,13 @@
1
- require "gfa/record"
1
+ require 'gfa/record'
2
2
 
3
3
  class GFA
4
4
  # Class-level
5
- MIN_VERSION = "1.0"
6
- MAX_VERSION = "1.0"
5
+ MIN_VERSION = '1.0'
6
+ MAX_VERSION = '1.2'
7
7
 
8
8
  def self.load(file)
9
9
  gfa = GFA.new
10
- fh = File.open(file, "r")
10
+ fh = File.open(file, 'r')
11
11
  fh.each { |ln| gfa << ln }
12
12
  fh.close
13
13
  gfa
@@ -20,17 +20,19 @@ class GFA
20
20
  # Instance-level
21
21
  def <<(obj)
22
22
  obj = parse_line(obj) unless obj.is_a? GFA::Record
23
- return if obj.nil? or obj.empty?
23
+ return if obj.nil? || obj.empty?
24
24
  @records[obj.type] << obj
25
- if obj.type==:Header and not obj.fields[:VN].nil?
25
+
26
+ if obj.type == :Header && !obj.fields[:VN].nil?
26
27
  set_gfa_version(obj.fields[:VN].value)
27
28
  end
28
29
  end
29
30
 
30
31
  def set_gfa_version(v)
31
32
  @gfa_version = v
32
- raise "GFA version currently unsupported: #{v}." unless
33
- GFA::supported_version? gfa_version
33
+ unless GFA::supported_version? gfa_version
34
+ raise "GFA version currently unsupported: #{v}."
35
+ end
34
36
  end
35
37
 
36
38
  private
@@ -41,5 +43,4 @@ class GFA
41
43
  cols = ln.split("\t")
42
44
  GFA::Record.code_class(cols.shift).new(*cols)
43
45
  end
44
-
45
46
  end
@@ -0,0 +1,10 @@
1
+ class GFA::Record::Comment < GFA::Record
2
+ CODE = :'#'
3
+ REQ_FIELDS = []
4
+ OPT_FIELDS = {}
5
+
6
+ def initialize(*opt_fields)
7
+ @fields = {}
8
+ opt_fields.each { |f| add_opt_field(f, OPT_FIELDS) }
9
+ end
10
+ end
@@ -1,14 +1,20 @@
1
1
  class GFA::Record::Containment < GFA::Record
2
2
  CODE = :C
3
- REQ_FIELDS = [:from, :from_orient, :to, :to_orient, :pos, :overlap]
3
+ REQ_FIELDS = %i[from from_orient to to_orient pos overlap]
4
4
  OPT_FIELDS = {
5
- :RC => :i,
6
- :NM => :i
5
+ RC: :i, # Read coverage
6
+ NM: :i, # Number of mismatches/gaps
7
+ ID: :Z # Edge identifier
7
8
  }
8
9
 
9
10
  REQ_FIELDS.each_index do |i|
10
- define_method(REQ_FIELDS[i]) { fields[i+2] }
11
+ define_method(REQ_FIELDS[i]) { fields[i + 2] }
11
12
  end
13
+
14
+ alias container from
15
+ alias container_orient from_orient
16
+ alias contained to
17
+ alias contained_orient to_orient
12
18
 
13
19
  def initialize(from, from_orient, to, to_orient, pos, overlap, *opt_fields)
14
20
  @fields = {}
@@ -18,7 +24,6 @@ class GFA::Record::Containment < GFA::Record
18
24
  add_field(5, :Z, to_orient, /^+|-$/)
19
25
  add_field(6, :i, pos, /^[0-9]*$/)
20
26
  add_field(7, :Z, overlap, /^\*|([0-9]+[MIDNSHPX=])+$/)
21
- opt_fields.each{ |f| add_opt_field(f, OPT_FIELDS) }
27
+ opt_fields.each { |f| add_opt_field(f, OPT_FIELDS) }
22
28
  end
23
-
24
29
  end
@@ -1,13 +1,12 @@
1
1
  class GFA::Record::Header < GFA::Record
2
- CODE = :H
3
- REQ_FIELDS = []
4
- OPT_FIELDS = {
5
- :VN => :Z
6
- }
2
+ CODE = :H
3
+ REQ_FIELDS = []
4
+ OPT_FIELDS = {
5
+ VN: :Z # Version number
6
+ }
7
7
 
8
- def initialize(*opt_fields)
9
- @fields = {}
10
- opt_fields.each{ |f| add_opt_field(f, OPT_FIELDS) }
11
- end
12
-
8
+ def initialize(*opt_fields)
9
+ @fields = {}
10
+ opt_fields.each{ |f| add_opt_field(f, OPT_FIELDS) }
11
+ end
13
12
  end
@@ -0,0 +1,45 @@
1
+ class GFA::Record::Jump < GFA::Record
2
+ CODE = :J
3
+ REQ_FIELDS = %i[from from_orient to to_orient distance]
4
+ OPT_FIELDS = {
5
+ SC: :i # 1 indicates indirect shortcut connections. Only 0/1 allowed.
6
+ }
7
+
8
+ REQ_FIELDS.each_index do |i|
9
+ define_method(REQ_FIELDS[i]) { fields[i + 2] }
10
+ end
11
+
12
+ def initialize(from, from_orient, to, to_orient, distance, *opt_fields)
13
+ @fields = {}
14
+ add_field(2, :Z, from, /^[!-)+-<>-~][!-~]*$/)
15
+ add_field(3, :Z, from_orient, /^+|-$/)
16
+ add_field(4, :Z, to, /^[!-)+-<>-~][!-~]*$/)
17
+ add_field(5, :Z, to_orient, /^+|-$/)
18
+ add_field(6, :Z, distance, /^\*|[-+]?[0-9]+$/)
19
+ opt_fields.each { |f| add_opt_field(f, OPT_FIELDS) }
20
+ end
21
+
22
+
23
+ def from?(segment, orient = nil)
24
+ links_from_to?(segment, orient, true)
25
+ end
26
+
27
+ def to?(segment, orient = nil)
28
+ links_from_to?(segment, orient, false)
29
+ end
30
+
31
+ private
32
+
33
+ def links_from_to?(segment, orient, from)
34
+ segment = segment_name(segment)
35
+ orient = orient.value if orient.is_a? GFA::Field
36
+ base_k = from ? 2 : 4
37
+ segment==fields[base_k].value &&
38
+ (orient.nil? || orient==fields[base_k + 1].value)
39
+ end
40
+
41
+ def segment_name(segment)
42
+ segment.is_a?(GFA::Record::Segment) ? segment.name.value :
43
+ segment.is_a?(GFA::Field) ? segment.value : segment
44
+ end
45
+ end
@@ -1,50 +1,49 @@
1
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
- }
2
+ CODE = :L
3
+ REQ_FIELDS = %i[from from_orient to to_orient overlap]
4
+ OPT_FIELDS = {
5
+ MQ: :i, # Mapping quality
6
+ NM: :i, # Number of mismatches/gaps
7
+ EC: :i, # Read count
8
+ FC: :i, # Fragment count
9
+ KC: :i, # k-mer count
10
+ ID: :Z # Edge identifier
11
+ }
11
12
 
12
- REQ_FIELDS.each_index do |i|
13
- define_method(REQ_FIELDS[i]) { fields[i+2] }
14
- end
13
+ REQ_FIELDS.each_index do |i|
14
+ define_method(REQ_FIELDS[i]) { fields[i + 2] }
15
+ end
15
16
 
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
17
+ def initialize(from, from_orient, to, to_orient, overlap, *opt_fields)
18
+ @fields = {}
19
+ add_field(2, :Z, from, /^[!-)+-<>-~][!-~]*$/)
20
+ add_field(3, :Z, from_orient, /^+|-$/)
21
+ add_field(4, :Z, to, /^[!-)+-<>-~][!-~]*$/)
22
+ add_field(5, :Z, to_orient, /^+|-$/)
23
+ add_field(6, :Z, overlap, /^\*|([0-9]+[MIDNSHPX=])+$/)
24
+ opt_fields.each { |f| add_opt_field(f, OPT_FIELDS) }
25
+ end
25
26
 
27
+ def from?(segment, orient = nil)
28
+ links_from_to?(segment, orient, true)
29
+ end
26
30
 
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
31
+ def to?(segment, orient = nil)
32
+ links_from_to?(segment, orient, false)
33
+ end
36
34
 
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
35
+ private
44
36
 
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
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 &&
42
+ (orient.nil? || orient==fields[base_k + 1].value)
43
+ end
49
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
50
49
  end
@@ -1,18 +1,19 @@
1
1
  class GFA::Record::Path < GFA::Record
2
- CODE = :P
3
- REQ_FIELDS = [:path_name, :segment_name, :cigar]
4
- OPT_FIELDS = {}
2
+ CODE = :P
3
+ REQ_FIELDS = %i[path_name segment_name cigar]
4
+ OPT_FIELDS = {}
5
5
 
6
- REQ_FIELDS.each_index do |i|
7
- define_method(REQ_FIELDS[i]) { fields[i+2] }
8
- end
6
+ REQ_FIELDS.each_index do |i|
7
+ define_method(REQ_FIELDS[i]) { fields[i + 2] }
8
+ end
9
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
10
+ alias overlaps cigar
17
11
 
12
+ def initialize(path_name, segment_name, cigar, *opt_fields)
13
+ @fields = {}
14
+ add_field(2, :Z, path_name, /^[!-)+-<>-~][!-~]*$/)
15
+ add_field(3, :Z, segment_name, /^[!-)+-<>-~][!-~]*$/)
16
+ add_field(4, :Z, cigar, /^\*|([0-9]+[MIDNSHPX=])+$/)
17
+ opt_fields.each { |f| add_opt_field(f, OPT_FIELDS) }
18
+ end
18
19
  end
@@ -1,22 +1,25 @@
1
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
- }
2
+ CODE = :S
3
+ REQ_FIELDS = %i[name sequence]
4
+ OPT_FIELDS = {
5
+ LN: :i, # Segment length
6
+ RC: :i, # Read count
7
+ FC: :i, # Fragment count
8
+ KC: :i, # k-mer count
9
+ SH: :H, # SHA-256 checksum of the sequence
10
+ UR: :Z, # URI or local file-system path of the sequence
11
+ # Non-cannonical
12
+ DP: :f # (From SAM)
13
+ }
10
14
 
11
- REQ_FIELDS.each_index do |i|
12
- define_method(REQ_FIELDS[i]) { fields[i+2] }
13
- end
15
+ REQ_FIELDS.each_index do |i|
16
+ define_method(REQ_FIELDS[i]) { fields[i + 2] }
17
+ end
14
18
 
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
-
19
+ def initialize(name, sequence, *opt_fields)
20
+ @fields = {}
21
+ add_field(2, :Z, name, /^[!-)+-<>-~][!-~]*$/)
22
+ add_field(3, :Z, sequence, /^\*|[A-Za-z=.]+$/)
23
+ opt_fields.each { |f| add_opt_field(f, OPT_FIELDS) }
24
+ end
22
25
  end
@@ -0,0 +1,20 @@
1
+ class GFA::Record::Walk < GFA::Record
2
+ CODE = :W
3
+ REQ_FIELDS = %i[sample_id hap_index seq_id seq_start seq_end walk]
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(sample_id, hap_index, seq_id, seq_start, seq_end, walk, *opt_fields)
11
+ @fields = {}
12
+ add_field(2, :Z, sample_id, /^[!-)+-<>-~][!-~]*$/)
13
+ add_field(3, :i, hap_index, /^[0-9]+$/)
14
+ add_field(4, :Z, seq_id, /^[!-)+-<>-~][!-~]*$/)
15
+ add_field(5, :i, seq_start, /^\*|[0-9]+$/)
16
+ add_field(6, :i, seq_end, /^\*|[0-9]+$/)
17
+ add_field(7, :Z, walk, /^([><][!-;=?-~]+)+$/)
18
+ opt_fields.each { |f| add_opt_field(f, OPT_FIELDS) }
19
+ end
20
+ end
data/lib/gfa/record.rb CHANGED
@@ -1,18 +1,18 @@
1
1
  class GFA::Record
2
-
3
2
  # Class-level
4
-
5
3
  CODES = {
6
- :H => :Header,
7
- :S => :Segment,
8
- :L => :Link,
9
- :C => :Containment,
10
- :P => :Path
4
+ :'#' => :Comment,
5
+ H: :Header,
6
+ S: :Segment,
7
+ L: :Link,
8
+ J: :Jump, # Since 1.2
9
+ C: :Containment,
10
+ P: :Path,
11
+ W: :Walk # Since 1.1
11
12
  }
12
13
  REQ_FIELDS = []
13
14
  OPT_FIELDS = {}
14
15
  TYPES = CODES.values
15
-
16
16
  TYPES.each { |t| require "gfa/record/#{t.downcase}" }
17
17
 
18
18
  [:CODES, :REQ_FIELDS, :OPT_FIELDS, :TYPES].each do |x|
@@ -44,9 +44,9 @@ class GFA::Record
44
44
  def to_s
45
45
  o = [code.to_s]
46
46
  self.class.REQ_FIELDS.each_index do |i|
47
- o << fields[i+2].to_s(false)
47
+ o << fields[i + 2].to_s(false)
48
48
  end
49
- fields.each do |k,v|
49
+ fields.each do |k, v|
50
50
  next if k.is_a? Integer
51
51
  o << "#{k}:#{v}"
52
52
  end
@@ -54,7 +54,7 @@ class GFA::Record
54
54
  end
55
55
 
56
56
  def hash
57
- {code => fields}.hash
57
+ { code => fields }.hash
58
58
  end
59
59
 
60
60
  def eql?(rec)
@@ -65,26 +65,32 @@ class GFA::Record
65
65
 
66
66
  private
67
67
 
68
- def add_field(f_tag, f_type, f_value, format=nil)
68
+ def add_field(f_tag, f_type, f_value, format = nil)
69
69
  unless format.nil?
70
70
  msg = (f_tag.is_a?(Integer) ? "column #{f_tag}" : "#{f_tag} field")
71
71
  GFA.assert_format(f_value, format, "Bad #{type} #{msg}")
72
72
  end
73
+
73
74
  @fields[ f_tag ] = GFA::Field.code_class(f_type).new(f_value)
74
75
  end
75
76
 
76
77
  def add_opt_field(f, known)
77
- m = /^([A-Za-z]+):([A-Za-z]+):(.*)$/.match(f) or
78
- raise "Cannot parse field: '#{f}'."
78
+ m = /^([A-Za-z]+):([A-Za-z]+):(.*)$/.match(f)
79
+ raise "Cannot parse field: '#{f}'." unless m
80
+
79
81
  f_tag = m[1].to_sym
80
82
  f_type = m[2].to_sym
81
83
  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
84
+
85
+ if known[f_tag].nil? && f_tag =~ /^[A-Z]+$/
86
+ raise "Unknown reserved tag #{f_tag} for a #{type} record."
87
+ end
88
+
89
+ unless known[f_tag].nil? || known[f_tag] == f_type
90
+ raise "Wrong field type #{f_type} for a #{f_tag} tag," \
91
+ " expected #{known[f_tag]}"
92
+ end
93
+
87
94
  add_field(f_tag, f_type, f_value)
88
95
  end
89
-
90
96
  end
data/lib/gfa/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class GFA
2
- VERSION = "0.1.2"
2
+ VERSION = '0.2.0'
3
3
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
4
4
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
5
5
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/gfa.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "gfa/common"
2
- require "gfa/parser"
3
- require "gfa/generator"
4
- require "gfa/graph"
1
+ require 'gfa/common'
2
+ require 'gfa/parser'
3
+ require 'gfa/generator'
4
+ require 'gfa/graph'
data/test/parser_test.rb CHANGED
@@ -4,7 +4,7 @@ require "gfa/parser"
4
4
  class ParserTest < Test::Unit::TestCase
5
5
 
6
6
  def test_load
7
- sample_f = File.expand_path("../fixtures/sample.gfa",__FILE__)
7
+ sample_f = File.expand_path('../fixtures/sample.gfa', __FILE__)
8
8
  assert_respond_to(GFA, :load)
9
9
  pre_fhs = ObjectSpace.each_object(IO).count{ |i| not i.closed? }
10
10
  sample = GFA.load(sample_f)
@@ -20,18 +20,18 @@ class ParserTest < Test::Unit::TestCase
20
20
 
21
21
  def test_version_suppport
22
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") }
23
+ assert_raise { gfa.set_gfa_version('0.9') }
24
+ assert_raise { gfa.set_gfa_version('2.1') }
25
+ assert_nothing_raised { gfa.set_gfa_version('1.0') }
26
26
  end
27
27
 
28
28
  def test_line_by_line
29
29
  gfa = GFA.new
30
30
  assert_respond_to(gfa, :<<)
31
31
  # Empty
32
- gfa << " "
32
+ gfa << ' '
33
33
  assert(gfa.empty?)
34
- gfa << "H"
34
+ gfa << 'H'
35
35
  assert(gfa.empty?)
36
36
  # Segment
37
37
  assert_equal(0, gfa.segments.size)
@@ -40,8 +40,8 @@ class ParserTest < Test::Unit::TestCase
40
40
  assert_equal(1, gfa.segments.size)
41
41
  # Version
42
42
  assert_nil(gfa.gfa_version)
43
- gfa << GFA::Record::Header.new("VN:Z:1.0")
44
- assert_equal("1.0", gfa.gfa_version)
43
+ gfa << GFA::Record::Header.new('VN:Z:1.0')
44
+ assert_equal('1.0', gfa.gfa_version)
45
45
  end
46
46
 
47
47
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,6 @@
1
- require "codeclimate-test-reporter"
2
- CodeClimate::TestReporter.start
1
+ require 'simplecov'
2
+ SimpleCov.start
3
3
 
4
- require "rubygems"
5
- require "test/unit"
6
- require "gfa/common"
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'gfa/common'
metadata CHANGED
@@ -1,55 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gfa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luis M. Rodriguez-R
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-25 00:00:00.000000000 Z
11
+ date: 2023-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rgl
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0.5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: test-unit
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  description: GFA is a graph representation of fragment assemblies
@@ -59,61 +59,64 @@ extensions: []
59
59
  extra_rdoc_files:
60
60
  - README.md
61
61
  files:
62
+ - Gemfile
63
+ - LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - lib/gfa.rb
62
67
  - lib/gfa/common.rb
68
+ - lib/gfa/field.rb
63
69
  - lib/gfa/field/char.rb
64
70
  - lib/gfa/field/float.rb
65
71
  - lib/gfa/field/hex.rb
72
+ - lib/gfa/field/json.rb
66
73
  - lib/gfa/field/numarray.rb
67
74
  - lib/gfa/field/sigint.rb
68
75
  - lib/gfa/field/string.rb
69
- - lib/gfa/field.rb
70
76
  - lib/gfa/generator.rb
71
77
  - lib/gfa/graph.rb
72
78
  - lib/gfa/parser.rb
79
+ - lib/gfa/record.rb
80
+ - lib/gfa/record/comment.rb
73
81
  - lib/gfa/record/containment.rb
74
82
  - lib/gfa/record/header.rb
83
+ - lib/gfa/record/jump.rb
75
84
  - lib/gfa/record/link.rb
76
85
  - lib/gfa/record/path.rb
77
86
  - lib/gfa/record/segment.rb
78
- - lib/gfa/record.rb
87
+ - lib/gfa/record/walk.rb
79
88
  - lib/gfa/version.rb
80
- - lib/gfa.rb
81
89
  - test/common_test.rb
82
90
  - test/field_test.rb
83
91
  - test/parser_test.rb
84
92
  - test/record_test.rb
85
93
  - test/test_helper.rb
86
- - Gemfile
87
- - Rakefile
88
- - README.md
89
- - LICENSE
90
94
  homepage: https://github.com/lmrodriguezr/gfa
91
95
  licenses: []
92
96
  metadata: {}
93
- post_install_message:
97
+ post_install_message:
94
98
  rdoc_options:
95
99
  - lib
96
100
  - README.md
97
- - --main
101
+ - "--main"
98
102
  - README.md
99
- - --title
103
+ - "--title"
100
104
  - Graphical Fragment Assembly (GFA) for Ruby
101
105
  require_paths:
102
106
  - lib
103
107
  required_ruby_version: !ruby/object:Gem::Requirement
104
108
  requirements:
105
- - - '>='
109
+ - - ">="
106
110
  - !ruby/object:Gem::Version
107
111
  version: '0'
108
112
  required_rubygems_version: !ruby/object:Gem::Requirement
109
113
  requirements:
110
- - - '>='
114
+ - - ">="
111
115
  - !ruby/object:Gem::Version
112
116
  version: '0'
113
117
  requirements: []
114
- rubyforge_project:
115
- rubygems_version: 2.0.14
116
- signing_key:
118
+ rubygems_version: 3.2.3
119
+ signing_key:
117
120
  specification_version: 4
118
121
  summary: Graphical Fragment Assembly (GFA) for Ruby
119
122
  test_files: []