bioinform 0.1.12 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +17 -17
  3. data/Gemfile +16 -16
  4. data/LICENSE +21 -21
  5. data/README.md +35 -35
  6. data/Rakefile +4 -4
  7. data/TODO.txt +37 -37
  8. data/bin/merge_into_collection +3 -3
  9. data/bin/pcm2pwm +3 -3
  10. data/bin/split_motifs +3 -3
  11. data/bioinform.gemspec +19 -19
  12. data/lib/bioinform/cli/convert_motif.rb +107 -107
  13. data/lib/bioinform/cli/merge_into_collection.rb +79 -79
  14. data/lib/bioinform/cli/pcm2pwm.rb +46 -46
  15. data/lib/bioinform/cli/split_motifs.rb +46 -46
  16. data/lib/bioinform/cli.rb +29 -29
  17. data/lib/bioinform/conversion_algorithms/pcm2ppm_converter.rb +18 -18
  18. data/lib/bioinform/conversion_algorithms/pcm2pwm_converter.rb +19 -19
  19. data/lib/bioinform/data_models/collection.rb +74 -74
  20. data/lib/bioinform/data_models/motif.rb +55 -55
  21. data/lib/bioinform/data_models/pcm.rb +23 -23
  22. data/lib/bioinform/data_models/pm.rb +169 -169
  23. data/lib/bioinform/data_models/ppm.rb +9 -9
  24. data/lib/bioinform/data_models/pwm.rb +55 -55
  25. data/lib/bioinform/data_models.rb +10 -10
  26. data/lib/bioinform/formatters/raw_formatter.rb +40 -40
  27. data/lib/bioinform/formatters/transfac_formatter.rb +38 -38
  28. data/lib/bioinform/formatters.rb +1 -1
  29. data/lib/bioinform/parsers/jaspar_parser.rb +34 -34
  30. data/lib/bioinform/parsers/parser.rb +87 -87
  31. data/lib/bioinform/parsers/splittable_parser.rb +56 -56
  32. data/lib/bioinform/parsers/string_fantom_parser.rb +34 -34
  33. data/lib/bioinform/parsers/string_parser.rb +71 -71
  34. data/lib/bioinform/parsers/trivial_parser.rb +33 -33
  35. data/lib/bioinform/parsers/yaml_parser.rb +34 -34
  36. data/lib/bioinform/parsers.rb +6 -6
  37. data/lib/bioinform/support/array_product.rb +5 -5
  38. data/lib/bioinform/support/array_zip.rb +5 -5
  39. data/lib/bioinform/support/collect_hash.rb +6 -6
  40. data/lib/bioinform/support/deep_dup.rb +4 -4
  41. data/lib/bioinform/support/delete_many.rb +13 -13
  42. data/lib/bioinform/support/inverf.rb +12 -12
  43. data/lib/bioinform/support/multiline_squish.rb +5 -5
  44. data/lib/bioinform/support/parameters.rb +27 -27
  45. data/lib/bioinform/support/partial_sums.rb +15 -15
  46. data/lib/bioinform/support/same_by.rb +12 -12
  47. data/lib/bioinform/support/strip_doc.rb +8 -8
  48. data/lib/bioinform/support/third_part/active_support/hash_with_indifferent_access.rb +3 -0
  49. data/lib/bioinform/support.rb +17 -17
  50. data/lib/bioinform/version.rb +3 -3
  51. data/lib/bioinform.rb +10 -10
  52. data/spec/cli/cli_spec.rb +13 -13
  53. data/spec/cli/convert_motif_spec.rb +106 -106
  54. data/spec/cli/data/merge_into_collection/GABPA_f1.pwm +14 -14
  55. data/spec/cli/data/merge_into_collection/KLF4_f2.pwm +11 -11
  56. data/spec/cli/data/merge_into_collection/SP1_f1.pwm +12 -12
  57. data/spec/cli/data/merge_into_collection/collection.txt.result +40 -40
  58. data/spec/cli/data/merge_into_collection/collection.yaml.result +188 -188
  59. data/spec/cli/data/merge_into_collection/collection_pwm.yaml.result +188 -188
  60. data/spec/cli/data/merge_into_collection/pwm_folder/GABPA_f1.pwm +14 -14
  61. data/spec/cli/data/merge_into_collection/pwm_folder/KLF4_f2.pwm +11 -11
  62. data/spec/cli/data/merge_into_collection/pwm_folder/SP1_f1.pwm +12 -12
  63. data/spec/cli/data/pcm2pwm/KLF4 f2 spaced name.pcm +11 -11
  64. data/spec/cli/data/pcm2pwm/KLF4_f2.pcm +11 -11
  65. data/spec/cli/data/pcm2pwm/KLF4_f2.pwm.result +11 -11
  66. data/spec/cli/data/pcm2pwm/SP1_f1.pcm +12 -12
  67. data/spec/cli/data/pcm2pwm/SP1_f1.pwm.result +12 -12
  68. data/spec/cli/data/split_motifs/GABPA_f1.mat.result +14 -14
  69. data/spec/cli/data/split_motifs/KLF4_f2.mat.result +11 -11
  70. data/spec/cli/data/split_motifs/SP1_f1.mat.result +12 -12
  71. data/spec/cli/data/split_motifs/collection.yaml +188 -188
  72. data/spec/cli/data/split_motifs/plain_collection.txt +38 -38
  73. data/spec/cli/merge_into_collection_spec.rb +99 -99
  74. data/spec/cli/pcm2pwm_spec.rb +79 -79
  75. data/spec/cli/shared_examples/convert_motif/motif_list_empty.rb +17 -17
  76. data/spec/cli/shared_examples/convert_motif/several_motifs_specified.rb +14 -14
  77. data/spec/cli/shared_examples/convert_motif/single_motif_specified.rb +49 -49
  78. data/spec/cli/shared_examples/convert_motif/yield_help_string.rb +4 -4
  79. data/spec/cli/shared_examples/convert_motif/yield_motif_conversion_error.rb +3 -3
  80. data/spec/cli/split_motifs_spec.rb +76 -76
  81. data/spec/data_models/collection_spec.rb +97 -97
  82. data/spec/data_models/motif_spec.rb +223 -223
  83. data/spec/data_models/pcm_spec.rb +55 -55
  84. data/spec/data_models/pm_spec.rb +359 -359
  85. data/spec/data_models/ppm_spec.rb +7 -7
  86. data/spec/data_models/pwm_spec.rb +82 -82
  87. data/spec/fabricators/collection_fabricator.rb +7 -7
  88. data/spec/fabricators/motif_fabricator.rb +32 -32
  89. data/spec/fabricators/motif_formats_fabricator.rb +124 -124
  90. data/spec/fabricators/pcm_fabricator.rb +24 -24
  91. data/spec/fabricators/pm_fabricator.rb +51 -51
  92. data/spec/fabricators/ppm_fabricator.rb +13 -13
  93. data/spec/fabricators/pwm_fabricator.rb +16 -16
  94. data/spec/parsers/parser_spec.rb +152 -152
  95. data/spec/parsers/string_fantom_parser_spec.rb +69 -69
  96. data/spec/parsers/string_parser_spec.rb +76 -76
  97. data/spec/parsers/trivial_parser_spec.rb +63 -63
  98. data/spec/parsers/yaml_parser_spec.rb +50 -50
  99. data/spec/spec_helper.rb +10 -10
  100. data/spec/spec_helper_source.rb +59 -59
  101. data/spec/support/advanced_scan_spec.rb +31 -31
  102. data/spec/support/array_product_spec.rb +14 -14
  103. data/spec/support/array_zip_spec.rb +14 -14
  104. data/spec/support/collect_hash_spec.rb +14 -14
  105. data/spec/support/delete_many_spec.rb +43 -43
  106. data/spec/support/inverf_spec.rb +18 -18
  107. data/spec/support/multiline_squish_spec.rb +24 -24
  108. data/spec/support/partial_sums_spec.rb +30 -30
  109. data/spec/support/same_by_spec.rb +35 -35
  110. metadata +3 -3
