bio 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,17 +2,18 @@
2
2
  #
3
3
  # = BioRuby shell - command line interface for the BioRuby library
4
4
  #
5
- # Copyright:: Copyright (C) 2005, 2006
5
+ # Copyright:: Copyright (C) 2005, 2006, 2007
6
6
  # Toshiaki Katayama <k@bioruby.org>
7
7
  # License:: The Ruby License
8
8
  #
9
- # $Id: bioruby,v 1.19 2007/04/05 23:35:39 trevor Exp $
9
+ # $Id: bioruby,v 1.21 2007/07/26 10:46:46 k Exp $
10
10
  #
11
11
 
12
12
  begin
13
13
  require 'rubygems'
14
- require_gem 'bio', '>= 1.1.0'
14
+ gem 'bio', '>= 1.1.0'
15
15
  rescue LoadError
16
+ require 'bio'
16
17
  end
17
18
  require 'bio/shell'
18
19
 
data/lib/bio.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  #
2
2
  # = bio.rb - Loading all BioRuby modules
3
3
  #
4
- # Copyright:: Copyright (C) 2001-2006
4
+ # Copyright:: Copyright (C) 2001-2007
5
5
  # Toshiaki Katayama <k@bioruby.org>
6
6
  # License:: The Ruby License
7
7
  #
8
- # $Id: bio.rb,v 1.86 2007/07/16 12:26:28 ngoto Exp $
8
+ # $Id: bio.rb,v 1.87 2007/12/14 16:04:54 k Exp $
9
9
  #
10
10
 
11
11
  module Bio
12
12
 
13
- BIORUBY_VERSION = [1, 1, 0].extend(Comparable)
13
+ BIORUBY_VERSION = [1, 2, 0].extend(Comparable)
14
14
 
15
15
  ### Basic data types
16
16
 
@@ -4,7 +4,7 @@
4
4
  # Copyright:: Copyright (C) 2003-2006 GOTO Naohisa <ng@bioruby.org>
5
5
  # License:: The Ruby License
6
6
  #
7
- # $Id: format0.rb,v 1.22 2007/04/21 08:58:17 ngoto Exp $
7
+ # $Id: format0.rb,v 1.24 2007/12/14 16:12:17 k Exp $
8
8
  #
9
9
  # == Description
10
10
  #
@@ -860,9 +860,10 @@ module Bio
860
860
  # Returns definition of the hit.
861
861
  def definition; parse_hitname; @definition; end
862
862
 
863
+ def target_id; definition[/^\s*(\S+)/, 1]; end
864
+
863
865
  #--
864
866
  # Aliases to keep compatibility with Bio::Fasta::Report::Hit.
865
- #alias target_id accession
866
867
  alias target_def definition
867
868
  alias target_len len
868
869
  #++
@@ -1,10 +1,10 @@
1
1
  #
2
2
  # = bio/appl/blast/format8.rb - BLAST tab-delimited output (-m 8) parser
3
3
  #
4
- # Copyright:: Copyright (C) 2002, 2003 Toshiaki Katayama <k@bioruby.org>
4
+ # Copyright:: Copyright (C) 2002, 2003, 2007 Toshiaki Katayama <k@bioruby.org>
5
5
  # License:: The Ruby License
6
6
  #
7
- # $Id: format8.rb,v 1.7 2007/04/05 23:35:39 trevor Exp $
7
+ # $Id: format8.rb,v 1.8 2007/12/14 16:15:20 k Exp $
8
8
  #
9
9
  # == Note
10
10
  #
@@ -22,6 +22,7 @@ module Bio
22
22
  @iterations.push(iteration)
23
23
  @query_id = @query_def = data[/\S+/]
24
24
 
25
+ query_prev = ''
25
26
  target_prev = ''
26
27
  hit_num = 1
27
28
  hsp_num = 1
@@ -29,7 +30,7 @@ module Bio
29
30
  data.each do |line|
30
31
  ary = line.chomp.split("\t")
31
32
  query_id, target_id, hsp = tab_parse_hsp(ary)
32
- if target_prev != target_id
33
+ if query_prev != query_id or target_prev != target_id
33
34
  hit = Hit.new
34
35
  hit.num = hit_num
35
36
  hit_num += 1
@@ -41,6 +42,7 @@ module Bio
41
42
  hsp.num = hsp_num
42
43
  hsp_num += 1
43
44
  hit.hsps.push(hsp)
