wrnap 1.0.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a49216040e651785e22f2fe010a08ad6ace0800
4
- data.tar.gz: beb5164b299e498a0a0c1d59ca579efb723aef46
3
+ metadata.gz: b2cc53a30fd53e8dc635b9a6f0e6b9dfc985eefb
4
+ data.tar.gz: ce9692b9164e77fac7b6d4e56ed6398500c19e71
5
5
  SHA512:
6
- metadata.gz: b4262912d96fa147269069032324e0319cc8deb5391dd56376acdea9165c9cc48ddf3d3755c221d9bdc1d503d6bda8840962b5437dc7522a1244571ed089d017
7
- data.tar.gz: 29c9eb3b9c20d32c6cdda08a6629fbf5917bfb482a3b76e2ac1f9150ecc54c799320789387a9d97fc4f8b35810fc4877d0e1667fc3166834a548b7f43d0f06eb
6
+ metadata.gz: 6e5c9b208ddb20f3d9377a40bfa6e5467a35c9012ddd0a0e38bcb47f082de147bd82df8ef7040a9dad2910f87f6bcc18df79b0f187a142f5ba99afa6bcc76d17
7
+ data.tar.gz: cf74fe53fde6cbdf70a7430d6dee2e56cbbcd12ad64b9a9e6c11a68e279b7a46657ffd2fe1b5d5ed9d813e223016f27479a638b72e8f05537ed1f0762cb22f92
@@ -7,7 +7,7 @@ module Wrnap
7
7
  LOCAL_END = /\*\[\s*\d+\s*\]\*/
8
8
 
9
9
  class << self
10
- def parse_file(file)
10
+ def load_all(file)
11
11
  output = File.exist?(file) ? File.read(file) : file
12
12
 
13
13
  if output =~ /No hits detected that satisfy reporting thresholds/
@@ -17,7 +17,7 @@ module Wrnap
17
17
  gsub(/^(.*\n)*Hit alignments:\n/, "").
18
18
  gsub(/Internal CM pipeline statistics summary:\n(.*\n)*$/, "").
19
19
  strip.split(?\n).reject(&:empty?).each_slice(10).map { |lines| parse_hit(lines.join(?\n)) }.compact
20
- end
20
+ end.wrnap
21
21
  end
22
22
 
23
23
  def parse_hit(output)
@@ -4,10 +4,21 @@ module Wrnap
4
4
  class << self
5
5
  def load_all(file)
6
6
  entries = Bio::Stockholm::Reader.parse_from_file(file)[0]
7
- sequences = entries.records.map(&:last).map(&:sequence)
8
- structure = dot_bracket_from_stockholm(entries.gc_features["SS_cons"])
7
+ structure = consensus_structure_from_file(file)
9
8
 
10
- sequences.map { |sequence| fit_structure_to_sequence(sequence, structure) }
9
+ entries.records.map do |label, record|
10
+ fit_structure_to_sequence(record.sequence, structure).tap do |rna|
11
+ rna.comment = if !record.gs_features.nil? && record.gs_features.is_a?(Hash)
12
+ record.gs_features["AC"].split(/[\/-]/).join(" ")
13
+ else
14
+ label.split(/[\/-]/).join(" ")
15
+ end
16
+ end
17
+ end.wrnap
18
+ end
19
+
20
+ def consensus_structure_from_file(file)
21
+ dot_bracket_from_stockholm(Bio::Stockholm::Reader.parse_from_file(file)[0].gc_features["SS_cons"])
11
22
  end
12
23
 
13
24
  def dot_bracket_from_stockholm(structure)
@@ -19,16 +19,18 @@ module Wrnap
19
19
  def sequence_from_entrez(id, position, window)
20
20
  Wrnap.debugger { "Retrieving sequence from Entrez: using nuccore DB (id: #{id}, seq_start: #{position + window.min}, seq_stop: #{position + window.max})" }
21
21
  Wrnap.debugger { "> True starting position: #{position} with window #{window.min} to #{window.max}" }
22
-
22
+
23
23
  fasta = ::Entrez.EFetch("nuccore", {
24
24
  id: id,
25
25
  seq_start: position + window.min,
26
26
  seq_stop: position + window.max,
27
27
  retmode: :fasta,
28
28
  rettype: :text
29
- }).response.body
29
+ })
30
+
31
+ Wrnap.debugger { fasta }
30
32
 
31
- Bio::FastaFormat.new(fasta)
33
+ Bio::FastaFormat.new(fasta.response.body)
32
34
  end
33
35
  end
34
36
  end
@@ -10,6 +10,10 @@ module Wrnap
10
10
  def exec_exists?(name)