@@ -1,360 +1,360 @@
1
- require_relative '../spec_helper'
2
- require_relative '../../lib/bioinform/data_models/pm'
3
-
4
- module Bioinform
5
- describe PM do
6
- {:as_pcm => PCM, :as_pwm => PWM, :as_ppm => PPM}.each do |converter_method, result_klass|
7
- describe "##{converter_method}" do
8
- before :each do
9
- @collection = Collection.new(name: 'Collection 1')
10
- @matrix = [[1,2,3,4],[5,6,7,8]]
11
- @name = 'PM_motif'
12
- @background = [0.2,0.3,0.3,0.2]
13
- @tags = [@collection, 'Collection 2']
14
- @pm = PM.new(matrix: @matrix, name: @name, background: @background, tags: @tags)
15
- @conv_motif = @pm.send converter_method
16
- end
17
- it "should return an instance of #{result_klass}" do
18
- @conv_motif.should be_kind_of(result_klass)
19
- end
20
- it 'should return have the same matrix, name and background' do #, background and tags' do
21
- @conv_motif.matrix.should == @matrix
22
- @conv_motif.name.should == @name
23
- @conv_motif.background.should == @background
24
- # @conv_motif.tags.should == @tags
25
- end
26
- end
27
- end
28
-
29
- # describe '#tagged?' do
30
- # context 'when PM marked with Collection object' do
31
- # context 'without collection-name' do
32
- # before :each do
33
- # @marking_collection = Collection.new
34
- # @nonmarking_collection = Collection.new
35
- # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
36
- # @pm.mark(@marking_collection)
37
- # end
38
- # it 'should be true for marking collection' do
39
- # @pm.should be_tagged(@marking_collection)
40
- # end
41
- # it 'should be false for nonmarking collection' do
42
- # @pm.should_not be_tagged(@nonmarking_collection)
43
- # end
44
- # it 'should be false for nil-name' do
45
- # @pm.should_not be_tagged(nil)
46
- # end
47
- # it 'should be false for any string' do
48
- # @pm.should_not be_tagged('Another name')
49
- # end
50
- # end
51
- # context 'with collection-name' do
52
- # before :each do
53
- # @marking_collection = Collection.new(name: 'Collection name')
54
- # @nonmarking_collection = Collection.new(name: 'Another name')
55
- # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
56
- # @pm.mark(@marking_collection)
57
- # end
58
- # it 'should be true for marking collection' do
59
- # @pm.should be_tagged(@marking_collection)
60
- # end
61
- # it 'should be false for nonmarking collection' do
62
- # @pm.should_not be_tagged(@nonmarking_collection)
63
- # end
64
- # it 'should be true for name of marking collection' do
65
- # @pm.should be_tagged('Collection name')
66
- # end
67
- # it 'should be false for string that is not name of marking collection' do
68
- # @pm.should_not be_tagged('Another name')
69
- # end
70
- # end
71
- # end
72
-
73
- # context 'when PM marked with name' do
74
- # before :each do
75
- # @nonmarking_collection = Collection.new(name: 'Another name')
76
- # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
77
- # @pm.mark('Mark name')
78
- # end
79
- # it 'should be true for marking name' do
80
- # @pm.should be_tagged('Mark name')
81
- # end
82
- # it 'should be false for string that is not marking name' do
83
- # @pm.should_not be_tagged('Another name')
84
- # end
85
- # it 'should be false for nonmarking collection' do
86
- # @pm.should_not be_tagged(@nonmarking_collection)
87
- # end
88
- # end
89
-
90
- # context 'when PM marked with several marks' do
91
- # before :each do
92
- # @collection_1 = Collection.new(name: 'First name')
93
- # @collection_2 = Collection.new(name: 'Second name')
94
- # @collection_3 = Collection.new(name: 'Nonmarking collection')
95
- # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
96
- # @pm.mark(@collection_1)
97
- # @pm.mark(@collection_2)
98
- # @pm.mark('Stringy-name')
99
- # end
100
- # it 'should be true for each mark' do
101
- # @pm.should be_tagged(@collection_1)
102
- # @pm.should be_tagged(@collection_2)
103
- # @pm.should be_tagged('Stringy-name')
104
- # end
105
- # it 'should be false for not presented marks' do
106
- # @pm.should_not be_tagged(@collection_3)
107
- # @pm.should_not be_tagged('Bad stringy-name')
108
- # end
109
- # end
110
- # end
111
-
112
- describe '#==' do
113
- it 'should be true iff motifs have the same matrix, background and name' do
114
- pm = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'First motif')
115
- pm_eq = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'First motif')
116
- pm_neq_matrix = PM.new(matrix: [[1,2,3,4],[15,16,17,18]], name: 'First motif')
117
- pm_neq_name = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'Second motif')
118
- pm_neq_background = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'First motif').set_parameters(background: [1,2,2,1])
119
-
120
- pm.should_not == pm_neq_matrix
121
- pm.should_not == pm_neq_name
122
- pm.should_not == pm_neq_background
123
- pm.should == pm_eq
124
- end
125
- end
126
- describe '::valid_matrix?' do
127
- it 'should be true iff an argument is an array of arrays of 4 numerics in a column' do
128
- PM.valid_matrix?( [[1,2,3,4],[1,4,5,6.5]] ).should be_true
129
- PM.valid_matrix?( {A: [1,1], C: [2,4], G: [3,5], T: [4, 6.5]} ).should be_false
130
- PM.valid_matrix?( [{A:1,C:2,G:3,T:4},{A:1,C:4,G:5,T: 6.5}] ).should be_false
131
- PM.valid_matrix?( [[1,2,3,4],[1,4,6.5]] ).should be_false
132
- PM.valid_matrix?( [[1,2,3],[1,4,6.5]] ).should be_false
133
- PM.valid_matrix?( [[1,2,'3','4'],[1,'4','5',6.5]] ).should be_false
134
- end
135
- end
136
-
137
- describe '#to_s' do
138
- before :each do
139
- @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
140
- end
141
- it 'should return string with single-tabulated multiline matrix' do
142
- @pm.to_s.should == "1\t2\t3\t4\n1\t4\t5\t6.5"
143
- end
144
- it 'should return positions in rows, letters in cols' do
145
- @pm.to_s.split("\n").size.should == 2
146
- @pm.to_s.split("\n").map{|pos| pos.split.size}.all?{|sz| sz==4}.should be_true
147
- end
148
- context 'with name specified' do
149
- before :each do
150
- @pm.name = 'Stub name'
151
- end
152
- it 'should return a string with a name and a matrix from the next line' do
153
- @pm.to_s.should == "Stub name\n1\t2\t3\t4\n1\t4\t5\t6.5"
154
- end
155
- it 'should not return a name if argument is set to false' do
156
- @pm.to_s(with_name: false).should == "1\t2\t3\t4\n1\t4\t5\t6.5"
157
- end
158
- end
159
- context 'in letters_as_rows mode' do
160
- it 'should print matrix with row-markers' do
161
- @pm.to_s(letters_as_rows: true).should == "A|1\t1\nC|2\t4\nG|3\t5\nT|4\t6.5"
162
- end
163
- end
164
- end
165
-
166
- describe '#pretty_string' do
167
- it 'should format string with 7-chars fields' do
168
- PM.new( [[1,2,3,4],[5,6,7,8]] ).pretty_string.should == " A C G T \n 1.0 2.0 3.0 4.0\n 5.0 6.0 7.0 8.0"
169
- end
170
- it 'should return a string of floats formatted with spaces' do
171
- PM.new( [[1,2,3,4],[5,6,7,8]] ).pretty_string.should match(/1.0 +2.0 +3.0 +4.0 *\n *5.0 +6.0 +7.0 +8.0/)
172
- end
173
- it 'should contain first string of ACGT letters' do
174
- PM.new( [[1,2,3,4],[5,6,7,8]] ).pretty_string.lines.first.should match(/A +C +G +T/)
175
- end
176
- it 'should round floats upto 3 digits' do
177
- PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] ).pretty_string.should match(/1.1 +2.22 +3.333 +4.444 *\n *5.5 +6.66 +7.777 +8.889/)
178
- end
179
-
180
- context 'with name specified' do
181
- before :each do
182
- @pm = PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] )
183
- @pm.name = 'MyName'
184
- end
185
- it 'should contain name if parameter `with_name` isn\'t false' do
186
- @pm.pretty_string.should match(/MyName\n/)
187
- end
188
- it 'should not contain name if parameter `with_name` is false' do
189
- @pm.pretty_string(with_name: false).should_not match(/MyName\n/)
190
- end
191
- end
192
- context 'without name specified' do
193
- before :each do
194
- @pm = PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] )
195
- end
196
- it 'should not contain name whether parameter `with_name` is or isn\'t false' do
197
- @pm.pretty_string.should_not match(/MyName\n/)
198
- @pm.pretty_string(with_name: false).should_not match(/MyName\n/)
199
- end
200
- end
201
- context 'in letters_as_rows mode' do
202
- it 'should print matrix with row-markers as to_s do' do
203
- @pm = PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] )
204
- @pm.pretty_string(letters_as_rows: true).should == @pm.to_s(letters_as_rows: true)
205
- end
206
- end
207
- end
208
-
209
- describe '#size' do
210
- it 'should return number of positions' do
211
- @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
212
- @pm.size.should == 2
213
- end
214
- end
215
-
216
- describe '#to_hash' do
217
- before :each do
218
- @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
219
- @hsh = @pm.to_hash
220
- end
221
- it 'should return a hash with keys A, C, G, T' do
222
- @hsh.should be_kind_of Hash
223
- @hsh.keys.sort.should == %w{A C G T}
224
- end
225
- it 'should contain matrix elements of corresponding letter' do
226
- @hsh['A'].should == [1, 1]
227
- @hsh['C'].should == [2, 4]
228
- @hsh['G'].should == [3, 5]
229
- @hsh['T'].should == [4, 6.5]
230
- end
231
- it 'should be accessible both by name and symbol (e.g. pm.to_hash[:A] or pm.to_hash[\'A\'] is the same)' do
232
- @hsh['A'].should == @hsh[:A]
233
- @hsh['C'].should == @hsh[:C]
234
- @hsh['G'].should == @hsh[:G]
235
- @hsh['T'].should == @hsh[:T]
236
- end
237
- end
238
-
239
- describe '#background' do
240
- before :each do
241
- @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
242
- end
243
- context 'when pm just created' do
244
- it 'should be [1,1,1,1]' do
245
- @pm.background.should == [1,1,1,1]
246
- end
247
- end
248
- end
249
-
250
- describe '#reverse_complement!' do
251
- before :each do
252
- @pm = PM.new( [[1, 2, 3, 4], [1, 4, 5, 6.5]] )
253
- end
254
- it 'should return pm object itself' do
255
- @pm.reverse_complement!.should be_equal(@pm)
256
- end
257
- it 'should reverse matrix rows and columns' do
258
- @pm.reverse_complement!
259
- @pm.matrix.should == [[6.5, 5, 4, 1], [4, 3, 2, 1]]
260
- end
261
- end
262
-
263
- describe '#left_augment!' do
264
- before :each do
265
- @pm = PM.new( [[1, 2, 3, 4], [1, 4, 5, 6.5]] )
266
- end
267
- it 'should return pm object itself' do
268
- @pm.left_augment!(2).should be_equal(@pm)
269
- end
270
- it 'should add number of zero columns from the left' do
271
- @pm.left_augment!(2)
272
- @pm.matrix.should == [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [1, 2, 3, 4], [1, 4, 5, 6.5]]
273
- end
274
- end
275
-
276
- describe '#right_augment!' do
277
- before :each do
278
- @pm = PM.new( [[1, 2, 3, 4], [1, 4, 5, 6.5]] )
279
- end
280
- it 'should return pm object itself' do
281
- @pm.right_augment!(2).should be_equal(@pm)
282
- end
283
- it 'should add number of zero columns from the right' do
284
- @pm.right_augment!(2)
285
- @pm.matrix.should == [[1, 2, 3, 4], [1, 4, 5, 6.5], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]]
286
- end
287
- end
288
-
289
- describe '#discrete!' do
290
- before :each do
291
- @pm = PM.new( [[1.3, 2.0, 3.2, 4.9], [6.51, 6.5, 3.25, 4.633]] )
292
- end
293
- it 'should return pm object itself' do
294
- @pm.discrete!(10).should be_equal(@pm)
295
- end
296
- context 'rate is 1' do
297
- it 'should discrete each element of matrix' do
298
- @pm.discrete!(1)
299
- @pm.matrix.should == [[2, 2, 4, 5], [7, 7, 4, 5]]
300
- end
301
- end
302
- it 'should discrete each element of matrix multiplied by rate' do
303
- @pm.discrete!(10)
304
- @pm.matrix.should == [[13, 20, 32, 49], [66, 65, 33, 47]]
305
- end
306
- end
307
-
308
- describe '#vocabulary_volume' do
309
- before :each do
310
- @pm_2_positions = PM.new( [[1.3, 2.0, 3.2, 4.9], [5.0, 6.5, 3.2, 4.6]] )
311
- @pm_3_positions = PM.new( [[1.3, 2.0, 3.2, 4.9], [5.0, 6.5, 3.2, 4.6], [1, 2, 3, 4]] )
312
- end
313
- context 'when background is [1,1,1,1]' do
314
- it 'should be equal to number of words' do
315
- @pm_2_positions.vocabulary_volume.should == 4**2
316
- @pm_3_positions.vocabulary_volume.should == 4**3
317
- end
318
- end
319
- context 'when background is normalized probabilities' do
320
- it 'should be 1.0' do
321
- @pm_2_positions.background = [0.2, 0.3, 0.3, 0.2]
322
- @pm_2_positions.vocabulary_volume.should == 1.0
323
-
324
- @pm_3_positions.background = [0.2, 0.3, 0.3, 0.2]
325
- @pm_3_positions.vocabulary_volume.should == 1.0
326
- end
327
- end
328
- end
329
-
330
- [:reverse_complement].each do |meth|
331
- describe "nonbang method #{meth}" do
332
- before :each do
333
- @pm = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
334
- @pm_2 = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
335
- end
336
- it 'should return copy of object not object itself' do
337
- @pm.send(meth).should_not be_equal @pm
338
- end
339
- it 'should == to bang-method' do
340
- @pm.send(meth).to_s.should == @pm_2.send("#{meth}!").to_s
341
- end
342
- end
343
- end
344
-
345
- [:discrete , :left_augment, :right_augment].each do |meth|
346
- describe "nonbang method #{meth}" do
347
- before :each do
348
- @pm = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
349
- @pm_2 = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
350
- end
351
- it 'should return copy of object not object itself' do
352
- @pm.send(meth, 2).should_not be_equal @pm
353
- end
354
- it 'should == to bang-method' do
355
- @pm.send(meth, 2).to_s.should == @pm_2.send("#{meth}!", 2).to_s
356
- end
357
- end
358
- end
359
- end
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/bioinform/data_models/pm'
3
+
4
+ module Bioinform
5
+ describe PM do
6
+ {:as_pcm => PCM, :as_pwm => PWM, :as_ppm => PPM}.each do |converter_method, result_klass|
7
+ describe "##{converter_method}" do
8
+ before :each do
9
+ @collection = Collection.new(name: 'Collection 1')
10
+ @matrix = [[1,2,3,4],[5,6,7,8]]
11
+ @name = 'PM_motif'
12
+ @background = [0.2,0.3,0.3,0.2]
13
+ @tags = [@collection, 'Collection 2']
14
+ @pm = PM.new(matrix: @matrix, name: @name, background: @background, tags: @tags)
15
+ @conv_motif = @pm.send converter_method
16
+ end
17
+ it "should return an instance of #{result_klass}" do
18
+ @conv_motif.should be_kind_of(result_klass)
19
+ end
20
+ it 'should return have the same matrix, name and background' do #, background and tags' do
21
+ @conv_motif.matrix.should == @matrix
22
+ @conv_motif.name.should == @name
23
+ @conv_motif.background.should == @background
24
+ # @conv_motif.tags.should == @tags
25
+ end
26
+ end
27
+ end
28
+
29
+ # describe '#tagged?' do
30
+ # context 'when PM marked with Collection object' do
31
+ # context 'without collection-name' do
32
+ # before :each do
33
+ # @marking_collection = Collection.new
34
+ # @nonmarking_collection = Collection.new
35
+ # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
36
+ # @pm.mark(@marking_collection)
37
+ # end
38
+ # it 'should be true for marking collection' do
39
+ # @pm.should be_tagged(@marking_collection)
40
+ # end
41
+ # it 'should be false for nonmarking collection' do
42
+ # @pm.should_not be_tagged(@nonmarking_collection)
43
+ # end
44
+ # it 'should be false for nil-name' do
45
+ # @pm.should_not be_tagged(nil)
46
+ # end
47
+ # it 'should be false for any string' do
48
+ # @pm.should_not be_tagged('Another name')
49
+ # end
50
+ # end
51
+ # context 'with collection-name' do
52
+ # before :each do
53
+ # @marking_collection = Collection.new(name: 'Collection name')
54
+ # @nonmarking_collection = Collection.new(name: 'Another name')
55
+ # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
56
+ # @pm.mark(@marking_collection)
57
+ # end
58
+ # it 'should be true for marking collection' do
59
+ # @pm.should be_tagged(@marking_collection)
60
+ # end
61
+ # it 'should be false for nonmarking collection' do
62
+ # @pm.should_not be_tagged(@nonmarking_collection)
63
+ # end
64
+ # it 'should be true for name of marking collection' do
65
+ # @pm.should be_tagged('Collection name')
66
+ # end
67
+ # it 'should be false for string that is not name of marking collection' do
68
+ # @pm.should_not be_tagged('Another name')
69
+ # end
70
+ # end
71
+ # end
72
+
73
+ # context 'when PM marked with name' do
74
+ # before :each do
75
+ # @nonmarking_collection = Collection.new(name: 'Another name')
76
+ # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
77
+ # @pm.mark('Mark name')
78
+ # end
79
+ # it 'should be true for marking name' do
80
+ # @pm.should be_tagged('Mark name')
81
+ # end
82
+ # it 'should be false for string that is not marking name' do
83
+ # @pm.should_not be_tagged('Another name')
84
+ # end
85
+ # it 'should be false for nonmarking collection' do
86
+ # @pm.should_not be_tagged(@nonmarking_collection)
87
+ # end
88
+ # end
89
+
90
+ # context 'when PM marked with several marks' do
91
+ # before :each do
92
+ # @collection_1 = Collection.new(name: 'First name')
93
+ # @collection_2 = Collection.new(name: 'Second name')
94
+ # @collection_3 = Collection.new(name: 'Nonmarking collection')
95
+ # @pm = PM.new(matrix:[[1,1,1,1]], name:'Motif name')
96
+ # @pm.mark(@collection_1)
97
+ # @pm.mark(@collection_2)
98
+ # @pm.mark('Stringy-name')
99
+ # end
100
+ # it 'should be true for each mark' do
101
+ # @pm.should be_tagged(@collection_1)
102
+ # @pm.should be_tagged(@collection_2)
103
+ # @pm.should be_tagged('Stringy-name')
104
+ # end
105
+ # it 'should be false for not presented marks' do
106
+ # @pm.should_not be_tagged(@collection_3)
107
+ # @pm.should_not be_tagged('Bad stringy-name')
108
+ # end
109
+ # end
110
+ # end
111
+
112
+ describe '#==' do
113
+ it 'should be true iff motifs have the same matrix, background and name' do
114
+ pm = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'First motif')
115
+ pm_eq = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'First motif')
116
+ pm_neq_matrix = PM.new(matrix: [[1,2,3,4],[15,16,17,18]], name: 'First motif')
117
+ pm_neq_name = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'Second motif')
118
+ pm_neq_background = PM.new(matrix: [[1,2,3,4],[5,6,7,8]], name: 'First motif').set_parameters(background: [1,2,2,1])
119
+
120
+ pm.should_not == pm_neq_matrix
121
+ pm.should_not == pm_neq_name
122
+ pm.should_not == pm_neq_background
123
+ pm.should == pm_eq
124
+ end
125
+ end
126
+ describe '::valid_matrix?' do
127
+ it 'should be true iff an argument is an array of arrays of 4 numerics in a column' do
128
+ PM.valid_matrix?( [[1,2,3,4],[1,4,5,6.5]] ).should be_true
129
+ PM.valid_matrix?( {A: [1,1], C: [2,4], G: [3,5], T: [4, 6.5]} ).should be_false
130
+ PM.valid_matrix?( [{A:1,C:2,G:3,T:4},{A:1,C:4,G:5,T: 6.5}] ).should be_false
131
+ PM.valid_matrix?( [[1,2,3,4],[1,4,6.5]] ).should be_false
132
+ PM.valid_matrix?( [[1,2,3],[1,4,6.5]] ).should be_false
133
+ PM.valid_matrix?( [[1,2,'3','4'],[1,'4','5',6.5]] ).should be_false
134
+ end
135
+ end
136
+
137
+ describe '#to_s' do
138
+ before :each do
139
+ @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
140
+ end
141
+ it 'should return string with single-tabulated multiline matrix' do
142
+ @pm.to_s.should == "1\t2\t3\t4\n1\t4\t5\t6.5"
143
+ end
144
+ it 'should return positions in rows, letters in cols' do
145
+ @pm.to_s.split("\n").size.should == 2
146
+ @pm.to_s.split("\n").map{|pos| pos.split.size}.all?{|sz| sz==4}.should be_true
147
+ end
148
+ context 'with name specified' do
149
+ before :each do
150
+ @pm.name = 'Stub name'
151
+ end
152
+ it 'should return a string with a name and a matrix from the next line' do
153
+ @pm.to_s.should == "Stub name\n1\t2\t3\t4\n1\t4\t5\t6.5"
154
+ end
155
+ it 'should not return a name if argument is set to false' do
156
+ @pm.to_s(with_name: false).should == "1\t2\t3\t4\n1\t4\t5\t6.5"
157
+ end
158
+ end
159
+ context 'in letters_as_rows mode' do
160
+ it 'should print matrix with row-markers' do
161
+ @pm.to_s(letters_as_rows: true).should == "A|1\t1\nC|2\t4\nG|3\t5\nT|4\t6.5"
162
+ end
163
+ end
164
+ end
165
+
166
+ describe '#pretty_string' do
167
+ it 'should format string with 7-chars fields' do
168
+ PM.new( [[1,2,3,4],[5,6,7,8]] ).pretty_string.should == " A C G T \n 1.0 2.0 3.0 4.0\n 5.0 6.0 7.0 8.0"
169
+ end
170
+ it 'should return a string of floats formatted with spaces' do
171
+ PM.new( [[1,2,3,4],[5,6,7,8]] ).pretty_string.should match(/1.0 +2.0 +3.0 +4.0 *\n *5.0 +6.0 +7.0 +8.0/)
172
+ end
173
+ it 'should contain first string of ACGT letters' do
174
+ PM.new( [[1,2,3,4],[5,6,7,8]] ).pretty_string.lines.first.should match(/A +C +G +T/)
175
+ end
176
+ it 'should round floats upto 3 digits' do
177
+ PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] ).pretty_string.should match(/1.1 +2.22 +3.333 +4.444 *\n *5.5 +6.66 +7.777 +8.889/)
178
+ end
179
+
180
+ context 'with name specified' do
181
+ before :each do
182
+ @pm = PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] )
183
+ @pm.name = 'MyName'
184
+ end
185
+ it 'should contain name if parameter `with_name` isn\'t false' do
186
+ @pm.pretty_string.should match(/MyName\n/)
187
+ end
188
+ it 'should not contain name if parameter `with_name` is false' do
189
+ @pm.pretty_string(with_name: false).should_not match(/MyName\n/)
190
+ end
191
+ end
192
+ context 'without name specified' do
193
+ before :each do
194
+ @pm = PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] )
195
+ end
196
+ it 'should not contain name whether parameter `with_name` is or isn\'t false' do
197
+ @pm.pretty_string.should_not match(/MyName\n/)
198
+ @pm.pretty_string(with_name: false).should_not match(/MyName\n/)
199
+ end
200
+ end
201
+ context 'in letters_as_rows mode' do
202
+ it 'should print matrix with row-markers as to_s do' do
203
+ @pm = PM.new( [[1.1,2.22,3.333,4.4444],[5.5,6.66,7.777,8.8888]] )
204
+ @pm.pretty_string(letters_as_rows: true).should == @pm.to_s(letters_as_rows: true)
205
+ end
206
+ end
207
+ end
208
+
209
+ describe '#size' do
210
+ it 'should return number of positions' do
211
+ @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
212
+ @pm.size.should == 2
213
+ end
214
+ end
215
+
216
+ describe '#to_hash' do
217
+ before :each do
218
+ @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
219
+ @hsh = @pm.to_hash
220
+ end
221
+ it 'should return a hash with keys A, C, G, T' do
222
+ @hsh.should be_kind_of Hash
223
+ @hsh.keys.sort.should == %w{A C G T}
224
+ end
225
+ it 'should contain matrix elements of corresponding letter' do
226
+ @hsh['A'].should == [1, 1]
227
+ @hsh['C'].should == [2, 4]
228
+ @hsh['G'].should == [3, 5]
229
+ @hsh['T'].should == [4, 6.5]
230
+ end
231
+ it 'should be accessible both by name and symbol (e.g. pm.to_hash[:A] or pm.to_hash[\'A\'] is the same)' do
232
+ @hsh['A'].should == @hsh[:A]
233
+ @hsh['C'].should == @hsh[:C]
234
+ @hsh['G'].should == @hsh[:G]
235
+ @hsh['T'].should == @hsh[:T]
236
+ end
237
+ end
238
+
239
+ describe '#background' do
240
+ before :each do
241
+ @pm = PM.new( [[1,2,3,4],[1,4,5,6.5]] )
242
+ end
243
+ context 'when pm just created' do
244
+ it 'should be [1,1,1,1]' do
245
+ @pm.background.should == [1,1,1,1]
246
+ end
247
+ end
248
+ end
249
+
250
+ describe '#reverse_complement!' do
251
+ before :each do
252
+ @pm = PM.new( [[1, 2, 3, 4], [1, 4, 5, 6.5]] )
253
+ end
254
+ it 'should return pm object itself' do
255
+ @pm.reverse_complement!.should be_equal(@pm)
256
+ end
257
+ it 'should reverse matrix rows and columns' do
258
+ @pm.reverse_complement!
259
+ @pm.matrix.should == [[6.5, 5, 4, 1], [4, 3, 2, 1]]
260
+ end
261
+ end
262
+
263
+ describe '#left_augment!' do
264
+ before :each do
265
+ @pm = PM.new( [[1, 2, 3, 4], [1, 4, 5, 6.5]] )
266
+ end
267
+ it 'should return pm object itself' do
268
+ @pm.left_augment!(2).should be_equal(@pm)
269
+ end
270
+ it 'should add number of zero columns from the left' do
271
+ @pm.left_augment!(2)
272
+ @pm.matrix.should == [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [1, 2, 3, 4], [1, 4, 5, 6.5]]
273
+ end
274
+ end
275
+
276
+ describe '#right_augment!' do
277
+ before :each do
278
+ @pm = PM.new( [[1, 2, 3, 4], [1, 4, 5, 6.5]] )
279
+ end
280
+ it 'should return pm object itself' do
281
+ @pm.right_augment!(2).should be_equal(@pm)
282
+ end
283
+ it 'should add number of zero columns from the right' do
284
+ @pm.right_augment!(2)
285
+ @pm.matrix.should == [[1, 2, 3, 4], [1, 4, 5, 6.5], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]]
286
+ end
287
+ end
288
+
289
+ describe '#discrete!' do
290
+ before :each do
291
+ @pm = PM.new( [[1.3, 2.0, 3.2, 4.9], [6.51, 6.5, 3.25, 4.633]] )
292
+ end
293
+ it 'should return pm object itself' do
294
+ @pm.discrete!(10).should be_equal(@pm)
295
+ end
296
+ context 'rate is 1' do
297
+ it 'should discrete each element of matrix' do
298
+ @pm.discrete!(1)
299
+ @pm.matrix.should == [[2, 2, 4, 5], [7, 7, 4, 5]]
300
+ end
301
+ end
302
+ it 'should discrete each element of matrix multiplied by rate' do
303
+ @pm.discrete!(10)
304
+ @pm.matrix.should == [[13, 20, 32, 49], [66, 65, 33, 47]]
305
+ end
306
+ end
307
+
308
+ describe '#vocabulary_volume' do
309
+ before :each do
310
+ @pm_2_positions = PM.new( [[1.3, 2.0, 3.2, 4.9], [5.0, 6.5, 3.2, 4.6]] )
311
+ @pm_3_positions = PM.new( [[1.3, 2.0, 3.2, 4.9], [5.0, 6.5, 3.2, 4.6], [1, 2, 3, 4]] )
312
+ end
313
+ context 'when background is [1,1,1,1]' do
314
+ it 'should be equal to number of words' do
315
+ @pm_2_positions.vocabulary_volume.should == 4**2
316
+ @pm_3_positions.vocabulary_volume.should == 4**3
317
+ end
318
+ end
319
+ context 'when background is normalized probabilities' do
320
+ it 'should be 1.0' do
321
+ @pm_2_positions.background = [0.2, 0.3, 0.3, 0.2]
322
+ @pm_2_positions.vocabulary_volume.should == 1.0
323
+
324
+ @pm_3_positions.background = [0.2, 0.3, 0.3, 0.2]
325
+ @pm_3_positions.vocabulary_volume.should == 1.0
326
+ end
327
+ end
328
+ end
329
+
330
+ [:reverse_complement].each do |meth|
331
+ describe "nonbang method #{meth}" do
332
+ before :each do
333
+ @pm = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
334
+ @pm_2 = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
335
+ end
336
+ it 'should return copy of object not object itself' do
337
+ @pm.send(meth).should_not be_equal @pm
338
+ end
339
+ it 'should == to bang-method' do
340
+ @pm.send(meth).to_s.should == @pm_2.send("#{meth}!").to_s
341
+ end
342
+ end
343
+ end
344
+
345
+ [:discrete , :left_augment, :right_augment].each do |meth|
346
+ describe "nonbang method #{meth}" do
347
+ before :each do
348
+ @pm = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
349
+ @pm_2 = PM.new( [[1.3, 2.0, 4.9, 3.2], [7.13, 6.5, 3.25, 4.633], [-1.0, -1.0, -1.5, -1.0]] )
350
+ end
351
+ it 'should return copy of object not object itself' do
352
+ @pm.send(meth, 2).should_not be_equal @pm
353
+ end
354
+ it 'should == to bang-method' do
355
+ @pm.send(meth, 2).to_s.should == @pm_2.send("#{meth}!", 2).to_s
356
+ end
357
+ end
358
+ end
359
+ end
360
360
  end