45
+ query_prev = query_id
44
46
  target_prev = target_id
45
47
  end
46
48
  end
@@ -4,7 +4,7 @@
4
4
  # Copyright:: Copyright (C) 2001, 2002, 2004, 2007 Toshiaki Katayama <k@bioruby.org>
5
5
  # License:: The Ruby License
6
6
  #
7
- # $Id: compound.rb,v 0.16 2007/06/28 11:27:24 k Exp $
7
+ # $Id: compound.rb,v 0.17 2007/11/27 07:09:43 k Exp $
8
8
  #
9
9
 
10
10
  require 'bio/db'
@@ -45,6 +45,11 @@ class COMPOUND < KEGGDB
45
45
  field_fetch('MASS').to_f
46
46
  end
47
47
 
48
+ # REMARK
49
+ def remark
50
+ field_fetch('REMARK')
51
+ end
52
+
48
53
  # GLYCAN
49
54
  def glycans
50
55
  unless @data['GLYCAN']
@@ -4,7 +4,7 @@
4
4
  # Copyright:: Copyright (C) 2001, 2002, 2007 Toshiaki Katayama <k@bioruby.org>
5
5
  # License:: The Ruby License
6
6
  #
7
- # $Id: enzyme.rb,v 0.11 2007/04/05 23:35:41 trevor Exp $
7
+ # $Id: enzyme.rb,v 0.12 2007/12/14 16:20:38 k Exp $
8
8
  #
9
9
 
10
10
  require 'bio/db'
@@ -106,9 +106,9 @@ class ENZYME < KEGGDB
106
106
  lines_fetch('PATHWAY')
107
107
  end
108
108
 
109
- # ORTHOLOG
109
+ # ORTHOLOGY
110
110
  def orthologs
111
- lines_fetch('ORTHOLOG')
111
+ lines_fetch('ORTHOLOGY')
112
112
  end
113
113
 
114
114
  # GENES
@@ -5,7 +5,7 @@
5
5
  # Toshiaki Katayama <k@bioruby.org>
6
6
  # License:: The Ruby License
7
7
  #
8
- # $Id: genes.rb,v 0.25 2007/04/05 23:35:41 trevor Exp $
8
+ # $Id: genes.rb,v 0.26 2007/12/14 16:20:38 k Exp $
9
9
  #
10
10
  #
11
11
  # == KEGG GENES parser
@@ -137,7 +137,7 @@ class GENES < KEGGDB
137
137
  end
138
138
 
139
139
  def orthologs
140
- lines_fetch('ORTHOLOG')
140
+ lines_fetch('ORTHOLOGY')
141
141
  end
142
142
 
143
143
  def pathway
@@ -4,7 +4,7 @@
4
4
  # Copyright:: Copyright (C) 2004 Toshiaki Katayama <k@bioruby.org>
5
5
  # License:: The Ruby License
6
6
  #
7
- # $Id: glycan.rb,v 1.6 2007/06/28 11:27:24 k Exp $
7
+ # $Id: glycan.rb,v 1.7 2007/12/14 16:20:38 k Exp $
8
8
  #
9
9
 
10
10
  require 'bio/db'
@@ -94,12 +94,12 @@ class GLYCAN < KEGGDB
94
94
  @data['ENZYME']
95
95
  end
96
96
 
97
- # ORTHOLOG
97
+ # ORTHOLOGY
98
98
  def orthologs
99
- unless @data['ORTHOLOG']
100
- @data['ORTHOLOG'] = lines_fetch('ORTHOLOG')
99
+ unless @data['ORTHOLOGY']
100
+ @data['ORTHOLOGY'] = lines_fetch('ORTHOLOGY')
101
101
  end
102
- @data['ORTHOLOG']
102
+ @data['ORTHOLOGY']
103
103
  end
104
104
 
105
105
  # COMMENT
@@ -5,7 +5,7 @@
5
5
  # Copyright:: Copyright (C) 2003 Masumi Itoh <m@bioruby.org>
6
6
  # License:: The Ruby License
7
7
  #
8
- # $Id: orthology.rb,v 1.9 2007/04/05 15:42:59 k Exp $
8
+ # $Id: orthology.rb,v 1.10 2007/12/14 16:19:54 k Exp $
9
9
  #
10
10
 
11
11
  require 'bio/db'
@@ -67,7 +67,7 @@ class ORTHOLOGY < KEGGDB
67
67
  keggclass.scan(/\[PATH:(.*?)\]/).flatten