11
11
  !%x[which RNA#{name.to_s.downcase}].empty? || !%x[which #{name.to_s.downcase}].empty?
12
12
  end
13
+
14
+ def exec_name
15
+ executable_name.respond_to?(:call) ? executable_name[self] : executable_name
16
+ end
13
17
 
14
18
  def run(*data)
15
19
  flags = data.length > 1 && data.last.is_a?(Hash) ? data.pop : {}
@@ -40,13 +44,23 @@ module Wrnap
40
44
  end
41
45
 
42
46
  def pre_run_check
43
- if %x[which #{exec_name}].empty?
47
+ valid_to_run = if self.class.instance_variable_get(:@pre_run_checked)
48
+ self.class.instance_variable_get(:@valid_to_run)
49
+ else
50
+ Wrnap.debugger { "Checking existence of executable %s." % exec_name }
51
+ self.class.module_eval do
52
+ @pre_run_checked = true
53
+ @valid_to_run = !%x[which #{exec_name}].empty?
54
+ end
55
+ end
56
+
57
+ unless valid_to_run
44
58
  raise RuntimeError.new("#{exec_name} is not defined on this machine")
45
59
  end
46
60
  end
47
61
 
48
62
  def exec_name
49
- executable_name.respond_to?(:call) ? executable_name[self] : executable_name
63
+ self.class.exec_name
50
64
  end
51
65
 
52
66
  def recursively_merge_flags(flags)
@@ -2,10 +2,10 @@ module Wrnap
2
2
  module Graphing
3
3
  module R
4
4
  class << self
5
- def graph(&block)
5
+ def graph(width: 8, height: 6, &block)
6
6
  if const_defined?(:RinRuby)
7
7
  begin
8
- (yield (r_instance = RinRuby.new(false))).tap { r_instance.close }
8
+ generate_graph(r_instance = RinRuby.new(false), width, height, &block).tap { r_instance.close }
9
9
  rescue RuntimeError => e
10
10
  raise unless e.message == "Unsupported data type on R's end"
11
11
  end
@@ -23,11 +23,6 @@ module Wrnap
23
23
  y_range = Range.new(y_points.map(&:min).min.floor, y_points.map(&:max).max.ceil)
24
24
 
25
25
  graph do |r|
26
- r.eval("%s('%s', 6, 6)" % [
27
- writing_file?(filename) ? filetype(filename) : "quartz",
28
- writing_file?(filename) ? filename : "Graph",
29
- ])
30
-
31
26
  r.assign("legend.titles", data.each_with_index.map { |hash, index| hash[:legend] || "Line #{index + 1}" })
32
27
  r.eval("line.colors <- rainbow(%d)" % data.size)
33
28
  r.eval("plot(0, 0, type = 'n', cex = .75, cex.axis = .9, xlab = '', ylab = '', xlim = c(%d, %d), ylim = c(%d, %d))" % [
@@ -73,8 +68,6 @@ module Wrnap
73
68
  )
74
69
  STR
75
70
  end
76
-
77
- r.eval("dev.off()") if writing_file?(filename)
78
71
  end
79
72
  end
80
73
 
@@ -115,7 +108,6 @@ module Wrnap
115
108
  end
116
109
  end
117
110
 
118
-
119
111
  overlay(
120
112
  formatted_data,
121
113
  title: title,
@@ -135,11 +127,6 @@ module Wrnap
135
127
  r.assign("histogram.data", data)
136
128
  r.assign("histogram.breaks", breaks)
137
129
 
138
- r.eval("%s('%s', 6, 6)" % [
139
- writing_file?(filename) ? filetype(filename) : "quartz",
140
- writing_file?(filename) ? filename : "Graph",
141
- ])
142
-
143
130
  r.eval <<-STR
144
131
  hist(
145
132
  histogram.data,
@@ -154,8 +141,6 @@ module Wrnap
154
141
  STR
155
142
 
156
143
  r.eval("abline(v = #{x_arrow}, lty = 'dashed')") if x_arrow
157
-
158
- r.eval("dev.off()") if writing_file?(filename)
159
144
  end
160
145
  end
161
146
 
@@ -179,26 +164,22 @@ module Wrnap
179
164
  x = matrix.x,
180
165
  index1 = F
181
166
  )
167
+
168
+ filtered.values <- Filter(function(i) { is.finite(i) & i != 0 }, matrix.x)
169
+ print(apply(as.matrix(matrix.data), 2, rev))
170
+ print(c(sort(filtered.values)[2], max(filtered.values)))
171
+
172
+ image(
173
+ x = 1:max(c(dim(matrix.data)[[1]], dim(matrix.data)[[2]])),
174
+ y = 1:max(c(dim(matrix.data)[[1]], dim(matrix.data)[[2]])),
175
+ z = as.matrix(matrix.data),
176
+ col = rev(heat.colors(#{num_colors})),
177
+ zlim = #{forced_square ? "c(sort(filtered.values)[2], max(filtered.values))" : "c(min(filtered.values), max(filtered.values))"},
178
+ xlab = "#{x_label} (1-indexed)",
179
+ ylab = "#{y_label} (1-indexed)"
180
+ )
181
+ title(#{expressionify(title || "Matrix Heatmap")})
182
182
  STR
183
-
184
- generate_graph("Heatmap") do
185
- <<-STR
186
- filtered.values <- Filter(function(i) { is.finite(i) & i != 0 }, matrix.x)
187
- print(apply(as.matrix(matrix.data), 2, rev))
188
- print(c(sort(filtered.values)[2], max(filtered.values)))
189
-
190
- image(
191
- x = 1:max(c(dim(matrix.data)[[1]], dim(matrix.data)[[2]])),
192
- y = 1:max(c(dim(matrix.data)[[1]], dim(matrix.data)[[2]])),
193
- z = as.matrix(matrix.data),
194
- col = rev(heat.colors(#{num_colors})),
195
- zlim = #{forced_square ? "c(sort(filtered.values)[2], max(filtered.values))" : "c(min(filtered.values), max(filtered.values))"},
196
- xlab = "#{x_label} (1-indexed)",
197
- ylab = "#{y_label} (1-indexed)"
198
- )
199
- title(#{expressionify(title || "Matrix Heatmap")})
200
- STR
201
- end
202
183
  else
203
184
  puts "Please install the Matrix package for R before using this function."
204
185
  end
@@ -207,15 +188,17 @@ module Wrnap
207
188
 
208
189
  private
209
190
 
210
- def generate_graph(window_title = "ViennaRNA Graph in R", &block)
211
- r, filename = block.binding.eval("[r, filename]")
191
+ def generate_graph(r, width, height, &block)
192
+ filename = block.binding.eval("filename")
212
193
 
213
- r.eval("%s('%s', 6, 6)" % [
194
+ r.eval("%s('%s', %d, %d)" % [
214
195
  writing_file?(filename) ? filetype(filename) : "quartz",
215
196
  writing_file?(filename) ? filename : "Graph",
197
+ width,
198
+ height
216
199
  ])
217
200
 
218
- r.eval(yield)
201
+ yield r
219
202
 
220
203
  r.eval("dev.off()") if writing_file?(filename)
221
204
  end
@@ -10,7 +10,7 @@ module Wrnap
10
10
  include Wrnap::Global::Yaml
11
11
 
12
12
  class_attribute :executable_name
13
- self.executable_name = ->(context) { "RNA#{context.class.name.split('::').last.underscore}" }
13
+ self.executable_name = ->(context) { "RNA#{context.name.split('::').last.underscore}" }
14
14
 
15
15
  class_attribute :call_with
16
16
  self.call_with = [:seq]
@@ -15,7 +15,7 @@ module Wrnap
15
15
  self.quote_flag_params = %w|sequenceDBN structureDBN title|
16
16
 
17
17
  def run_command(flags)
18
- "java fr.orsay.lri.varna.applications.VARNAcmd %s" % stringify_flags(flags)
18
+ "java -Djava.awt.headless=true fr.orsay.lri.varna.applications.VARNAcmd %s" % stringify_flags(flags)
19
19
  end
20
20
  end
21
21
  end
@@ -5,7 +5,7 @@ module Wrnap
5
5
  E: "/usr/local/bin/rna_turner2004.par"
6
6
  }
7
7
 
8
- self.executable_name = ->(context) { context.class.name.demodulize.gsub(/^([A-Z].*)bor$/) { |match| $1.upcase + "bor" } }
8
+ self.executable_name = ->(context) { context.name.demodulize.gsub(/^([A-Z].*)bor$/) { |match| $1.upcase + "bor" } }
9
9
 
10
10
  def run_command(flags)
11
11
  file = Tempfile.new("rna")
data/lib/wrnap/rna/box.rb CHANGED
@@ -9,13 +9,19 @@ module Wrnap
9
9
 
10
10
  class << self
11
11
  def load_all(pattern = "*.fa", &block)
12
- new(Dir[File.directory?(pattern) ? pattern + "/*.fa" : pattern].map { |file| RNA.from_fasta(file, &block) })
12
+ new(Dir[File.directory?(pattern) ? pattern + "/*.fa" : pattern].inject([]) { |array, file| array + RNA.from_fasta(file, &block).rnas })
13
13
  end
14
14
  end
15
15
 
16
16
  def initialize(rnas)
17
17
  @rnas = rnas.kind_of?(Array) ? rnas : [rnas]
18
18
  end
19
+
20
+ def write_fa!(filename)
21
+ filename.tap do |filename|
22
+ File.open(filename, ?w) { |file| file.write(rnas.map(&:formatted_string).join(?\n) + ?\n) }
23
+ end
24
+ end
19
25
 
20
26
  def pp
21
27
  rnas.each(&:pp) and nil
@@ -25,15 +31,27 @@ module Wrnap
25
31
  self.class.new(rnas + (arrayish.is_a?(Box) ? arrayish.rnas : arrayish))
26
32
  end
27
33
 
28
- def_delegators :@rnas, *%i|size length [] []= <<|
34
+ def_delegators :@rnas, *%i|size length first last [] []= <<|
29
35
 
30
36
  def each(&block)
37
+ return enum_for(:each) unless block_given?
31
38
  rnas.each(&block)
32
39
  end
40
+
41
+ def run_in_parallel(method, *args)
42
+ Wrnap.debug, debug_status = false, Wrnap.debug
43
+ Parallel.map(self, progress: "Calling %s on %d RNAs" % [method, rnas.size]) { |rna| rna.send(method, *args) }.tap { Wrnap.debug = debug_status }
44
+ end
33
45
 
34
46
  def kind_of?(klass)
35
47
  klass == Array ? true : super
36
48
  end
49
+
50
+ def method_missing(name, *args, &block)
51
+ if (name_str = "#{name}") =~ /^run_\w+$/
52
+ run_in_parallel(name_str, *args)
53
+ else super end
54
+ end
37
55
 
38
56
  def inspect
39
57
  "#<Wrnap::Rna::Box with %d RNAs>" % rnas.size
@@ -9,6 +9,10 @@ module Wrnap
9
9
  def constraint_mask
10
10
  md[:constraint_mask]
11
11
  end
12
+
13
+ def show_constraints(&block)
14
+ ConstraintBox.new(metadata.__rna__).tap { |box| box.instance_eval(&block) }.to_s
15
+ end
12
16
 
13
17
  def build_constraints(&block)
14
18
  meta_rna do |metadata|
@@ -23,6 +27,10 @@ module Wrnap
23
27
  def initialize(rna)
24
28
  @rna, @constraints = rna, []
25
29
  end
30
+
31
+ def n
32
+ rna.len - 1
33
+ end
26
34
 
27
35
  def between(i, j)
28
36
  Loop.new(i, j)
@@ -32,10 +40,25 @@ module Wrnap
32
40
  between(i + 1, j - 1)
33
41
  end
34
42
 
43
+ def start_to(i)
44
+ between(0, i)
45
+ end
46
+
47
+ def end_to(i)
48
+ between(i, n)
49
+ end
50
+
51
+ def freeze(mask_object)
52
+ force mask_object
53
+ prohibit mask_object.unpaired_regions
54
+ end
55
+
35
56
  def mask!(mask_object, *args)
36
57
  case mask_object
37
- when Helix then mask_helix!(mask_object, *args)
38
- when Loop then mask_loop!(mask_object, symbol: args[0][:symbol])
58
+ when TreeStem then mask_object.preorder_traversal { |node| mask!(node.content, *args) }
59
+ when Array then mask_object.map { |node| mask!(node, *args) }
60
+ when Helix then mask_helix!(mask_object, *args)
61
+ when Loop then mask_loop!(mask_object, symbol: args[0][:symbol])
39
62
  end
40
63
  end
41
64
 
@@ -1,14 +1,16 @@
1
1
  module Wrnap
2
2
  class Rna
3
3
  class Context < Rna
4
+ extend Forwardable
5
+
4
6
  attr_reader :accession, :from, :to, :coord_options
5
7
 
6
8
  class << self
7
9
  def init_from_entrez(accession, from, to, options = {}, &block)
8
10
  new(
9
11
  accession: accession,
10
- from: from,
11
- to: to,
12
+ from: from.to_i,
13
+ to: to.to_i,
12
14
  options: options,
13
15
  &block
14
16
  )
@@ -18,8 +20,8 @@ module Wrnap
18
20
  new(
19
21
  sequence: sequence,
20
22
  accession: accession,
21
- from: from,
22
- to: to,
23
+ from: from.to_i,
24
+ to: to.to_i,
23
25
  options: options,
24
26
  &block
25
27
  )
@@ -102,6 +104,8 @@ module Wrnap
102
104
  end
103
105
 
104
106
  alias :seq :sequence
107
+
108
+ def_delegator :@raw_sequence, :length, :len
105
109
 
106
110
  def extend!(coord_options = {})
107
111
  self.class.init_from_entrez(accession, from, to, coords: coord_options)
@@ -126,14 +130,22 @@ module Wrnap
126
130
  range
127
131
  end
128
132
  end
129
-
133
+
130
134
  def identifier
131
- "%s %d %s %d" % [accession, from, plus_strand? ? ?+ : ?-, to]
135
+ "%s %d %s %d" % [accession, seq_from, plus_strand? ? ?+ : ?-, seq_to]
136
+ end
137
+
138
+ def _id
139
+ identifier.gsub(/[^A-Z0-9]/, ?_).gsub(/__+/, ?_)
132
140
  end
133
141
 
134
142
  def inspect
135
- super.gsub(/((\w(::)?)+)>$/) { |_| "%s %s>" % [identifier, $1] }
143
+ if super.match(/Wrnap::(\w+(::)?)+>$/)
144
+ super.sub(/([\w:]+)>$/) { |_| "%s %s>" % [identifier, $1] }
145
+ else
146
+ super
147
+ end
136
148
  end
137
149
  end
138
150
  end
139
- end
151
+ end
@@ -39,8 +39,53 @@ module Wrnap
39
39
  end
40
40
 
41
41
  module InstanceMethods
42
+ def hamming_distance(other_rna)
43
+ raise "The two sequences are not the same length" unless len == other_rna.len
44
+
45
+ [seq, other_rna.seq].map(&:each_char).map(&:to_a).transpose.select { |array| array.uniq.size > 1 }.count
46
+ end
47
+
48
+ def local_structural_shuffle(dishuffle: false)
49
+ sequence = " " * len
50
+ loops, helices = loops_and_helices
51
+
52
+ loops.each { |loop| sequence[loop.i..loop.j] = Shuffle.new(loop.in(seq)).send(dishuffle ? :dishuffle : :shuffle) }
53
+ helices.each do |helix|
54
+ left_stem, right_stem = if dishuffle
55
+ Shuffle.new(helix.in(seq)).dishuffle
56
+ else
57
+ Shuffle.new(helix.in(seq)).shuffle.map { |array| rand(2).zero? ? array : array.reverse }
58
+ end.transpose.map(&:join)
59
+
60
+ sequence[helix.i..helix.k] = left_stem
61
+ sequence[helix.l..helix.j] = right_stem.reverse
62
+ end
63
+
64
+ Rna.init_from_string(sequence, str)
65
+ end
66
+
67
+ def local_structural_dishuffle
68
+ local_structural_shuffle(dishuffle: true)
69
+ end
70
+
71
+ def global_structural_shuffle
72
+ sequence = " " * len
73
+ loops, helices = loops_and_helices
74
+ shuffled_loops = Shuffle.new(loops.map { |loop| loop.in(seq) }.join.split(//)).shuffle
75
+ shuffled_helices = helices.map { |helix| helix.in(seq) }.inject(&:+).shuffle.map { |array| rand(2).zero? ? array : array.reverse }
76
+
77
+ loops.each { |loop| sequence[loop.i..loop.j] = shuffled_loops.shift(loop.length).join }
78
+ helices.each do |helix|
79
+ left_stem, right_stem = shuffled_helices.shift(helix.length).transpose.map(&:join)
80
+ sequence[helix.i..helix.k] = left_stem
81
+ sequence[helix.l..helix.j] = right_stem.reverse
82
+ end
83
+
84
+ Rna.init_from_string(sequence, str)
85
+ end
86
+
42
87
  def dishuffle
43
- self.class.shuffle(sequence, 2)
88
+ Rna.init_from_string(self.class.shuffle(sequence, 2))
44
89
  end
45
90
 
46
91
  def gc_content
@@ -56,6 +101,33 @@ module Wrnap
56
101
  def max_bp_distance(structure)
57
102
  base_pairs(structure).count + ((structure.length - 3) / 2.0).floor
58
103
  end
104
+
105
+ def loops_and_helices(structure)
106
+ [loop_regions(structure), collapsed_helices(structure, lonely_bp: true)]
107
+ end
108
+
109
+ def loop_regions(structure)
110
+ [structure.split(//), (0...structure.length).to_a].transpose.select { |char, _| char == ?. }.inject([]) do |array, (_, index)|
111
+ array.tap do
112
+ matching_loop = array.map(&:last).each_with_index.find { |end_of_loop, _| end_of_loop + 1 == index }
113
+ matching_loop ? array[matching_loop[-1]][-1] += 1 : array << [index, index]
114
+ end
115
+ end.map { |loop_indices| Loop.new(*loop_indices) }
116
+ end
117
+
118
+ def helices(structure)
119
+ unless (array = base_pairs(structure).sort_by(&:first).map(&:to_a)).empty?
120
+ array[1..-1].inject([[array.first]]) do |bins, (i, j)|
121
+ bins.tap { bins[-1][-1] == [i - 1, j + 1] ? bins[-1] << [i, j] : bins << [[i, j]] }
122
+ end
123
+ else
124
+ []
125
+ end
126
+ end
127
+
128
+ def collapsed_helices(structure, lonely_bp: false)
129
+ helices(structure).map { |((i, j), *rest)| Helix.new(i, j, rest.length + 1) }.select { |helix| lonely_bp ? helix : helix.length > 1 }
130
+ end
59
131
 
60
132
  def base_pairs(structure)
61
133
  get_pairings(structure).each_with_index.inject(Set.new) do |set, (j, i)|
@@ -1,23 +1,5 @@
1
1
  module Wrnap
2
- class Rna
3
- module Motifs
4
- def helices
5
- array = base_pairs.sort_by(&:first).map(&:to_a)
6
-
7
- unless array.empty?
8
- array[1..-1].inject([[array.first]]) do |bins, (i, j)|
9
- bins.tap { bins[-1][-1] == [i - 1, j + 1] ? bins[-1] << [i, j] : bins << [[i, j]] }
10
- end
11
- else
12
- []
13
- end
14
- end
15
-
16
- def collapsed_helices(lonely_bp: false)
17
- helices.map { |((i, j), *rest)| Helix.new(i, j, rest.length + 1) }.select { |helix| lonely_bp ? helix : helix.length > 1 }
18
- end
19
- end
20
-
2
+ class Rna
21
3
  class Helix
22
4
  attr_reader :i, :j, :length
23
5
 
@@ -28,9 +10,26 @@ module Wrnap
28
10
  def k; i + length - 1; end
29
11
  def l; j - length + 1; end
30
12
 
13
+ def in(sequence)
14
+ (0...length).map do |stem_position|
15
+ [sequence[i + stem_position], sequence[j - stem_position]]
16
+ end
17
+ end
18
+
31
19
  def to_loops
32
20
  [Loop.new(i, k), Loop.new(l, j)]
33
21
  end
22
+
23
+ def apply!(structure)
24
+ structure.tap do
25
+ structure[i, length] = ?( * length
26
+ structure[l, length] = ?) * length
27
+ end
28
+ end
29
+
30
+ def merge!(helix)
31
+ @length = helix.k - i + 1
32
+ end
34
33
 
35
34
  def reindex!(rna)
36
35
  tap do
@@ -45,7 +44,7 @@ module Wrnap
45
44
  end
46
45
 
47
46
  def name
48
- "(%d..%d, %d..%d)" % [i, k, l, j]
47
+ "(%d..%d, %d..%d [%d])" % [i, k, l, j, length]
49
48
  end
50
49
 
51
50
  def inspect
@@ -60,8 +59,16 @@ module Wrnap
60
59
  @i, @j = i, j
61
60
  end
62
61
 
62
+ def in(sequence)
63
+ sequence[i..j]
64
+ end
65
+
66
+ def length
67
+ j - i + 1
68
+ end
69
+
63
70
  def name
64
- "(%d, %d)" % [i, j]
71
+ "(%d, %d [%d])" % [i, j, length]
65
72
  end
66
73
 
67
74
  def inspect
@@ -14,19 +14,84 @@ module Wrnap
14
14
  extend Forwardable
15
15
  include Enumerable
16
16
 
17
- STEM_NOTATION_REGEX = /^p((\d+_)*(\d+))(_?([ijkl]))?$/
17
+ STEM_NOTATION_REGEX = /^[pt]_?(\d+_)*\d+(_?[ijkl])?$/
18
18
 
19
- def_delegators :@content, :i, :j
19
+ def_delegators :@content, :i, :j, :k, :l
20
20
  def_delegator :@content, :length, :stem_length
21
+
22
+ def unpaired_regions
23
+ Wrnap.debugger { "Collecting unpaired regions for %s" % [root.content.name] }
24
+
25
+ postorder_traversal.inject([]) do |array, node|
26
+ array.tap do
27
+ if node.is_leaf?
28
+ array << Loop.new(node.k + 1, node.l - 1)
29
+ end
30
+
31
+ if node != self
32
+ if node.is_only_child?
33
+ Wrnap.debugger { "Interior node: %s, parent: %s" % [node.content.inspect, node.parent.content.inspect] }
34
+
35
+ if node.i - node.parent.k > 0
36
+ Wrnap.debugger { "Left bulge." }
37
+ array << Loop.new(node.parent.k + 1, node.i - 1)
38
+ end
39
+
40
+ if node.parent.l - node.j > 0
41
+ Wrnap.debugger { "Right bulge." }
42
+ array << Loop.new(node.j + 1, node.parent.l - 1)
43
+ end
44
+ else
45
+ node_index = node.parent.children.each_with_index.find { |child, _| child == node }.last
46
+
47
+ if node.is_last_sibling?
48
+ Wrnap.debugger { "Leaf node, last child: %s" % node.content.inspect }
49
+ array << Loop.new(node.j + 1, node.parent.l - 1)
50
+ else
51
+ if node.is_first_sibling?
52
+ Wrnap.debugger { "Leaf node, first child: %s" % node.content.inspect }
53
+ array << Loop.new(node.parent.k + 1, node.i - 1)
54
+ end
55
+
56
+ Wrnap.debugger { "Connecting node, middle child: %s" % node.content.inspect }
57
+ alexa = node.siblings[node_index]
58
+ array << Loop.new(node.j + 1, alexa.i - 1)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def detached_copy
67
+ self.class.new(@name, @content ? @content.clone : nil)
68
+ end
69
+
70
+ def preorder_traversal(&block)
71
+ return enum_for(:preorder_traversal) unless block_given?
72
+ yield self
73
+ children.map { |child| child.preorder_traversal(&block) }
74
+ end
75
+
76
+ def postorder_traversal(&block)
77
+ return enum_for(:postorder_traversal) unless block_given?
78
+ children.each { |child| child.postorder_traversal(&block) }
79
+ yield self
80
+ end
21
81
 
22
82
  def method_missing(name, *args, &block)
23
- if name.to_s =~ STEM_NOTATION_REGEX
24
- if $2 && child = children[$2.to_i - 1]
25
- child.send("p%s" % name.to_s.gsub(/^p\d+_/, ""))
26
- elsif child = children[$1.to_i - 1]
27
- $5 ? child.content.send($5) : child.content
28
- else
29
- nil
83
+ if (method_name = name.to_s) =~ STEM_NOTATION_REGEX
84
+ call_type = method_name[0]
85
+ indices = method_name.gsub(/\D+/, ?_).split(?_).reject(&:empty?).map(&:to_i)
86
+ helix_index = method_name.match(/([ijkl])$/) ? $1 : ""
87
+
88
+ if indices.size > 1 && child = children[indices[0] - 1]
89
+ child.send(call_type + indices[1..-1].join(?_) + helix_index)
90
+ elsif child = children[indices[0] - 1]
91
+ case call_type
92
+ when ?p then helix_index.empty? ? child.content : child.send(helix_index)
93
+ when ?t then child
94
+ end
30
95
  end
31
96
  else super end
32
97
  end
@@ -85,14 +150,35 @@ module Wrnap
85
150
  def coalesce!
86
151
  tap { merge_interior_loops! }
87
152
  end
153
+
154
+ def fuse
155
+ self.class.new(rna, root.dup).tap { |tree| tree.extend_interior_loops! }
156
+ end
88
157
 
158
+ def fuse!
159
+ tap { extend_interior_loops! }
160
+ end
161
+
162
+ def extend_interior_loops!
163
+ handle_interior_loops! do |node, child|
164
+ node.content.merge!(child.content)
165
+ child.remove_from_parent!
166
+ child.children.each { |grandchild| node.add(grandchild) }
167
+ end
168
+ end
169
+
89
170
  def merge_interior_loops!
171
+ handle_interior_loops! do |node, child|
172
+ node.parent.add(child)
173
+ node.remove_from_parent!
174
+ end
175
+ end
176
+
177
+ def handle_interior_loops!(&block)
90
178
  root.tap do
91
- self.class.postorder_traversal(root) do |node|
92
- if node.children.count == 1 && !node.is_root?
93
- child = node.children.first
94
- node.parent.add(child)
95
- node.remove_from_parent!
179
+ root.postorder_traversal do |node|
180
+ if node.children.count == 1 && !node.is_root?
181
+ yield(node, node.children.first)
96
182
  end
97
183
  end
98
184
 
@@ -119,18 +205,6 @@ module Wrnap
119
205
  root.send(name, *args, &block)
120
206
  else super end
121
207
  end
122
-
123
- class << self
124
- def preorder_traversal(node, &block)
125
- node.children.map { |child| preorder_traversal(child, &block) }
126
- yield node
127
- end
128
-
129
- def postorder_traversal(node, &block)
130
- node.children.map { |child| postorder_traversal(child, &block) }
131
- yield node
132
- end
133
- end
134
208
  end
135
209
  end
136
210
  end
data/lib/wrnap/rna.rb CHANGED
@@ -5,7 +5,6 @@ module Wrnap
5
5
  include Wrnap::Rna::Extensions
6
6
  include Wrnap::Rna::Wrnapper
7
7
  include Wrnap::Rna::Metadata
8
- include Wrnap::Rna::Motifs
9
8
  include Wrnap::Rna::TreeFunctions
10
9
  include Wrnap::Rna::Constraints
11
10
 
@@ -44,12 +43,19 @@ module Wrnap
44
43
  comment = File.basename(string, string.include?(?.) ? ".%s" % string.split(?.)[-1] : "")
45
44
  string = File.read(string).chomp
46
45
  end
47
-
48
- init_from_string(*string.split(/\n/).reject { |line| line.start_with?(">") }[0, 3], &block).tap do |rna|
49
- if (line = string.split(/\n/).first).start_with?(">") && !(file_comment = line.gsub(/^>\s*/, "")).empty?
50
- rna.comment = file_comment
51
- elsif comment
52
- rna.comment = comment
46
+
47
+ if string.count(?>) > 1
48
+ string.split(/>/).reject(&:empty?).map do |rna_string|
49
+ rna_data = rna_string.split(?\n)
50
+ init_from_string(*rna_data[1..-1]).copy_name_from(rna_data[0])
51
+ end.wrnap
52
+ else
53
+ init_from_string(*string.split(/\n/).reject { |line| line.start_with?(">") }[0, 3], &block).tap do |rna|
54
+ if (line = string.split(/\n/).first).start_with?(">") && !(file_comment = line.gsub(/^>\s*/, "")).empty?
55
+ rna.comment = file_comment
56
+ elsif comment
57
+ rna.comment = comment
58
+ end
53
59
  end
54
60
  end
55
61
  end
@@ -62,8 +68,8 @@ module Wrnap
62
68
  # This happens when you call a Wrnap library function with the output of something like Wrnap::Fold.run(...).mfe
63
69
  new(
64
70
  sequence: rna.sequence,
65
- strucutre: rna.structure,
66
- second_strucutre: rna.second_structure,
71
+ structure: rna.structure,
72
+ second_structure: rna.second_structure,
67
73
  comment: rna.comment,
68
74
  &block
69
75
  )
@@ -111,8 +117,8 @@ module Wrnap
111
117
 
112
118
  def_delegator :@sequence, :length, :len
113
119
 
114
- def copy_name_from(rna)
115
- tap { @comment = rna.name }
120
+ def copy_name_from(nameish)
121
+ tap { @comment = nameish.is_a?(String) ? nameish : nameish.name }
116
122
  end
117
123
 
118
124
  def empty_structure
@@ -142,15 +148,19 @@ module Wrnap
142
148
  end
143
149
 
144
150
  alias :two_str :two_structures
151
+
152
+ def formatted_string
153
+ [
154
+ (">%s" % name if name),
155
+ ("%s" % seq if seq),
156
+ ("%s" % str_1 if str_1),
157
+ ("%s" % str_2 if str_2)
158
+ ].compact.join(?\n)
159
+ end
145
160
 
146
161
  def write_fa!(filename)
147
162
  filename.tap do |filename|
148
- File.open(filename, ?w) do |file|
149
- file.write("> %s\n" % name) if name
150
- file.write("%s\n" % seq) if seq
151
- file.write("%s\n" % str_1) if str_1
152
- file.write("%s\n" % str_2) if str_2
153
- end
163
+ File.open(filename, ?w) { |file| file.write(formatted_string) }
154
164
  end
155
165
  end
156
166
 
@@ -177,18 +187,14 @@ module Wrnap
177
187
  end
178
188
 
179
189
  def pp
180
- puts("> %s" % name) if name
181
- puts("%s" % seq) if seq
182
- puts("%s" % str_1) if str_1
183
- puts("%s" % str_2) if str_2
184
- puts("%s" % meta.inspect) if meta
190
+ puts(formatted_string)
185
191
  end
186
-
192
+
187
193
  def inspect
188
194
  "#<RNA: %s>" % [
189
- ("#{seq[0, 20] + (len > 20 ? '... [%d]' % len : '')}" if seq && !seq.empty?),
190
- ("#{str_1[0, 20] + (str_1.length > 20 ? ' [%d]' % len : '')}" if str_1 && !str_1.empty?),
191
- ("#{str_2[0, 20] + (str_2.length > 20 ? ' [%d]' % len : '')}" if str_2 && !str_1.empty?),
195
+ ("#{seq[0, 20] + (len > 20 ? '... [%d]' % len : '')}" if seq && !seq.empty?),
196
+ ("#{str_1[0, 20] + (str_1.length > 20 ? ' [%d]' % str_1.length : '')}" if str_1 && !str_1.empty?),
197
+ ("#{str_2[0, 20] + (str_2.length > 20 ? ' [%d]' % str_2.length : '')}" if str_2 && !str_1.empty?),
192
198
  (md.inspect unless md.nil? || md.empty?),
193
199
  (name ? name : "#{self.class.name}")
194
200
  ].compact.join(", ")
data/lib/wrnap/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Wrnap
2
- VERSION = "1.0.1"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/wrnap.rb CHANGED
@@ -1,16 +1,17 @@
1
- require "yaml"
1
+ require "active_support/core_ext/class"
2
+ require "active_support/inflector"
2
3
  require "benchmark"
3
- require "set"
4
- require "tree"
5
- require "shuffle"
6
- require "tempfile"
7
4
  require "bigdecimal"
8
- require "rroc"
9
5
  require "bio"
10
6
  require "bio-stockholm"
11
7
  require "entrez"
12
- require "active_support/inflector"
13
- require "active_support/core_ext/class"
8
+ require "parallel"
9
+ require "rroc"
10
+ require "set"
11
+ require "shuffle"
12
+ require "tempfile"
13
+ require "tree"
14
+ require "yaml"
14
15
 
15
16
  unless %x[which R].empty?
16
17
  require "rinruby"
data/wrnap.gemspec CHANGED
@@ -23,12 +23,14 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.6"
24
24
  spec.add_development_dependency "rake"
25
25
 
26
- spec.add_runtime_dependency "activesupport", "~> 4.0"
27
- spec.add_runtime_dependency "shuffle", "~> 0.1"
28
- spec.add_runtime_dependency "rinruby", "~> 2.0"
29
- spec.add_runtime_dependency "rroc", "~> 0.1"
30
- spec.add_runtime_dependency "bio", "~> 1.4"
31
- spec.add_runtime_dependency "bio-stockholm", "~> 0.0.1"
32
- spec.add_runtime_dependency "entrez", "~> 0.5"
33
- spec.add_runtime_dependency "rubytree", "~> 0.9"
26
+ spec.add_runtime_dependency "activesupport", "~> 4.0"
27
+ spec.add_runtime_dependency "bio", "~> 1.4"
28
+ spec.add_runtime_dependency "bio-stockholm", "~> 0.0.1"
29
+ spec.add_runtime_dependency "entrez", "~> 0.5"
30
+ spec.add_runtime_dependency "parallel", "~> 1.3", ">= 1.3.2"
31
+ spec.add_runtime_dependency "rinruby", "~> 2.0"
32
+ spec.add_runtime_dependency "rroc", "~> 0.1"
33
+ spec.add_runtime_dependency "ruby-progressbar", "~> 1.5", ">= 1.5.1"
34
+ spec.add_runtime_dependency "rubytree", "~> 0.9"
35
+ spec.add_runtime_dependency "shuffle", "~> 1.0", ">= 1.0.1"
34
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wrnap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Senter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-31 00:00:00.000000000 Z
11
+ date: 2014-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,89 +53,115 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '4.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: shuffle
56
+ name: bio
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.1'
61
+ version: '1.4'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.1'
68
+ version: '1.4'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rinruby
70
+ name: bio-stockholm
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '2.0'
75
+ version: 0.0.1
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.0'
82
+ version: 0.0.1
83
83
  - !ruby/object:Gem::Dependency
84
- name: rroc
84
+ name: entrez
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.1'
89
+ version: '0.5'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.1'
96
+ version: '0.5'
97
97
  - !ruby/object:Gem::Dependency
98
- name: bio
98
+ name: parallel
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.4'
103
+ version: '1.3'
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 1.3.2
104
107
  type: :runtime
105
108
  prerelease: false
106
109
  version_requirements: !ruby/object:Gem::Requirement
107
110
  requirements:
108
111
  - - "~>"
109
112
  - !ruby/object:Gem::Version
110
- version: '1.4'
113
+ version: '1.3'
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 1.3.2
111
117
  - !ruby/object:Gem::Dependency
112
- name: bio-stockholm
118
+ name: rinruby
113
119
  requirement: !ruby/object:Gem::Requirement
114
120
  requirements:
115
121
  - - "~>"
116
122
  - !ruby/object:Gem::Version
117
- version: 0.0.1
123
+ version: '2.0'
118
124
  type: :runtime
119
125
  prerelease: false
120
126
  version_requirements: !ruby/object:Gem::Requirement
121
127
  requirements:
122
128
  - - "~>"
123
129
  - !ruby/object:Gem::Version
124
- version: 0.0.1
130
+ version: '2.0'
125
131
  - !ruby/object:Gem::Dependency
126
- name: entrez
132
+ name: rroc
127
133
  requirement: !ruby/object:Gem::Requirement
128
134
  requirements:
129
135
  - - "~>"
130
136
  - !ruby/object:Gem::Version
131
- version: '0.5'
137
+ version: '0.1'
132
138
  type: :runtime
133
139
  prerelease: false
134
140
  version_requirements: !ruby/object:Gem::Requirement
135
141
  requirements:
136
142
  - - "~>"
137
143
  - !ruby/object:Gem::Version
138
- version: '0.5'
144
+ version: '0.1'
145
+ - !ruby/object:Gem::Dependency
146
+ name: ruby-progressbar
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '1.5'
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 1.5.1
155
+ type: :runtime
156
+ prerelease: false
157
+ version_requirements: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
160
+ - !ruby/object:Gem::Version
161
+ version: '1.5'
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: 1.5.1
139
165
  - !ruby/object:Gem::Dependency
140
166
  name: rubytree
141
167
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +176,26 @@ dependencies:
150
176
  - - "~>"
151
177
  - !ruby/object:Gem::Version
152
178
  version: '0.9'
179
+ - !ruby/object:Gem::Dependency
180
+ name: shuffle
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - "~>"
184
+ - !ruby/object:Gem::Version
185
+ version: '1.0'
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: 1.0.1
189
+ type: :runtime
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - "~>"
194
+ - !ruby/object:Gem::Version
195
+ version: '1.0'
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: 1.0.1
153
199
  description: ''
154
200
  email:
155
201
  - evansenter@gmail.com
@@ -226,8 +272,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
272
  version: '0'
227
273
  requirements: []
228
274
  rubyforge_project:
229
- rubygems_version: 2.2.2
275
+ rubygems_version: 2.4.2
230
276
  signing_key:
231
277
  specification_version: 4
232
278
  summary: A comprehensive wrapper (wRNApper) for various RNA CLI programs.
233
279
  test_files: []
280
+ has_rdoc: