libssw 0.0.2 → 0.0.3

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
2
  SHA256:
3
- metadata.gz: 182b0d30cdf3d9a93b100b05f96d469d612b09bcfcfd2afc3cb63a4c93501d17
4
- data.tar.gz: 99ec370125c707acff3a99664706ce8691f2e66e48d22a49af0362894b2c6b72
3
+ metadata.gz: 010f0923d209dc9f0d3fde047c5cfbbb176e57239ff79e236a1f69f3b634573f
4
+ data.tar.gz: 9e08dc3fb6b03405eaa97ac6a65743bd61fc49d8fc28de6a32b737243a365236
5
5
  SHA512:
6
- metadata.gz: 8a49bf4924da5d12310b691f9f9335d96cdce0ef4b82ac1a38aeb6293c92d939cd17e4b0e6e99a4c427a0f4074f94db1cca91ca6c26b76a0551e558371b4aee7
7
- data.tar.gz: 5af24c2124cd53f8aa54dc905172eb6f9b3d7c57b33fb87d1884ca2ab1a90acf0cb1f2ca73cb88eecda223e3f723836cca2dbae9cb0c1ac665d097993645ee19
6
+ metadata.gz: 9cf4524856aba84e141dd6b6e727e671a01ac907c1d1ad4b33907a16385a499024f235b7f982e66244af07af42e60b1efe0c093281bb433147fb594f887930e7
7
+ data.tar.gz: 275a528ded7a99cfac5d8d45487e27f290bd7b252cac7ddb141d1a03218b72042e0b6c54c92a7c39ee1ff276fd3cb1575772ae3b9b74316ea9a7a7e2e48ffe9a
data/README.md CHANGED
@@ -3,11 +3,10 @@
3
3
  ![test](https://github.com/kojix2/ruby-libssw/workflows/CI/badge.svg)
4
4
  [![Gem Version](https://img.shields.io/gem/v/libssw?color=brightgreen)](https://rubygems.org/gems/libssw)
5
5
  [![Docs Latest](https://img.shields.io/badge/docs-latest-blue.svg)](https://rubydoc.info/gems/libssw)
6
+ [![DOI](https://zenodo.org/badge/328163622.svg)](https://zenodo.org/badge/latestdoi/328163622)
6
7
 
7
8
  :checkered_flag: [libssw](https://github.com/mengyao/Complete-Striped-Smith-Waterman-Library) - fast SIMD parallelized implementation of the Smith-Waterman algorithm - for Ruby
8
9
 
9
- :construction: Under development.
10
-
11
10
  ## Installation
12
11
 
13
12
  ```ssh
@@ -24,41 +23,42 @@ export LIBSSWDIR=/usr/lib/x86_64-linux-gnu/ # libssw.so
24
23
 
25
24
  ### Installing from source
26
25
 
27
- When installing from source code using the following steps, the shared library `libssw.so` will be packed in the Ruby gem. In this case, the environment variable LIBSSWDIR is not required. (Only tested on Ubuntu)
26
+ When installing from source code using the following steps, the shared library `libssw.so` or `libssw.dylib` will be packed in the Ruby gem. In this case, the environment variable `LIBSSWDIR` is not required.
28
27
 
29
28
  ```sh
30
29
  git clone --recurse-submodules https://github.com/kojix2/ruby-libssw
31
- bundle exec rake libssw:compile
30
+ bundle exec rake libssw:build
32
31
  bundle exec rake install
33
32
  ```
34
33
 
34
+ ruby-libssw does not support Windows.
35
+
35
36
  ## Usage
36
37
 
37
38
  ```ruby
38
39
  require 'libssw'
39
40
 
40
- SSW = LibSSW
41
-
42
41
  ref_str = "AAAAAAAAACGTTAAAAAAAAAA"
43
- ref_int = SSW.dna_to_int_array(ref_str)
42
+ ref_int = SSW::DNA.to_int_array(ref_str)
44
43
  # [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
45
44
 
46
45
  read_str1 = "ACGTT"
47
- read_str2 = SSW.dna_complement(read_str1)
48
- read_int1 = SSW.dna_to_int_array(read_str1)
46
+ read_str2 = SSW::DNA.revcomp(read_str1)
47
+ # "AACGT"
48
+ read_int1 = SSW::DNA.to_int_array(read_str1)
49
49
  # [0, 1, 2, 3, 3]
50
- read_int2 = SSW.dna_to_int_array(read_str2)
50
+ read_int2 = SSW::DNA.to_int_array(read_str2)
51
51
  # [0, 0, 1, 2, 3]
52
52
 
53
- mat = SSW.create_scoring_matrix(SSW::DNAElements, 2, -2)
53
+ mat = SSW.create_scoring_matrix(SSW::DNA::Elements, 2, -2)
54
54
  # mat = [2, -2, -2, -2, 0,
55
55
  # -2, 2, -2, -2, 0,
56
56
  # -2, -2, 2, -2, 0,
57
57
  # -2, -2, -2, 2, 0,
58
58
  # 0, 0, 0, 0, 0]
59
59
 
60
- profile1 = LibSSW.ssw_init(read_int1, mat)
61
- align1 = LibSSW.ssw_align(profile1, ref_int, 3, 1, 1, 0, 0, 15)
60
+ profile1 = SSW.init(read_int1, mat)
61
+ align1 = SSW.align(profile1, ref_int, 3, 1, 1, 0, 0)
62
62
  pp align1.to_h
63
63
  # {
64
64
  # :score1 => 10,
@@ -73,8 +73,8 @@ pp align1.to_h
73
73
  # :cigar_string => "5M"
74
74
  # }
75
75
 
76
- profile2 = LibSSW.ssw_init(read_int2, mat)
77
- align2 = LibSSW.ssw_align(profile2, ref_int, 3, 1, 1, 0, 0, 15)
76
+ profile2 = SSW.init(read_int2, mat)
77
+ align2 = SSW.align(profile2, ref_int, 3, 1, 1, 0, 0)
78
78
  pp align2.to_h
79
79
  # {
80
80
  # :score1 => 10,
@@ -88,24 +88,65 @@ pp align2.to_h
88
88
  # :cigar_len => 1,
89
89
  # :cigar_string => "5M"
90
90
  # }
91
- ```
92
91
 
92
+ puts SSW.build_path(read_str1, ref_str, align1)
93
+ # 5M
94
+ # ACGTT
95
+ # |||||
96
+ # ACGTT
97
+ ```
93
98
 
94
- ## Documentation
95
-
96
- * [API Documentation](https://rubydoc.info/gems/libssw)
99
+ ## APIs
100
+
101
+ See [API Documentation](https://rubydoc.info/gems/libssw).
102
+
103
+ ```markdown
104
+ * SSW module
105
+ * SSW.init
106
+ * SSW.init_destroy
107
+ * SSW.align
108
+ * SSW.align_destroy
109
+ * SSW.mark_mismatch
110
+ * SSW.create_scoring_matrix
111
+ * SSW.build_path
112
+
113
+ * Profile class
114
+ * attributes
115
+ * read, mat, read_len, n, bias
116
+
117
+ * Align class
118
+ * attributes
119
+ * score1, score2, ref_begin1, ref_end1, read_begin1, read_end1, ref_end2
120
+ cigar, cigar_len, cigar_string
121
+
122
+ * DNA module
123
+ * DNA.to_int_array
124
+ * DNA.from_int_array
125
+ * revcomp
126
+
127
+ * AASeq module
128
+ * AASeq.to_int_array
129
+ * AASeq.from_int_array
130
+
131
+ * BLOSUM62
132
+ * BLOSUM50
133
+ ```
97
134
 
98
135
  ## Development
99
136
 
100
137
  ```sh
101
138
  git clone --recurse-submodules https://github.com/kojix2/ruby-libssw
102
- bundle exec rake libssw:compile
139
+ bundle exec rake libssw:build
103
140
  bundle exec rake test
104
141
  ```
105
142
 
106
143
  ## Contributing
107
144
 
108
- Bug reports and pull requests are welcome on GitHub at https://github.com/kojix2/ruby-libssw.
145
+ * [Report bugs](https://github.com/kojix2/ruby-libssw/issues)
146
+ * Fix bugs and [submit pull requests](https://github.com/kojix2/ruby-libssw/pulls)
147
+ * Write, clarify, or fix documentation
148
+ * English corrections are welcome
149
+ * Suggest or add new features
109
150
 
110
151
  ## License
111
152
 
data/lib/libssw.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'libssw/version'
4
- require_relative 'libssw/BLOSUM50'
5
- require_relative 'libssw/BLOSUM62'
3
+ require_relative 'ssw/version'
4
+ require_relative 'ssw/BLOSUM50'
5
+ require_relative 'ssw/BLOSUM62'
6
+ require_relative 'ssw/dna'
7
+ require_relative 'ssw/aaseq'
6
8
 
7
- module LibSSW
9
+ module SSW
8
10
  class Error < StandardError; end
9
11
 
10
12
  class << self
@@ -26,67 +28,9 @@ module LibSSW
26
28
  File.expand_path("../vendor/#{lib_name}", __dir__)
27
29
  end
28
30
 
29
- require_relative 'libssw/ffi'
30
- require_relative 'libssw/profile'
31
- require_relative 'libssw/align'
32
-
33
- AAELEMENTS = ['A', 'R', 'N', 'D', 'C', 'Q', 'E', 'G',
34
- 'H', 'I', 'L', 'K', 'M', 'F', 'P', 'S',
35
- 'T', 'W', 'Y', 'V', 'B', 'Z', 'X', '*']
36
-
37
- AA2INT = { 'A' => 0, 'a' => 0,
38
- 'R' => 1, 'r' => 1,
39
- 'N' => 2, 'n' => 2,
40
- 'D' => 3, 'd' => 3,
41
- 'C' => 4, 'c' => 4,
42
- 'Q' => 5, 'q' => 5,
43
- 'E' => 6, 'e' => 6,
44
- 'G' => 7, 'g' => 7,
45
- 'H' => 8, 'h' => 8,
46
- 'I' => 9, 'i' => 9,
47
- 'L' => 10, 'l' => 10,
48
- 'K' => 11, 'k' => 11,
49
- 'M' => 12, 'm' => 12,
50
- 'F' => 13, 'f' => 13,
51
- 'P' => 14, 'p' => 14,
52
- 'S' => 15, 's' => 15,
53
- 'T' => 16, 't' => 16,
54
- 'W' => 17, 'w' => 17,
55
- 'Y' => 18, 'y' => 18,
56
- 'V' => 19, 'v' => 19,
57
- 'B' => 20, 'b' => 20,
58
- 'Z' => 21, 'z' => 21,
59
- 'X' => 22, 'x' => 22,
60
- '*' => 23 }
61
-
62
- INT2AA = { 0 => 'A', 1 => 'R', 2 => 'N', 3 => 'D',
63
- 4 => 'C', 5 => 'Q', 6 => 'E', 7 => 'G',
64
- 8 => 'H', 9 => 'I', 10 => 'L', 11 => 'K',
65
- 12 => 'M', 13 => 'F', 14 => 'P', 15 => 'S',
66
- 16 => 'T', 17 => 'W', 18 => 'Y', 19 => 'V',
67
- 20 => 'B', 21 => 'Z', 22 => 'X', 23 => '*' }
68
-
69
- DNAElements = %w[A C G T N]
70
-
71
- DNA2INT = { 'A' => 0, 'a' => 0,
72
- 'C' => 1, 'c' => 1,
73
- 'G' => 2, 'g' => 2,
74
- 'T' => 3, 't' => 3,
75
- 'N' => 4, 'n' => 4 }
76
-
77
- INT2DNA = { 0 => 'A', 1 => 'C', 2 => 'G', 3 => 'T', 4 => 'N' }
78
-
79
- # reverse complement
80
- DNARC = { 'A' => 'T',
81
- 'C' => 'G',
82
- 'G' => 'C',
83
- 'T' => 'A',
84
- 'N' => 'N',
85
- 'a' => 'T',
86
- 'c' => 'G',
87
- 'g' => 'C',
88
- 't' => 'A',
89
- 'n' => 'N' }
31
+ require_relative 'ssw/ffi'
32
+ require_relative 'ssw/profile'
33
+ require_relative 'ssw/align'
90
34
 
91
35
  class << self
92
36
  # Create the query profile using the query sequence.
@@ -99,10 +43,14 @@ module LibSSW
99
43
  # * if your estimated best alignment score is surely < 255 please set 0;
100
44
  # * if your estimated best alignment score >= 255, please set 1;
101
45
  # * if you don't know, please set 2
102
- def ssw_init(read, mat, n = nil, score_size: 2)
46
+ def init(read, mat, n = nil, score_size: 2)
47
+ read = read.to_a
48
+ mat = mat.to_a.flatten
49
+ raise ArgumentError, 'Expect class of read to be Array' unless read.is_a?(Array)
50
+ raise ArgumentError, 'Expect class of mat to be Array' unless mat.is_a?(Array)
51
+
103
52
  read_str = read.pack('c*')
104
53
  read_len = read.size
105
- mat = mat.to_a.flatten
106
54
  n = Math.sqrt(mat.size) if n.nil?
107
55
  raise "Not a square matrix. size: #{mat.size}, n: #{n}" if mat.size != n * n
108
56
 
@@ -126,20 +74,24 @@ module LibSSW
126
74
  ptr.instance_variable_set(:@n, n)
127
75
  ptr.instance_variable_set(:@score_size, score_size)
128
76
 
129
- LibSSW::Profile.new(ptr)
77
+ SSW::Profile.new(ptr)
130
78
  end
131
79
 
132
80
  # Release the memory allocated by function ssw_init.
133
- # @param p [Fiddle::Pointer, LibSSW::Profile, LibSSW::FFI::Profile]
81
+ # @param p [Fiddle::Pointer, SSW::Profile, SSW::FFI::Profile]
134
82
  # pointer to the query profile structure
135
83
  # @note Ruby has garbage collection, so there is not much reason to call
136
84
  # this method.
137
85
  def init_destroy(profile)
86
+ unless profile.is_a?(Fiddle::Pointer) || prof.is_a?(Profile) || prof.respond_to?(:to_ptr)
87
+ raise ArgumentError, 'Expect class of filename to be Profile or Pointer'
88
+ end
89
+
138
90
  FFI.init_destroy(profile)
139
91
  end
140
92
 
141
93
  # Do Striped Smith-Waterman alignment.
142
- # @param prof [Fiddle::Pointer, LibSSW::Profile, LibSSW::FFI::Profile]
94
+ # @param prof [Fiddle::Pointer, SSW::Profile, SSW::FFI::Profile]
143
95
  # pointer to the query profile structure
144
96
  # @param ref [Array]
145
97
  # target sequence;
@@ -181,9 +133,15 @@ module LibSSW
181
133
  # SSW C library masks the reference loci nearby (mask length = maskLen)
182
134
  # the best alignment ending position and locates the second largest score
183
135
  # from the unmasked elements.
184
- def ssw_align(prof, ref, weight_gap0, weight_gapE, flag, filters, filterd, mask_len)
136
+ def align(prof, ref, weight_gap0, weight_gapE, flag, filters, filterd, mask_len = nil)
137
+ unless prof.is_a?(Fiddle::Pointer) || prof.is_a?(Profile) || prof.respond_to?(:to_ptr)
138
+ raise ArgumentError, 'Expect class of filename to be Profile or Pointer'
139
+ end
140
+ raise ArgumentError, 'Expect class of ref to be Array' unless ref.is_a?(Array)
141
+
185
142
  ref_str = ref.pack('c*')
186
143
  ref_len = ref.size
144
+ mask_len ||= [ref_len / 2, 15].max
187
145
  ptr = FFI.ssw_align(
188
146
  prof, ref_str, ref_len, weight_gap0, weight_gapE, flag, filters, filterd, mask_len
189
147
  )
@@ -192,14 +150,21 @@ module LibSSW
192
150
  # For example: instance_variable_set(:@ref_str, ref_str)
193
151
  #
194
152
  # ptr.free = FFI.instance_variable_get(:@func_map)['align_destroy']
195
- LibSSW::Align.new(ptr)
153
+ SSW::Align.new(ptr)
196
154
  end
197
155
 
198
156
  # Release the memory allocated by function ssw_align.
199
- # @param a [Fiddle::Pointer, LibSSW::Align, LibSSW::FFI::Align]
157
+ # @param a [Fiddle::Pointer, SSW::Align, SSW::FFI::Align]
200
158
  # pointer to the alignment result structure
201
159
  def align_destroy(align)
202
- FFI.align_destroy(align)
160
+ if align.is_a?(Align)
161
+ warn "You don't need to call this method for Ruby's Align class."
162
+ nil
163
+ elsif align.is_a?(Fiddle::Pointer) || align.respond_to?(:to_ptr)
164
+ FFI.align_destroy(align)
165
+ else
166
+ raise ArgumentError, 'Expect class of filename to be Pointer'
167
+ end
203
168
  end
204
169
 
205
170
  # 1. Calculate the number of mismatches.
@@ -231,17 +196,6 @@ module LibSSW
231
196
  )
232
197
  end
233
198
 
234
- def array_to_cigar_string(arr)
235
- cigar_string = String.new
236
- arr.each do |x|
237
- n = x >> 4
238
- m = x & 15
239
- c = m > 8 ? 'M' : 'MIDNSHP=X'[m]
240
- cigar_string << n.to_s << c
241
- end
242
- cigar_string
243
- end
244
-
245
199
  # Create scoring matrix of Smith-Waterman algrithum.
246
200
  # @param [Array] elements
247
201
  # @param [Integer] match_score
@@ -258,44 +212,37 @@ module LibSSW
258
212
  score
259
213
  end
260
214
 
261
- # @param [String] seq
262
- def dna_to_int_array(seq)
263
- raise ArgumentError, 'seq must be a string' unless seq.is_a? String
264
-
265
- seq.each_char.map do |base|
266
- DNA2INT[base] || DNA2INT['N']
267
- end
268
- end
269
-
270
- def dna_complement(seq)
271
- seq.each_char.map do |base|
272
- DNARC[base]
273
- end.join.reverse
274
- end
275
-
276
- # @param [Array] int array
277
- def int_array_to_dna(arr)
278
- raise ArgumentError, 'arr must be an Array' unless arr.is_a? Array
279
-
280
- arr.map do |i|
281
- INT2DNA[i] || 'N'
282
- end.join
283
- end
284
-
285
- def aaseq_to_int_array(seq)
286
- raise ArgumentError, 'seq must be a string' unless seq.is_a? String
287
-
288
- seq.each_char.map do |base|
289
- AA2INT[base] || AA2INT['*']
215
+ # TODO: fix variable names
216
+ def build_path(q_seq, r_seq, align)
217
+ sQ = ''
218
+ sA = ''
219
+ sR = ''
220
+ q_off = align.read_begin1
221
+ r_off = align.ref_begin1
222
+ align.cigar.each do |x|
223
+ n = x >> 4
224
+ m = x & 15
225
+ c = m > 8 ? 'M' : 'MIDNSHP=X'[m]
226
+ case c
227
+ when 'M'
228
+ sQ += q_seq[q_off...(q_off + n)]
229
+ sA += Array.new(n) { |j| q_seq[q_off + j] == r_seq[r_off + j] ? '|' : '*' }.join
230
+ sR += r_seq[r_off...(r_off + n)]
231
+ q_off += n
232
+ r_off += n
233
+ when 'I'
234
+ sQ += q_seq[q_off...(q_off + n)]
235
+ sA += ' ' * n
236
+ sR += ' ' * n
237
+ q_off += n
238
+ when 'D'
239
+ sQ += ' ' * n
240
+ sA += ' ' * n
241
+ sR += r_seq[r_off...(r_off + n)]
242
+ r_off += n
243
+ end
290
244
  end
291
- end
292
-
293
- def int_array_to_aaseq(arr)
294
- raise ArgumentError, 'arr must be an Array' unless arr.is_a? Array
295
-
296
- arr.map do |i|
297
- INT2AA[i] || '*'
298
- end.join
245
+ [align.cigar_string, sQ, sA, sR]
299
246
  end
300
247
  end
301
248
  end
@@ -1,4 +1,4 @@
1
- module LibSSW
1
+ module SSW
2
2
  BLOSUM50 = [
3
3
  # A R N D C Q E G H I L K M F P S T W Y V B Z X *
4
4
  5, -2, -1, -2, -1, -1, -1, 0, -2, -1, -2, -1, -1, -3, -1, 1, 0, -3, -2, 0, -2, -1, -1, -5, # A
@@ -1,4 +1,4 @@
1
- module LibSSW
1
+ module SSW
2
2
  BLOSUM62 = [
3
3
  # A R N D C Q E G H I L K M F P S T W Y V B Z X *
4
4
  4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0, -4, # A
data/lib/ssw/aaseq.rb ADDED
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SSW
4
+ module AASeq
5
+ AAELEMENTS = ['A', 'R', 'N', 'D', 'C', 'Q', 'E', 'G',
6
+ 'H', 'I', 'L', 'K', 'M', 'F', 'P', 'S',
7
+ 'T', 'W', 'Y', 'V', 'B', 'Z', 'X', '*'].freeze
8
+
9
+ AA2INT = { 'A' => 0, 'a' => 0,
10
+ 'R' => 1, 'r' => 1,
11
+ 'N' => 2, 'n' => 2,
12
+ 'D' => 3, 'd' => 3,
13
+ 'C' => 4, 'c' => 4,
14
+ 'Q' => 5, 'q' => 5,
15
+ 'E' => 6, 'e' => 6,
16
+ 'G' => 7, 'g' => 7,
17
+ 'H' => 8, 'h' => 8,
18
+ 'I' => 9, 'i' => 9,
19
+ 'L' => 10, 'l' => 10,
20
+ 'K' => 11, 'k' => 11,
21
+ 'M' => 12, 'm' => 12,
22
+ 'F' => 13, 'f' => 13,
23
+ 'P' => 14, 'p' => 14,
24
+ 'S' => 15, 's' => 15,
25
+ 'T' => 16, 't' => 16,
26
+ 'W' => 17, 'w' => 17,
27
+ 'Y' => 18, 'y' => 18,
28
+ 'V' => 19, 'v' => 19,
29
+ 'B' => 20, 'b' => 20,
30
+ 'Z' => 21, 'z' => 21,
31
+ 'X' => 22, 'x' => 22,
32
+ '*' => 23 }.freeze
33
+
34
+ INT2AA = { 0 => 'A', 1 => 'R', 2 => 'N', 3 => 'D',
35
+ 4 => 'C', 5 => 'Q', 6 => 'E', 7 => 'G',
36
+ 8 => 'H', 9 => 'I', 10 => 'L', 11 => 'K',
37
+ 12 => 'M', 13 => 'F', 14 => 'P', 15 => 'S',
38
+ 16 => 'T', 17 => 'W', 18 => 'Y', 19 => 'V',
39
+ 20 => 'B', 21 => 'Z', 22 => 'X', 23 => '*' }.freeze
40
+
41
+ module_function
42
+
43
+ def to_int_array(seq)
44
+ raise ArgumentError, 'seq must be a string' unless seq.is_a? String
45
+
46
+ seq.each_char.map do |base|
47
+ AA2INT[base] || AA2INT['*']
48
+ end
49
+ end
50
+
51
+ def from_int_array(arr)
52
+ raise ArgumentError, 'arr must be an Array' unless arr.is_a? Array
53
+
54
+ arr.map do |i|
55
+ INT2AA[i] || '*'
56
+ end.join
57
+ end
58
+ end
59
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module LibSSW
3
+ module SSW
4
4
  # structure of the alignment result
5
5
  # @!attribute score1
6
6
  # @return [Integer] the best alignment score
@@ -28,7 +28,9 @@ module LibSSW
28
28
  # @!attribute cigar_len
29
29
  # @return [Integer]
30
30
  # length of the cigar string; cigarLen = 0 when the best alignment path is not available
31
- class Align < FFI::Align
31
+ # @!attribute cigar_string
32
+ # @return [String] cigar string
33
+ class Align
32
34
  def self.keys
33
35
  %i[score1 score2 ref_begin1 ref_end1
34
36
  read_begin1 read_end1 ref_end2 cigar cigar_len cigar_string]
@@ -50,12 +52,25 @@ module LibSSW
50
52
  @cigar_len = align.cigarLen
51
53
  @cigar = cigar_len.positive? ? align.cigar[0, 4 * cigar_len].unpack('L*') : []
52
54
  # Attributes for ruby binding only
53
- @cigar_string = LibSSW.array_to_cigar_string(@cigar)
54
- LibSSW.align_destroy(ptr)
55
+ @cigar_string = array_to_cigar_string(@cigar)
56
+ SSW.align_destroy(ptr)
55
57
  end
56
58
 
57
59
  def to_h
58
60
  self.class.keys.map { |k| [k, __send__(k)] }.to_h
59
61
  end
62
+
63
+ private
64
+
65
+ def array_to_cigar_string(arr)
66
+ cigar_string = String.new
67
+ arr.each do |x|
68
+ n = x >> 4
69
+ m = x & 15
70
+ c = m > 8 ? 'M' : 'MIDNSHP=X'[m]
71
+ cigar_string << n.to_s << c
72
+ end
73
+ cigar_string
74
+ end
60
75
  end
61
76
  end
data/lib/ssw/dna.rb ADDED
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SSW
4
+ module DNA
5
+ Elements = %w[A C G T N].freeze
6
+
7
+ DNA2INT = { 'A' => 0, 'a' => 0,
8
+ 'C' => 1, 'c' => 1,
9
+ 'G' => 2, 'g' => 2,
10
+ 'T' => 3, 't' => 3,
11
+ 'N' => 4, 'n' => 4 }.freeze
12
+
13
+ INT2DNA = { 0 => 'A', 1 => 'C', 2 => 'G', 3 => 'T', 4 => 'N' }.freeze
14
+
15
+ # reverse complement
16
+ DNARC = { 'A' => 'T',
17
+ 'C' => 'G',
18
+ 'G' => 'C',
19
+ 'T' => 'A',
20
+ 'N' => 'N',
21
+ 'a' => 'T',
22
+ 'c' => 'G',
23
+ 'g' => 'C',
24
+ 't' => 'A',
25
+ 'n' => 'N' }.freeze
26
+
27
+ module_function
28
+
29
+ # @param [String] seq
30
+ def to_int_array(seq)
31
+ raise ArgumentError, 'seq must be a string' unless seq.is_a? String
32
+
33
+ seq.each_char.map do |base|
34
+ DNA2INT[base] || DNA2INT['N']
35
+ end
36
+ end
37
+
38
+ # @param [Array] int array
39
+ def from_int_array(arr)
40
+ raise ArgumentError, 'arr must be an Array' unless arr.is_a? Array
41
+
42
+ arr.map do |i|
43
+ INT2DNA[i] || 'N'
44
+ end.join
45
+ end
46
+
47
+ def revcomp(seq)
48
+ seq.each_char.map do |base|
49
+ DNARC[base]
50
+ end.join.reverse
51
+ end
52
+ end
53
+ end
@@ -2,12 +2,12 @@
2
2
 
3
3
  require 'fiddle/import'
4
4
 
5
- module LibSSW
5
+ module SSW
6
6
  module FFI
7
7
  extend Fiddle::Importer
8
8
 
9
9
  begin
10
- dlload LibSSW.ffi_lib
10
+ dlload SSW.ffi_lib
11
11
  rescue LoadError => e
12
12
  raise LoadError, "Could not find libssw shared library. \n#{e}"
13
13
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module LibSSW
3
+ module SSW
4
4
  # structure of the query profile/usr/lib/x86_64-linux-gnu/
5
5
  # @!attribute read
6
6
  # @!attribute mat
7
7
  # @!attribute read_len
8
8
  # @!attribute n
9
9
  # @!attribute bias
10
- class Profile < FFI::Profile
10
+ class Profile
11
11
  def self.keys
12
12
  %i[read mat read_len n bias]
13
13
  end
@@ -17,7 +17,7 @@ module LibSSW
17
17
 
18
18
  def initialize(ptr)
19
19
  @ptr = ptr
20
- @cstruct = profile = LibSSW::FFI::Profile.new(ptr)
20
+ @cstruct = profile = SSW::FFI::Profile.new(ptr)
21
21
  @read_len = profile.readLen
22
22
  @read = read_len.positive? ? profile.read[0, read_len].unpack('c*') : []
23
23
  @n = profile.n
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module LibSSW
4
- VERSION = '0.0.2'
3
+ module SSW
4
+ VERSION = '0.0.3'
5
5
  end
data/vendor/libssw.so ADDED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libssw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-22 00:00:00.000000000 Z
11
+ date: 2021-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fiddle
@@ -120,12 +120,15 @@ files:
120
120
  - README.md
121
121
  - exe/rbssw
122
122
  - lib/libssw.rb
123
- - lib/libssw/BLOSUM50.rb
124
- - lib/libssw/BLOSUM62.rb
125
- - lib/libssw/align.rb
126
- - lib/libssw/ffi.rb
127
- - lib/libssw/profile.rb
128
- - lib/libssw/version.rb
123
+ - lib/ssw/BLOSUM50.rb
124
+ - lib/ssw/BLOSUM62.rb
125
+ - lib/ssw/aaseq.rb
126
+ - lib/ssw/align.rb
127
+ - lib/ssw/dna.rb
128
+ - lib/ssw/ffi.rb
129
+ - lib/ssw/profile.rb
130
+ - lib/ssw/version.rb
131
+ - vendor/libssw.so
129
132
  homepage: https://github.com/kojix2/ruby-libssw
130
133
  licenses:
131
134
  - MIT