68
68
  end
69
69
 
70
- # Returns a Hash of Array of a database name and entry IDs in DBLINKS field.
70
+ # Returns an Array of a database name and entry IDs in DBLINKS field.
71
71
  def dblinks
72
72
  unless @data['DBLINKS']
73
73
  @data['DBLINKS'] = lines_fetch('DBLINKS')
@@ -75,13 +75,37 @@ class ORTHOLOGY < KEGGDB
75
75
  @data['DBLINKS']
76
76
  end
77
77
 
78
- # Returns a Hash of Array of the organism ID and entry IDs in GENES field.
78
+ # Returns a Hash of the DB name and an Array of entry IDs in DBLINKS field.
79
+ def dblinks_as_hash
80
+ hash = {}
81
+ dblinks.each do |line|
82
+ name, *list = line.split(/\s+/)
83
+ db = name.downcase.sub(/:/, '')
84
+ hash[db] = list
85
+ end
86
+ return hash
87
+ end
88
+
89
+ # Returns an Array of the organism ID and entry IDs in GENES field.
79
90
  def genes
80
91
  unless @data['GENES']
81
92
  @data['GENES'] = lines_fetch('GENES')
82
93
  end
83
94
  @data['GENES']
84
95
  end
96
+
97
+ # Returns a Hash of the organism ID and an Array of entry IDs in GENES field.
98
+ def genes_as_hash
99
+ hash = {}
100
+ genes.each do |line|
101
+ name, *list = line.split(/\s+/)
102
+ org = name.downcase.sub(/:/, '')
103
+ genes = list.map {|x| x.sub(/\(.*\)/, '')}
104
+ #names = list.map {|x| x.scan(/.*\((.*)\)/)}
105
+ hash[org] = genes
106
+ end
107
+ return hash
108
+ end
85
109
 
86
110
  end # ORTHOLOGY
87
111
 
@@ -6,9 +6,19 @@
6
6
  # Daniel Amelang <dan@amelang.net>
7
7
  # License:: The Ruby License
8
8
  #
9
- # $Id: newick.rb,v 1.7 2007/04/05 23:35:40 trevor Exp $
9
+ # $Id: newick.rb,v 1.8 2007/12/12 16:06:22 ngoto Exp $
10
+ #
11
+ # == Description
12
+ #
13
+ # This file contains parser and formatter of Newick and NHX.
14
+ #
15
+ # == References
16
+ #
17
+ # * http://evolution.genetics.washington.edu/phylip/newick_doc.html
18
+ # * http://www.phylosoft.org/forester/NHX.html
10
19
  #
11
20
 
21
+ require 'strscan'
12
22
  require 'bio/tree'
13
23
 
14
24
  module Bio
@@ -18,6 +28,7 @@ module Bio
18
28
  # newick output
19
29
  #+++
20
30
 
31
+ # default options
21
32
  DEFAULT_OPTIONS =
22
33
  { :indent => ' ' }
23
34
 
@@ -32,10 +43,26 @@ module Bio
32
43
  end
33
44
  private :__get_option
34
45
 
46
+
47
+ # formats Newick label (unquoted_label or quoted_label)
48
+ def __to_newick_format_label(str, options)
49
+ if __get_option(:parser, options) == :naive then
50
+ return str.to_s
51
+ end
52
+ str = str.to_s
53
+ if /([\(\)\,\:\[\]\_\'\x00-\x1f\x7f])/ =~ str then
54
+ # quoted_label
55
+ return "\'" + str.gsub(/\'/, "\'\'") + "\'"
56
+ end
57
+ # unquoted_label
58
+ return str.gsub(/ /, '_')
59
+ end
60
+ private :__to_newick_format_label
61
+
35
62
  # formats leaf
36
63
  def __to_newick_format_leaf(node, edge, options)
37
64
 
38
- label = get_node_name(node).to_s
65
+ label = __to_newick_format_label(get_node_name(node), options)
39
66
 
40
67
  dist = get_edge_distance_string(edge)
41
68
 
@@ -62,7 +89,7 @@ module Bio
62
89
  # formats leaf for NHX
63
90
  def __to_newick_format_leaf_NHX(node, edge, options)
64
91
 
65
- label = get_node_name(node).to_s
92
+ label = __to_newick_format_label(get_node_name(node), options)
66
93
 
67
94
  dist = get_edge_distance_string(edge)
68
95
 
@@ -165,11 +192,14 @@ module Bio
165
192
  # Returns a newick formatted string.
166
193
  # If block is given, the order of the node is sorted
167
194
  # (as the same manner as Enumerable#sort).
168
- # Description about options.
169
- # :indent : indent string; set false to disable (default: ' ')
170
- # :bootstrap_style : :disabled disables bootstrap representations
171
- # :traditional traditional style
172
- # :molphy Molphy style (default)
195
+ #
196
+ # Available options:
197
+ # <tt>:indent</tt>::
198
+ # indent string; set false to disable (default: ' ')
199
+ # <tt>:bootstrap_style</tt>::
200
+ # <tt>:disabled</tt> disables bootstrap representations.
201
+ # <tt>:traditional</tt> for traditional style.
202
+ # <tt>:molphy</tt> for Molphy style (default).
173
203
  def output_newick(options = {}, &block) #:yields: node1, node2
174
204
  root = @root
175
205
  root ||= self.nodes.first
@@ -185,8 +215,11 @@ module Bio
185
215
  # Returns a NHX (New Hampshire eXtended) formatted string.
186
216
  # If block is given, the order of the node is sorted
187
217
  # (as the same manner as Enumerable#sort).
188
- # Description about options.
189
- # :indent : indent string; set false to disable (default: ' ')
218
+ #
219
+ # Available options:
220
+ # <tt>:indent</tt>::
221
+ # indent string; set false to disable (default: ' ')
222
+ #
190
223
  def output_nhx(options = {}, &block) #:yields: node1, node2
191
224
  root = @root
192
225
  root ||= self.nodes.first
@@ -257,13 +290,28 @@ module Bio
257
290
  # Creates a new Newick object.
258
291
  # _options_ for parsing can be set.
259
292
  #
260
- # Note: molphy-style bootstrap values may be parsed, even if
261
- # the options[:bootstrap_style] is set to :traditional or :disabled.
262
- # Note: By default, if all of the internal node's names are numeric
293
+ # Available options:
294
+ # <tt>:bootstrap_style</tt>::
295
+ # <tt>:traditional</tt> for traditional bootstrap style,
296
+ # <tt>:molphy</tt> for molphy style,
297
+ # <tt>:disabled</tt> to ignore bootstrap strings.
298
+ # For details of default actions, please read the notes below.
299
+ # <tt>:parser</tt>::
300
+ # <tt>:naive</tt> for using naive parser, compatible with
301
+ # BioRuby 1.1.0, which ignores quoted strings and
302
+ # do not convert underscores to spaces.
303
+ #
304
+ # Notes for bootstrap style:
305
+ # Molphy-style bootstrap values may always be parsed, even if
306
+ # the <tt>options[:bootstrap_style]</tt> is set to
307
+ # <tt>:traditional</tt> or <tt>:disabled</tt>.
308
+ #
309
+ # Note for default or traditional bootstrap style:
310
+ # By default, if all of the internal node's names are numeric
263
311
  # and there are no NHX and no molphy-style boostrap values,
264
312
  # the names of internal nodes are regarded as bootstrap values.
265
- # options[:bootstrap_style] = :disabled or :molphy to disable the feature
266
- # (or at least one NHX tag exists).
313
+ # <tt>options[:bootstrap_style] = :disabled</tt> or <tt>:molphy</tt>
314
+ # to disable the feature (or at least one NHX tag exists).
267
315
  def initialize(str, options = nil)
268
316
  str = str.sub(/\;(.*)/m, ';')
269
317
  @original_string = str
@@ -308,57 +356,66 @@ module Bio
308
356
  end
309
357
 
310
358
  # Parses newick formatted leaf (or internal node) name.
311
- def __parse_newick_leaf(str, node, edge, options)
312
- case str
313
- when /(.*)\:(.*)\[(.*)\]/
314
- node.name = $1
315
- edge.distance_string = $2 if $2 and !($2.strip.empty?)
316
- # bracketted string into bstr
317
- bstr = $3
318
- when /(.*)\[(.*)\]/
319
- node.name = $1
320
- # bracketted string into bstr
321
- bstr = $2
322
- when /(.*)\:(.*)/
323
- node.name = $1
324
- edge.distance_string = $2 if $2 and !($2.strip.empty?)
325
- else
326
- node.name = str
359
+ def __parse_newick_leaf(leaf_tokens, node, edge, options)
360
+ t = leaf_tokens.shift
361
+ if !t.kind_of?(Symbol) then
362
+ node.name = t
363
+ t = leaf_tokens.shift
364
+ end
365
+
366
+ if t == :':' then
367
+ t = leaf_tokens.shift
368
+ if !t.kind_of?(Symbol) then
369
+ edge.distance_string = t if t and !(t.strip.empty?)
370
+ t = leaf_tokens.shift
371
+ end
327
372
  end
328
373
 
329
- # determines NHX or Molphy-style bootstrap
330
- if bstr and !(bstr.strip.empty?)
374
+ if t == :'[' then
375
+ btokens = leaf_tokens
331
376
  case __get_option(:original_format, options)
332
377
  when :nhx
333
378
  # regarded as NHX string which might be broken
334
- __parse_nhx(bstr, node, edge)
379
+ __parse_nhx(btokens, node, edge)
335
380
  when :traditional
336
381
  # simply ignored
337
382
  else
338
- case bstr
383
+ case btokens[0].to_s.strip
384
+ when ''
385
+ # not automatically determined
339
386
  when /\A\&\&NHX/
340
387
  # NHX string
341
388
  # force to set NHX mode
342
389
  @options[:original_format] = :nhx
343
- __parse_nhx(bstr, node, edge)
390
+ __parse_nhx(btokens, node, edge)
344
391
  else
345
392
  # Molphy-style boostrap values
346
393
  # let molphy mode if nothing determined
347
394
  @options[:original_format] ||= :molphy
395
+ bstr = ''
396
+ while t = btokens.shift and t != :']'
397
+ bstr.concat t.to_s
398
+ end
348
399
  node.bootstrap_string = bstr
349
- end #case bstr
400
+ end #case btokens[0]
350
401
  end
351
402
  end
352
403
 
404
+ if !btokens and !leaf_tokens.empty? then
405
+ # syntax error?
406
+ end
407
+ node.name ||= '' # compatibility for older BioRuby
408
+
353
409
  # returns true
354
410
  true
355
411
  end
356
412
 
357
413
  # Parses NHX (New Hampshire eXtended) string
358
- def __parse_nhx(bstr, node, edge)
359
- a = bstr.split(/\:/)
360
- a.shift if a[0] == '&&NHX'
361
- a.each do |str|
414
+ def __parse_nhx(btokens, node, edge)
415
+ btokens.shift if btokens[0] == '&&NHX'
416
+ btokens.each do |str|
417
+ break if str == :']'
418
+ next if str.kind_of?(Symbol)
362
419
  tag, val = str.split(/\=/, 2)
363
420
  case tag
364
421
  when 'B'
@@ -391,6 +448,97 @@ module Bio
391
448
  true
392
449
  end
393
450
 
451
+ # splits string to tokens
452
+ def __parse_newick_tokenize(str, options)
453
+ str = str.chop if str[-1..-1] == ';'
454
+ # http://evolution.genetics.washington.edu/phylip/newick_doc.html
455
+ # quoted_label ==> ' string_of_printing_characters '
456
+ # single quote in quoted_label is '' (two single quotes)
457
+ #
458
+
459
+ if __get_option(:parser, options) == :naive then
460
+ ary = str.split(/([\(\)\,\:\[\]])/)
461
+ ary.collect! { |x| x.strip!; x.empty? ? nil : x }
462
+ ary.compact!
463
+ ary.collect! do |x|
464
+ if /\A([\(\)\,\:\[\]])\z/ =~ x then
465
+ x.intern
466
+ else
467
+ x
468
+ end
469
+ end
470
+ return ary
471
+ end
472
+
473
+ tokens = []
474
+ ss = StringScanner.new(str)
475
+
476
+ while !(ss.eos?)
477
+ if ss.scan(/\s+/) then
478
+ # do nothing
479
+
480
+ elsif ss.scan(/[\(\)\,\:\[\]]/) then
481
+ # '(' or ')' or ',' or ':' or '[' or ']'
482
+ t = ss.matched
483
+ tokens.push t.intern
484
+
485
+ elsif ss.scan(/\'/) then
486
+ # quoted_label
487
+ t = ''
488
+ while true
489
+ if ss.scan(/([^\']*)\'/) then
490
+ t.concat ss[1]
491
+ if ss.scan(/\'/) then
492
+ # single quote in quoted_label
493
+ t.concat ss.matched
494
+ else
495
+ break
496
+ end
497
+ else
498
+ # incomplete quoted_label?
499
+ break
500
+ end
501
+ end #while true
502
+ unless ss.match?(/\s*[\(\)\,\:\[\]]/) or ss.match?(/\s*\z/) then
503
+ # label continues? (illegal, but try to rescue)
504
+ if ss.scan(/[^\(\)\,\:\[\]]+/) then
505
+ t.concat ss.matched.lstrip
506
+ end
507
+ end
508
+ tokens.push t
509
+
510
+ elsif ss.scan(/[^\(\)\,\:\[\]]+/) then
511
+ # unquoted_label
512
+ t = ss.matched.strip
513
+ t.gsub!(/[\r\n]/, '')
514
+ # unquoted underscore should be converted to blank
515
+ t.gsub!(/\_/, ' ')
516
+ tokens.push t unless t.empty?
517
+
518
+ else
519
+ # unquoted_label in end of string
520
+ t = ss.rest.strip
521
+ t.gsub!(/[\r\n]/, '')
522
+ # unquoted underscore should be converted to blank
523
+ t.gsub!(/\_/, ' ')
524
+ tokens.push t unless t.empty?
525
+ ss.terminate
526
+
527
+ end
528
+ end #while !(ss.eos?)
529
+
530
+ tokens
531
+ end
532
+
533
+ # get tokens for a leaf
534
+ def __parse_newick_get_tokens_for_leaf(ary)
535
+ r = []
536
+ while t = ary[0] and t != :',' and t != :')' and t != :'('
537
+ r.push ary.shift
538
+ end
539
+ r
540
+ end
541
+
394
542
  # Parses newick formatted string.
395
543
  def __parse_newick(str, options = {})
396
544
  # initializing
@@ -401,40 +549,37 @@ module Bio
401
549
  internal_nodes = []
402
550
  node_stack = []
403
551
  # preparation of tokens
404
- str = str.chop if str[-1..-1] == ';'
405
- ary = str.split(/([\(\)\,])/)
406
- ary.collect! { |x| x.strip!; x.empty? ? nil : x }
407
- ary.compact!
552
+ ary = __parse_newick_tokenize(str, options)
408
553
  previous_token = nil
409
554
  # main loop
410
555
  while token = ary.shift
411
556
  #p token
412
557
  case token
413
- when ','
414
- if previous_token == ',' or previous_token == '(' then
558
+ when :','
559
+ if previous_token == :',' or previous_token == :'(' then
415
560
  # there is a leaf whose name is empty.
416
561
  ary.unshift(token)
417
562
  ary.unshift('')
418
563
  token = nil
419
564
  end
420
- when '('
565
+ when :'('
421
566
  node = Node.new
422
567
  nodes << node
423
568
  internal_nodes << node
424
569
  node_stack.push(cur_node)
425
570
  cur_node = node
426
- when ')'
427
- if previous_token == ',' or previous_token == '(' then
571
+ when :')'
572
+ if previous_token == :',' or previous_token == :'(' then
428
573
  # there is a leaf whose name is empty.
429
574
  ary.unshift(token)
430
575
  ary.unshift('')
431
576
  token = nil
432
577
  else
433
578
  edge = Edge.new
434
- next_token = ary[0]
435
- if next_token and next_token != ',' and next_token != ')' then
436
- __parse_newick_leaf(next_token, cur_node, edge, options)
437
- ary.shift
579
+ leaf_tokens = __parse_newick_get_tokens_for_leaf(ary)
580
+ token = nil
581
+ if leaf_tokens.size > 0 then
582
+ __parse_newick_leaf(leaf_tokens, cur_node, edge, options)
438
583
  end
439
584
  parent = node_stack.pop
440
585
  raise ParseError, 'unmatched parentheses' unless parent
@@ -444,7 +589,10 @@ module Bio
444
589
  else
445
590
  leaf = Node.new
446
591
  edge = Edge.new
447
- __parse_newick_leaf(token, leaf, edge, options)
592
+ ary.unshift(token)
593
+ leaf_tokens = __parse_newick_get_tokens_for_leaf(ary)
594
+ token = nil
595
+ __parse_newick_leaf(leaf_tokens, leaf, edge, options)
448
596
  nodes << leaf
449
597
  edges << Bio::Relation.new(cur_node, leaf, edge)
450
598
  end #case