bio-nexml 0.0.1
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.
- data/Gemfile +15 -0
- data/Gemfile.lock +24 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +47 -0
- data/Rakefile +55 -0
- data/TODO.txt +6 -0
- data/VERSION +1 -0
- data/bio-nexml.gemspec +126 -0
- data/extconf.rb +2 -0
- data/lib/bio-nexml.rb +0 -0
- data/lib/bio.rb +321 -0
- data/lib/bio/db/nexml.rb +109 -0
- data/lib/bio/db/nexml/mapper.rb +113 -0
- data/lib/bio/db/nexml/mapper/framework.rb +157 -0
- data/lib/bio/db/nexml/mapper/inflection.rb +99 -0
- data/lib/bio/db/nexml/mapper/repository.rb +59 -0
- data/lib/bio/db/nexml/matrix.rb +1046 -0
- data/lib/bio/db/nexml/parser.rb +622 -0
- data/lib/bio/db/nexml/schema/README.txt +21 -0
- data/lib/bio/db/nexml/schema/abstract.xsd +159 -0
- data/lib/bio/db/nexml/schema/characters/README.txt +1 -0
- data/lib/bio/db/nexml/schema/characters/abstractcharacters.xsd +361 -0
- data/lib/bio/db/nexml/schema/characters/characters.xsd +22 -0
- data/lib/bio/db/nexml/schema/characters/continuous.xsd +190 -0
- data/lib/bio/db/nexml/schema/characters/dna.xsd +282 -0
- data/lib/bio/db/nexml/schema/characters/protein.xsd +280 -0
- data/lib/bio/db/nexml/schema/characters/restriction.xsd +239 -0
- data/lib/bio/db/nexml/schema/characters/rna.xsd +283 -0
- data/lib/bio/db/nexml/schema/characters/standard.xsd +261 -0
- data/lib/bio/db/nexml/schema/external/sawsdl.xsd +21 -0
- data/lib/bio/db/nexml/schema/external/xhtml-datatypes-1.xsd +177 -0
- data/lib/bio/db/nexml/schema/external/xlink.xsd +75 -0
- data/lib/bio/db/nexml/schema/external/xml.xsd +145 -0
- data/lib/bio/db/nexml/schema/meta/README.txt +2 -0
- data/lib/bio/db/nexml/schema/meta/annotations.xsd +100 -0
- data/lib/bio/db/nexml/schema/meta/meta.xsd +294 -0
- data/lib/bio/db/nexml/schema/nexml.xsd +104 -0
- data/lib/bio/db/nexml/schema/taxa/README.txt +2 -0
- data/lib/bio/db/nexml/schema/taxa/taxa.xsd +39 -0
- data/lib/bio/db/nexml/schema/trees/README.txt +2 -0
- data/lib/bio/db/nexml/schema/trees/abstracttrees.xsd +135 -0
- data/lib/bio/db/nexml/schema/trees/network.xsd +113 -0
- data/lib/bio/db/nexml/schema/trees/tree.xsd +149 -0
- data/lib/bio/db/nexml/schema/trees/trees.xsd +36 -0
- data/lib/bio/db/nexml/taxa.rb +147 -0
- data/lib/bio/db/nexml/trees.rb +663 -0
- data/lib/bio/db/nexml/writer.rb +265 -0
- data/test/data/nexml/test.xml +69 -0
- data/test/test_bio-nexml.rb +17 -0
- data/test/unit/bio/db/nexml/tc_factory.rb +119 -0
- data/test/unit/bio/db/nexml/tc_mapper.rb +78 -0
- data/test/unit/bio/db/nexml/tc_matrix.rb +551 -0
- data/test/unit/bio/db/nexml/tc_parser.rb +21 -0
- data/test/unit/bio/db/nexml/tc_taxa.rb +118 -0
- data/test/unit/bio/db/nexml/tc_trees.rb +370 -0
- data/test/unit/bio/db/nexml/tc_writer.rb +633 -0
- metadata +253 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<xs:schema
|
3
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
4
|
+
targetNamespace="http://www.nexml.org/2009"
|
5
|
+
xmlns="http://www.nexml.org/2009"
|
6
|
+
elementFormDefault="qualified">
|
7
|
+
<xs:annotation>
|
8
|
+
<xs:documentation>
|
9
|
+
This module defines the components of networks, graphs
|
10
|
+
where edges have an in-degree that may exceed 1. The
|
11
|
+
types defined in this module are concrete implementations
|
12
|
+
that inherit from the abstract types in the <a href="../abstract">
|
13
|
+
abstract trees module
|
14
|
+
</a>. <br /><br />
|
15
|
+
Depending on the concrete subclass, edges in networks either
|
16
|
+
have lengths formatted as integers or lengths formatted as
|
17
|
+
floating point numbers.
|
18
|
+
</xs:documentation>
|
19
|
+
</xs:annotation>
|
20
|
+
|
21
|
+
<xs:include schemaLocation="abstracttrees.xsd"/>
|
22
|
+
|
23
|
+
<xs:complexType name="NetworkNode" abstract="false">
|
24
|
+
<xs:annotation>
|
25
|
+
<xs:documentation>
|
26
|
+
A concrete network node implementation.
|
27
|
+
</xs:documentation>
|
28
|
+
</xs:annotation>
|
29
|
+
<xs:complexContent>
|
30
|
+
<xs:restriction base="AbstractNode">
|
31
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
32
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
33
|
+
</xs:sequence>
|
34
|
+
</xs:restriction>
|
35
|
+
</xs:complexContent>
|
36
|
+
</xs:complexType>
|
37
|
+
<!--
|
38
|
+
<xs:complexType name="NetworkEdge" abstract="false">
|
39
|
+
<xs:annotation>
|
40
|
+
<xs:documentation>
|
41
|
+
A concrete network edge implementation, no length specified.
|
42
|
+
</xs:documentation>
|
43
|
+
</xs:annotation>
|
44
|
+
<xs:complexContent>
|
45
|
+
<xs:extension base="AbstractEdge"/>
|
46
|
+
</xs:complexContent>
|
47
|
+
</xs:complexType>
|
48
|
+
-->
|
49
|
+
<xs:complexType name="NetworkFloatEdge" abstract="false">
|
50
|
+
<xs:annotation>
|
51
|
+
<xs:documentation>
|
52
|
+
A concrete network edge implementation, with float edge.
|
53
|
+
</xs:documentation>
|
54
|
+
</xs:annotation>
|
55
|
+
<xs:complexContent>
|
56
|
+
<xs:restriction base="AbstractEdge">
|
57
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
58
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
59
|
+
</xs:sequence>
|
60
|
+
<xs:attribute name="length" type="xs:float"/>
|
61
|
+
</xs:restriction>
|
62
|
+
</xs:complexContent>
|
63
|
+
</xs:complexType>
|
64
|
+
|
65
|
+
<xs:complexType name="NetworkIntEdge" abstract="false">
|
66
|
+
<xs:annotation>
|
67
|
+
<xs:documentation>
|
68
|
+
A concrete network edge implementation, with int edge.
|
69
|
+
</xs:documentation>
|
70
|
+
</xs:annotation>
|
71
|
+
<xs:complexContent>
|
72
|
+
<xs:restriction base="AbstractEdge">
|
73
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
74
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
75
|
+
</xs:sequence>
|
76
|
+
<xs:attribute name="length" type="xs:integer"/>
|
77
|
+
</xs:restriction>
|
78
|
+
</xs:complexContent>
|
79
|
+
</xs:complexType>
|
80
|
+
|
81
|
+
<xs:complexType name="FloatNetwork" abstract="false">
|
82
|
+
<xs:annotation>
|
83
|
+
<xs:documentation>
|
84
|
+
A concrete network implementation, with floating point edge lengths.
|
85
|
+
</xs:documentation>
|
86
|
+
</xs:annotation>
|
87
|
+
<xs:complexContent>
|
88
|
+
<xs:restriction base="AbstractNetwork">
|
89
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
90
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="node" type="NetworkNode"/>
|
91
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="edge" type="NetworkFloatEdge"/>
|
92
|
+
</xs:sequence>
|
93
|
+
</xs:restriction>
|
94
|
+
</xs:complexContent>
|
95
|
+
</xs:complexType>
|
96
|
+
|
97
|
+
<xs:complexType name="IntNetwork" abstract="false">
|
98
|
+
<xs:annotation>
|
99
|
+
<xs:documentation>
|
100
|
+
A concrete network implementation, with integer edge lengths.
|
101
|
+
</xs:documentation>
|
102
|
+
</xs:annotation>
|
103
|
+
<xs:complexContent>
|
104
|
+
<xs:restriction base="AbstractNetwork">
|
105
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
106
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="node" type="NetworkNode"/>
|
107
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="edge" type="NetworkIntEdge"/>
|
108
|
+
</xs:sequence>
|
109
|
+
</xs:restriction>
|
110
|
+
</xs:complexContent>
|
111
|
+
</xs:complexType>
|
112
|
+
|
113
|
+
</xs:schema>
|
@@ -0,0 +1,149 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<xs:schema
|
3
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
4
|
+
targetNamespace="http://www.nexml.org/2009"
|
5
|
+
xmlns="http://www.nexml.org/2009"
|
6
|
+
elementFormDefault="qualified">
|
7
|
+
<xs:annotation>
|
8
|
+
<xs:documentation>
|
9
|
+
This module defines the components of trees, graphs
|
10
|
+
where edges have an in-degree that of 1. The
|
11
|
+
types defined in this module are concrete implementations
|
12
|
+
that inherit from the abstract types in the <a href="../abstract">
|
13
|
+
abstract trees module</a>.<br /><br />
|
14
|
+
Depending on the concrete subclass, edges in trees either
|
15
|
+
have lengths formatted as integers or lengths formatted as
|
16
|
+
floating point numbers.
|
17
|
+
</xs:documentation>
|
18
|
+
</xs:annotation>
|
19
|
+
|
20
|
+
<xs:include schemaLocation="abstracttrees.xsd"/>
|
21
|
+
|
22
|
+
<xs:complexType name="TreeNode" abstract="false">
|
23
|
+
<xs:annotation>
|
24
|
+
<xs:documentation>
|
25
|
+
A concrete node implementation.
|
26
|
+
</xs:documentation>
|
27
|
+
</xs:annotation>
|
28
|
+
<xs:complexContent>
|
29
|
+
<xs:restriction base="AbstractNode">
|
30
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
31
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
32
|
+
</xs:sequence>
|
33
|
+
</xs:restriction>
|
34
|
+
</xs:complexContent>
|
35
|
+
</xs:complexType>
|
36
|
+
|
37
|
+
<!--
|
38
|
+
<xs:complexType name="TreeEdge" abstract="false">
|
39
|
+
<xs:annotation>
|
40
|
+
<xs:documentation>
|
41
|
+
A concrete edge implementation, no length type specified.
|
42
|
+
</xs:documentation>
|
43
|
+
</xs:annotation>
|
44
|
+
<xs:complexContent>
|
45
|
+
<xs:extension base="AbstractEdge"/>
|
46
|
+
</xs:complexContent>
|
47
|
+
</xs:complexType>
|
48
|
+
-->
|
49
|
+
<xs:complexType name="TreeFloatEdge" abstract="false">
|
50
|
+
<xs:annotation>
|
51
|
+
<xs:documentation>
|
52
|
+
A concrete edge implementation, with float length.
|
53
|
+
</xs:documentation>
|
54
|
+
</xs:annotation>
|
55
|
+
<xs:complexContent>
|
56
|
+
<xs:restriction base="AbstractEdge">
|
57
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
58
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
59
|
+
</xs:sequence>
|
60
|
+
<xs:attribute name="length" type="xs:float"/>
|
61
|
+
</xs:restriction>
|
62
|
+
</xs:complexContent>
|
63
|
+
</xs:complexType>
|
64
|
+
|
65
|
+
<xs:complexType name="TreeFloatRootEdge" abstract="false">
|
66
|
+
<xs:annotation>
|
67
|
+
<xs:documentation>
|
68
|
+
A concrete root edge implementation, with float length.
|
69
|
+
</xs:documentation>
|
70
|
+
</xs:annotation>
|
71
|
+
<xs:complexContent>
|
72
|
+
<xs:restriction base="AbstractRootEdge">
|
73
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
74
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
75
|
+
</xs:sequence>
|
76
|
+
<xs:attribute name="length" type="xs:float"/>
|
77
|
+
</xs:restriction>
|
78
|
+
</xs:complexContent>
|
79
|
+
</xs:complexType>
|
80
|
+
|
81
|
+
<xs:complexType name="TreeIntEdge" abstract="false">
|
82
|
+
<xs:annotation>
|
83
|
+
<xs:documentation>
|
84
|
+
A concrete edge implementation, with int length.
|
85
|
+
</xs:documentation>
|
86
|
+
</xs:annotation>
|
87
|
+
<xs:complexContent>
|
88
|
+
<xs:restriction base="AbstractEdge">
|
89
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
90
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
91
|
+
</xs:sequence>
|
92
|
+
<xs:attribute name="length" type="xs:integer"/>
|
93
|
+
</xs:restriction>
|
94
|
+
</xs:complexContent>
|
95
|
+
</xs:complexType>
|
96
|
+
|
97
|
+
<xs:complexType name="TreeIntRootEdge" abstract="false">
|
98
|
+
<xs:annotation>
|
99
|
+
<xs:documentation>
|
100
|
+
A concrete root edge implementation, with int length.
|
101
|
+
</xs:documentation>
|
102
|
+
</xs:annotation>
|
103
|
+
<xs:complexContent>
|
104
|
+
<xs:restriction base="AbstractRootEdge">
|
105
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
106
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
107
|
+
</xs:sequence>
|
108
|
+
<xs:attribute name="length" type="xs:integer"/>
|
109
|
+
</xs:restriction>
|
110
|
+
</xs:complexContent>
|
111
|
+
</xs:complexType>
|
112
|
+
|
113
|
+
<xs:complexType name="FloatTree" abstract="false">
|
114
|
+
<xs:annotation>
|
115
|
+
<xs:documentation>
|
116
|
+
A concrete tree implementation, with floating point edge lengths.
|
117
|
+
</xs:documentation>
|
118
|
+
</xs:annotation>
|
119
|
+
<xs:complexContent>
|
120
|
+
<xs:restriction base="AbstractTree">
|
121
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
122
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
123
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="node" type="TreeNode"/>
|
124
|
+
<xs:element minOccurs="0" maxOccurs="1" name="rootedge" type="TreeFloatRootEdge"/>
|
125
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="edge" type="TreeFloatEdge"/>
|
126
|
+
</xs:sequence>
|
127
|
+
</xs:restriction>
|
128
|
+
</xs:complexContent>
|
129
|
+
</xs:complexType>
|
130
|
+
|
131
|
+
<xs:complexType name="IntTree" abstract="false">
|
132
|
+
<xs:annotation>
|
133
|
+
<xs:documentation>
|
134
|
+
A concrete tree implementation, with integer edge lengths.
|
135
|
+
</xs:documentation>
|
136
|
+
</xs:annotation>
|
137
|
+
<xs:complexContent>
|
138
|
+
<xs:restriction base="AbstractTree">
|
139
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
140
|
+
<xs:element name="meta" type="Meta" minOccurs="0" maxOccurs="unbounded"/>
|
141
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="node" type="TreeNode"/>
|
142
|
+
<xs:element minOccurs="0" maxOccurs="1" name="rootedge" type="TreeIntRootEdge"/>
|
143
|
+
<xs:element minOccurs="1" maxOccurs="unbounded" name="edge" type="TreeIntEdge"/>
|
144
|
+
</xs:sequence>
|
145
|
+
</xs:restriction>
|
146
|
+
</xs:complexContent>
|
147
|
+
</xs:complexType>
|
148
|
+
|
149
|
+
</xs:schema>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.nexml.org/2009"
|
3
|
+
xmlns="http://www.nexml.org/2009" elementFormDefault="qualified">
|
4
|
+
<xs:annotation>
|
5
|
+
<xs:documentation>
|
6
|
+
This module defines the complex type for a set of trees,
|
7
|
+
analogous to the "trees" block in NEXUS files. The module
|
8
|
+
includes the modules that define concrete instances of
|
9
|
+
<a href="../tree">tree</a> objects and of <a href="../network">network</a>
|
10
|
+
objects.
|
11
|
+
</xs:documentation>
|
12
|
+
</xs:annotation>
|
13
|
+
|
14
|
+
<xs:include schemaLocation="tree.xsd"/>
|
15
|
+
<xs:include schemaLocation="network.xsd"/>
|
16
|
+
|
17
|
+
<xs:complexType name="Trees" abstract="false" mixed="true">
|
18
|
+
<xs:annotation>
|
19
|
+
<xs:documentation>
|
20
|
+
A concrete container for tree objects.
|
21
|
+
</xs:documentation>
|
22
|
+
</xs:annotation>
|
23
|
+
<xs:complexContent mixed="true">
|
24
|
+
<xs:extension base="TaxaLinked">
|
25
|
+
<xs:sequence minOccurs="1" maxOccurs="1">
|
26
|
+
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
27
|
+
<xs:element name="network" type="AbstractNetwork" minOccurs="1"
|
28
|
+
maxOccurs="unbounded"/>
|
29
|
+
<xs:element name="tree" type="AbstractTree" minOccurs="1"
|
30
|
+
maxOccurs="unbounded"/>
|
31
|
+
</xs:choice>
|
32
|
+
</xs:sequence>
|
33
|
+
</xs:extension>
|
34
|
+
</xs:complexContent>
|
35
|
+
</xs:complexType>
|
36
|
+
</xs:schema>
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Bio
|
2
|
+
module NeXML
|
3
|
+
# = DESCRIPTION
|
4
|
+
# Otu represents a taxon; an implementation of the
|
5
|
+
# <em>Taxon</em>[http://nexml.org/nexml/html/doc/schema-1/taxa/taxa/#Taxon] type.
|
6
|
+
# An Otu must have an 'id' and may take an an optional 'label'.
|
7
|
+
# taxon1 = Bio::NeXML::Otu.new( 'taxon1', :label => 'Label for taxon1' )
|
8
|
+
# taxon1.id #=> 'taxon1'
|
9
|
+
# taxon1.label #=> 'Label for taxon1'
|
10
|
+
# taxon1.otus #=> otus object they belong to; see docs for Otus
|
11
|
+
class Otu
|
12
|
+
include Mapper
|
13
|
+
@@writer = Bio::NeXML::Writer.new
|
14
|
+
|
15
|
+
# A file level unique identifier.
|
16
|
+
attr_accessor :id
|
17
|
+
|
18
|
+
# A human readable description.
|
19
|
+
attr_accessor :label
|
20
|
+
|
21
|
+
# An otu is contained in otus.
|
22
|
+
belongs_to :otus
|
23
|
+
|
24
|
+
# An otu is referred to by several tree nodes.
|
25
|
+
has_n :nodes
|
26
|
+
|
27
|
+
has_n :rows
|
28
|
+
|
29
|
+
# Create a new otu.
|
30
|
+
# otu = Bio::NeXML::Otu.id( 'o1' )
|
31
|
+
# otu = Bio::NeXML::Otu.id( 'o1', :label => 'A label' )
|
32
|
+
def initialize( id, options = {}, &block )
|
33
|
+
@id = id
|
34
|
+
properties( options ) unless options.empty?
|
35
|
+
block.arity < 1 ? instance_eval( &block ) : block.call( self ) if block_given?
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_xml
|
39
|
+
@@writer.create_node( "otu", @@writer.attributes( self, :id, :label ) )
|
40
|
+
end
|
41
|
+
|
42
|
+
end #end class Otu
|
43
|
+
|
44
|
+
# = DESCRIPTION
|
45
|
+
# Otus is a container for Otu objects; an implementation of the
|
46
|
+
# <em>Taxa</em>[http://nexml.org/nexml/html/doc/schema-1/taxa/taxa/#Taxa] type.
|
47
|
+
# An Otus must have an 'id' and may take an optional 'label'. Adding two or more Otu objects
|
48
|
+
# with the same 'id' to an Otus is not allowed. Doing so will overwrite the previous Otu object
|
49
|
+
# with the same the same 'id'.
|
50
|
+
# taxa1 = Bio::NeXML::Otus.new( 'taxa1', :label => 'Label for taxa1' )
|
51
|
+
# taxa1.id #=> 'taxa1'
|
52
|
+
# taxa1.label #=> 'Label for taxa1'
|
53
|
+
#
|
54
|
+
# taxon1 = Bio::NeXML::Otu.new( 'taxon1' )
|
55
|
+
# taxon2 = Bio::NeXML::Otu.new( 'taxon2' )
|
56
|
+
#
|
57
|
+
# taxa1 << taxon1 << taxon2
|
58
|
+
# taxa1.count #=> 2
|
59
|
+
# taxa1.each { |otu| puts otu.id }
|
60
|
+
# taxon2.otus #=> taxa1
|
61
|
+
# taxa1.include?( taxon1 ) #=> true
|
62
|
+
# taxa1.delete( taxon2 ) #=> taxon2
|
63
|
+
class Otus
|
64
|
+
include Enumerable
|
65
|
+
include Mapper
|
66
|
+
@@writer = Bio::NeXML::Writer.new
|
67
|
+
|
68
|
+
# A file level unique identifier.
|
69
|
+
attr_accessor :id
|
70
|
+
|
71
|
+
# A human readable description.
|
72
|
+
attr_accessor :label
|
73
|
+
|
74
|
+
belongs_to :nexml
|
75
|
+
|
76
|
+
has_n :otus
|
77
|
+
has_n :trees, :singularize => false
|
78
|
+
has_n :characters, :singularize => false
|
79
|
+
|
80
|
+
def initialize( id, options = {}, &block )
|
81
|
+
@id = id
|
82
|
+
properties( options ) unless options.empty?
|
83
|
+
block.arity < 1 ? instance_eval( &block ) : block.call( self ) if block_given?
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns an array of otu contained in <tt>self</tt>.
|
87
|
+
def otus; end if false # dummy for rdoc
|
88
|
+
# Taken an array of otu and adds it to <tt>self</tt>.
|
89
|
+
def otus=; end if false # dummy for rdoc
|
90
|
+
|
91
|
+
# Takes an otu object and appends it to <tt>self</tt>.
|
92
|
+
def <<( otu )
|
93
|
+
add_otu( otu )
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# Creates and returns an otu after appending it to self
|
98
|
+
def create_otu( options = {} )
|
99
|
+
otu = Otu.new( Bio::NeXML.generate_id( Otu ), options )
|
100
|
+
self << otu
|
101
|
+
otu
|
102
|
+
end
|
103
|
+
|
104
|
+
# Takes an otu or its id and deletes it. Returns the object deleted or <tt>nil</tt>.
|
105
|
+
def delete( otu )
|
106
|
+
delete_otu( otu )
|
107
|
+
end
|
108
|
+
|
109
|
+
# Takes an otu or its id and returns <tt>true</tt> if it is contained in <tt>self</tt>.
|
110
|
+
def include?( object )
|
111
|
+
has_otu?( object )
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns the otu object with the given id; <tt>nil</tt> if an otu with the given id is not
|
115
|
+
# contained in <tt>self</tt>.
|
116
|
+
def []( id )
|
117
|
+
get_otu_by_id( id )
|
118
|
+
end
|
119
|
+
|
120
|
+
# Iterate over each otu in <tt>self</tt> passing it to the block given. If no block is provided,
|
121
|
+
# it returns an Enumerator.
|
122
|
+
def each( &block )
|
123
|
+
@otus.each( &block )
|
124
|
+
end
|
125
|
+
|
126
|
+
# Iterate over each otu in <tt>self</tt> passing the otu and its id to the block given. If no
|
127
|
+
# block is provided, it returns an Enumerator.
|
128
|
+
def each_with_id( &block )
|
129
|
+
@otus.each_with_id( &block )
|
130
|
+
end
|
131
|
+
|
132
|
+
# Return the number of otu in <tt>self</tt>.
|
133
|
+
def length
|
134
|
+
number_of_otus
|
135
|
+
end
|
136
|
+
|
137
|
+
def to_xml
|
138
|
+
node = @@writer.create_node( "otus", @@writer.attributes( self, :id, :label ) )
|
139
|
+
self.each do |otu|
|
140
|
+
node << otu.to_xml
|
141
|
+
end
|
142
|
+
node
|
143
|
+
end
|
144
|
+
|
145
|
+
end #end class Otus
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,663 @@
|
|
1
|
+
require 'bio/tree'
|
2
|
+
|
3
|
+
module Bio
|
4
|
+
module NeXML
|
5
|
+
|
6
|
+
# Node represents a node of a Tree or a Network. A node must have a unique id. It may optionally
|
7
|
+
# have a human readable 'label' and may link to an 'otu'.
|
8
|
+
class Node < Bio::Tree::Node
|
9
|
+
include Mapper
|
10
|
+
@@writer = Bio::NeXML::Writer.new
|
11
|
+
|
12
|
+
def to_xml
|
13
|
+
@@writer.create_node( "node", @@writer.attributes( self, :id, :otu, :root, :label ) )
|
14
|
+
end
|
15
|
+
|
16
|
+
# A file level unique identifier.
|
17
|
+
attr_accessor :id
|
18
|
+
|
19
|
+
# Stores a boolean value to indicate a root node.
|
20
|
+
attr_accessor :root
|
21
|
+
|
22
|
+
# A human readable description.
|
23
|
+
attr_accessor :label
|
24
|
+
|
25
|
+
# A node may optionally refer to an Otu.
|
26
|
+
belongs_to :otu
|
27
|
+
|
28
|
+
# A node is deemed part of a Tree.
|
29
|
+
belongs_to :tree
|
30
|
+
|
31
|
+
# Create a new otu. Passing an 'id' is a must. While 'label' and 'otu' may be passed
|
32
|
+
# as an optional hash.
|
33
|
+
# node = Bio::NeXML::Node.new( 'node1' )
|
34
|
+
# node = Bio::NeXML::Node.new( 'node1', :label => 'A node' )
|
35
|
+
# node = Bio::NeXML::Node.new( 'node1', :label => 'A node', :otu => otu )
|
36
|
+
def initialize( id, options = {} )
|
37
|
+
super( id )
|
38
|
+
@id = id
|
39
|
+
properties( options ) unless options.empty?
|
40
|
+
block.arity < 1 ? instance_eval( &block ) : block.call( self ) if block_given?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return the otu to which the node links to.
|
44
|
+
def otu; end if false # dummy for rdoc
|
45
|
+
|
46
|
+
# Link the node to the given otu.
|
47
|
+
def otu=( otu ); end if false # dummy for rdoc
|
48
|
+
|
49
|
+
# Returns true if the node is a root node; false otherwise.
|
50
|
+
def root?
|
51
|
+
root
|
52
|
+
end
|
53
|
+
end #end class Node
|
54
|
+
|
55
|
+
# Edge connect two nodes of a tree or a network. An edge should have a unique id. It should have
|
56
|
+
# a 'source' and a 'target' node and optionally a 'length' may be assigned to it.
|
57
|
+
class Edge < Bio::Tree::Edge
|
58
|
+
include Mapper
|
59
|
+
@@writer = Bio::NeXML::Writer.new
|
60
|
+
|
61
|
+
def to_xml
|
62
|
+
@@writer.create_node( "edge", @@writer.attributes( self, :id, :source, :target, :length, :label ) )
|
63
|
+
end
|
64
|
+
|
65
|
+
# A file level unique identifier.
|
66
|
+
attr_accessor :id
|
67
|
+
|
68
|
+
# Source of the edge.
|
69
|
+
attr_accessor :source
|
70
|
+
|
71
|
+
# Target of the edge.
|
72
|
+
attr_accessor :target
|
73
|
+
|
74
|
+
# A human readable description.
|
75
|
+
attr_accessor :label
|
76
|
+
|
77
|
+
# A node is deemed part of a Tree.
|
78
|
+
belongs_to :tree
|
79
|
+
|
80
|
+
# Create a new edge.
|
81
|
+
# edge = Bio::NeXML::Edge.new( 'edge1' )
|
82
|
+
# edge = Bio::NeXML::Edge.new( 'edge1', :source => node1, :target => node2 )
|
83
|
+
# edge = Bio::NeXML::Edge.new( 'edge1', :source => node1, :target => node2, :length => 1 )
|
84
|
+
def initialize( id, options = {} )
|
85
|
+
super( length )
|
86
|
+
@id = id
|
87
|
+
properties( options ) unless options.empty?
|
88
|
+
block.arity < 1 ? instance_eval( &block ) : block.call( self ) if block_given?
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return the length of an edge.
|
92
|
+
def length
|
93
|
+
distance
|
94
|
+
end
|
95
|
+
|
96
|
+
# Set the length of an edge.
|
97
|
+
def length=( length )
|
98
|
+
self.distance = length
|
99
|
+
end
|
100
|
+
end #end class Edge
|
101
|
+
|
102
|
+
# A rootedge is an edge without a source. It is used in context of coalescent trees. RootEdge
|
103
|
+
# inherits from Edge so the same functionality is available in rootedge too.
|
104
|
+
class RootEdge < Edge
|
105
|
+
@@writer = Bio::NeXML::Writer.new
|
106
|
+
def to_xml
|
107
|
+
@@writer.create_node( "rootedge", @@writer.attributes( self, :id, :target, :length, :label ) )
|
108
|
+
end
|
109
|
+
|
110
|
+
private :source=
|
111
|
+
|
112
|
+
def initialize( id, options = {} )
|
113
|
+
super
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class FloatRootEdge < RootEdge
|
118
|
+
def initialize( id, options = {} )
|
119
|
+
super
|
120
|
+
end
|
121
|
+
def length
|
122
|
+
distance.to_f
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class IntRootEdge < RootEdge
|
127
|
+
def initialize( id, options = {} )
|
128
|
+
super
|
129
|
+
end
|
130
|
+
def length
|
131
|
+
distance.to_i
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# A float edge is an edge whose length is defined using a floating point
|
136
|
+
# number.
|
137
|
+
class FloatEdge < Edge
|
138
|
+
def initialize( id, options = {} )
|
139
|
+
super
|
140
|
+
end
|
141
|
+
def length
|
142
|
+
distance.to_f
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# An int edge is an edge whose length is defined using an integer
|
147
|
+
class IntEdge < Edge
|
148
|
+
def initialize( id, options = {} )
|
149
|
+
super
|
150
|
+
end
|
151
|
+
def length
|
152
|
+
distance.to_i
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# An NeXML tree. A tree must have a unique 'id'. It may optionally take a 'label' and a 'rootedge'.
|
157
|
+
# This class inherits from Bio::Tree; naturally its functionality is leveraged here.
|
158
|
+
class Tree < Bio::Tree
|
159
|
+
include Mapper
|
160
|
+
@@writer = Bio::NeXML::Writer.new
|
161
|
+
|
162
|
+
def to_xml
|
163
|
+
node = @@writer.create_node( "tree", @@writer.attributes( self, :id, :'xsi:type', :label ) )
|
164
|
+
|
165
|
+
self.each_node do |n|
|
166
|
+
node << n.to_xml
|
167
|
+
end
|
168
|
+
|
169
|
+
rootedge = self.rootedge
|
170
|
+
node << rootedge.to_xml if rootedge
|
171
|
+
|
172
|
+
self.each_edge do |edge|
|
173
|
+
node << edge.to_xml
|
174
|
+
end
|
175
|
+
|
176
|
+
node
|
177
|
+
end
|
178
|
+
|
179
|
+
def create_node( options = {} )
|
180
|
+
node = Node.new( Bio::NeXML.generate_id( Node ), options )
|
181
|
+
self << node
|
182
|
+
node
|
183
|
+
end
|
184
|
+
|
185
|
+
def create_edge( options = {} )
|
186
|
+
raise "This is supposed to be an abstract method"
|
187
|
+
end
|
188
|
+
|
189
|
+
def create_rootedge( options = {} )
|
190
|
+
raise "This is supposed to be an abstract method"
|
191
|
+
end
|
192
|
+
|
193
|
+
# A file level unique identifier.
|
194
|
+
attr_accessor :id
|
195
|
+
|
196
|
+
# A human readable description.
|
197
|
+
attr_accessor :label
|
198
|
+
|
199
|
+
# A rootedge to indicate a time span leading up to the root.
|
200
|
+
attr_accessor :rootedge
|
201
|
+
|
202
|
+
# A tree is contained in Trees.
|
203
|
+
belongs_to :trees
|
204
|
+
|
205
|
+
# A tree will contain n number of nodes.
|
206
|
+
has_n :nodes
|
207
|
+
|
208
|
+
# A tree will contain n number of edges joining the nodes.
|
209
|
+
has_n :edges
|
210
|
+
|
211
|
+
# Create a new tree.
|
212
|
+
# tree = Bio::NeXML::Tree.new( 'tree1' )
|
213
|
+
# tree = Bio::NeXML::Tree.new( 'tree1', :label => 'A tree' )
|
214
|
+
#
|
215
|
+
# nodes = %w|node1 node2 node3|.map{ |n| Bio::NeXML::Node.new( n ) }
|
216
|
+
# edge1 = Bio::NeXML::Edge.new( 'edge1', :source => nodes[0], :target => nodes[1] )
|
217
|
+
# edge2 = Bio::NeXML::Edge.new( 'edge2', :source => nodes[0], :target => nodes[2] )
|
218
|
+
#
|
219
|
+
# tree = Bio::NeXML::Tree.new( 'tree1', :nodes => nodes )
|
220
|
+
# tree = Bio::NeXML::Tree.new do |t|
|
221
|
+
# t.label = 'A tree'
|
222
|
+
# t.nodes = nodes
|
223
|
+
# t.edges = [ edge1, edge2 ]
|
224
|
+
# # or, t << edge1 << edge2
|
225
|
+
# # or, t.add_edge( edge1 ); t.add_edge( edge2 )
|
226
|
+
#
|
227
|
+
# root = Bio::NeXML::Node.new( 'root1', :root => true )
|
228
|
+
# rootedge = Bio::NeXML::RootEdge.new( 're1', :target => root )
|
229
|
+
#
|
230
|
+
# t << root # or, t.add_otu( root )
|
231
|
+
# t.rootedge = rootedge
|
232
|
+
# end
|
233
|
+
def initialize( id = nil, options = {}, &block )
|
234
|
+
super()
|
235
|
+
@id = id
|
236
|
+
properties( options ) unless options.empty?
|
237
|
+
block.arity < 1 ? instance_eval( &block ) : block.call( self ) if block_given?
|
238
|
+
end
|
239
|
+
|
240
|
+
# Returns an array of root nodes.
|
241
|
+
def roots
|
242
|
+
nodes.select{ |n| n.root? }
|
243
|
+
end
|
244
|
+
|
245
|
+
# Append a node or an edge to the tree. The method delegates the actuall addition to
|
246
|
+
# <tt>add_node</tt>, <tt>add_edge</tt> methods.
|
247
|
+
def <<( object )
|
248
|
+
case object
|
249
|
+
when Node
|
250
|
+
add_node( object )
|
251
|
+
when Edge
|
252
|
+
add_edge( object )
|
253
|
+
end
|
254
|
+
self
|
255
|
+
end
|
256
|
+
|
257
|
+
# :stopdoc:
|
258
|
+
alias __add_node__ add_node
|
259
|
+
# :startdoc:
|
260
|
+
# Add a node to the tree.
|
261
|
+
def add_node( node )
|
262
|
+
super( node )
|
263
|
+
__add_node__( node )
|
264
|
+
end
|
265
|
+
|
266
|
+
# :stopdoc:
|
267
|
+
alias __add_edge__ add_edge
|
268
|
+
# :startdoc:
|
269
|
+
# Add an edge to the tree.
|
270
|
+
def add_edge( edge )
|
271
|
+
super( edge.source, edge.target, edge )
|
272
|
+
__add_edge__( edge )
|
273
|
+
end
|
274
|
+
|
275
|
+
def add_rootedge( edge )
|
276
|
+
@rootedge = edge
|
277
|
+
end
|
278
|
+
|
279
|
+
# :stopdoc:
|
280
|
+
alias __delete_node__ delete_node
|
281
|
+
# :startdoc:
|
282
|
+
|
283
|
+
# Remove a node from the tree. Returns the deleted node. It automatically removes all edges
|
284
|
+
# connected to that node. Raises IndexError if the node is not found in the tree.
|
285
|
+
def remove_node( node )
|
286
|
+
return unless include?( node )
|
287
|
+
super( node )
|
288
|
+
__delete_node__( node )
|
289
|
+
end
|
290
|
+
alias delete_node remove_node
|
291
|
+
|
292
|
+
# :stopdoc:
|
293
|
+
alias __delete_edge__ delete_edge
|
294
|
+
# :startdoc:
|
295
|
+
|
296
|
+
# Remove an edge from the tree. Returns the edge deleted. If more than one edge exists between
|
297
|
+
# the source and the target, both of them will be removed. Raises IndexError if the edge is
|
298
|
+
# not found in the tree.
|
299
|
+
def remove_edge( edge )
|
300
|
+
return unless include?( edge )
|
301
|
+
super( edge.source, edge.target )
|
302
|
+
__delete_edge__( edge )
|
303
|
+
end
|
304
|
+
alias delete_edge remove_edge
|
305
|
+
|
306
|
+
# Fetch a node by the given id.
|
307
|
+
def get_node_by_id( id ); end if false # dummy for rdoc
|
308
|
+
|
309
|
+
# get_node_by_name is actually defined in Bio::Tree. I have aliased it to get_node_by_id
|
310
|
+
# as hash lookup is faster than searching through an enumerable.
|
311
|
+
alias get_node_by_name get_node_by_id
|
312
|
+
|
313
|
+
# Fetch an edge by the given id.
|
314
|
+
def get_edge_by_id( id ); end if false # dummy for rdoc
|
315
|
+
|
316
|
+
# Fetch a node, or an edge by its id.
|
317
|
+
def []( id )
|
318
|
+
get_node_by_id( id ) ||
|
319
|
+
get_edge_by_id( id )
|
320
|
+
end
|
321
|
+
|
322
|
+
# Returns true if the given node is a part of <tt>self</tt>.
|
323
|
+
def has_node?( node ); end if false # dummy for rdoc
|
324
|
+
|
325
|
+
# Returns true if the given edge is a part of <tt>self</tt>.
|
326
|
+
def has_edge?( edge ); end if false # dummy for rdoc
|
327
|
+
|
328
|
+
# Returns true if the given node or the edge object is a part of this tree; false otherwise.
|
329
|
+
def include?( object )
|
330
|
+
has_node?( object ) ||
|
331
|
+
has_edge?( object )
|
332
|
+
end
|
333
|
+
alias has? include?
|
334
|
+
|
335
|
+
# Iterate over each node. Return an Enumerator if no block is given.
|
336
|
+
def each_node( &block ); end if false # dummy for rdoc
|
337
|
+
|
338
|
+
# Iterate over each node passing id and the node itself to the given block.
|
339
|
+
# Returns an Enumerator if no block is given.
|
340
|
+
def each_node_with_id; end if false # dummy for rdoc
|
341
|
+
|
342
|
+
# Iterate over each edge. Return an Enumerator if no block is given.
|
343
|
+
def each_edge; end if false # :yield: edge
|
344
|
+
|
345
|
+
# Iterate over each node passing id and the node itself to the given block.
|
346
|
+
# Returns an Enumerator if no block is given.
|
347
|
+
def each_edge_with_id; end if false # dummy for rdoc
|
348
|
+
|
349
|
+
# Return the number of nodes in the tree.
|
350
|
+
def number_of_nodes; end if false #dummy for rdoc
|
351
|
+
|
352
|
+
# Return the number of edges in the tree.
|
353
|
+
def number_of_edges; end if false #dummy for rdoc
|
354
|
+
|
355
|
+
# :stopdoc:
|
356
|
+
# Following methods have been redifined from Bio::Tree to take advantage of multiple root
|
357
|
+
# nodes in NeXML. Since for each root a differrent solution is possible, the result returned
|
358
|
+
# is a ( root, solution) hash. The solution for each root is the same as that returned by its
|
359
|
+
# super method.
|
360
|
+
# :startdoc:
|
361
|
+
|
362
|
+
# Returns the parent of the given node corresponding to each root.
|
363
|
+
def parent( node, *roots )
|
364
|
+
if roots.empty?
|
365
|
+
raise IndexError, 'can not get parent for unrooted tree' if self.roots.empty?
|
366
|
+
roots = self.roots
|
367
|
+
end
|
368
|
+
parents = {}
|
369
|
+
roots.each do |r|
|
370
|
+
parents[ r ] = super( node, r )
|
371
|
+
end
|
372
|
+
parents
|
373
|
+
end
|
374
|
+
|
375
|
+
def children( node, *root )
|
376
|
+
if root.empty?
|
377
|
+
raise IndexError, 'can not get parent for unrooted tree' if self.root.empty?
|
378
|
+
root = self.root
|
379
|
+
end
|
380
|
+
childrens = {}
|
381
|
+
root.each do |r|
|
382
|
+
c = adjacent_nodes(node)
|
383
|
+
c.delete(parent(node, r)[ r ])
|
384
|
+
childrens[ r ] = c
|
385
|
+
end
|
386
|
+
|
387
|
+
childrens
|
388
|
+
end
|
389
|
+
|
390
|
+
def descendents( node, *root )
|
391
|
+
if root.empty?
|
392
|
+
raise IndexError, 'can not get parent for unrooted tree' if self.root.empty?
|
393
|
+
root = self.root
|
394
|
+
end
|
395
|
+
descendent = {}
|
396
|
+
root.each do |r|
|
397
|
+
descendent[ r ] = super( node, r )
|
398
|
+
end
|
399
|
+
descendent
|
400
|
+
end
|
401
|
+
|
402
|
+
def lowest_common_ancestor( node1, node2, *root )
|
403
|
+
if root.empty?
|
404
|
+
raise IndexError, 'can not get parent for unrooted tree' if self.root.empty?
|
405
|
+
root = self.root
|
406
|
+
end
|
407
|
+
lca = {}
|
408
|
+
root.each do |r|
|
409
|
+
lca[ r ] = super( node1, node2, r )
|
410
|
+
end
|
411
|
+
lca
|
412
|
+
end
|
413
|
+
|
414
|
+
def ancestors( node, *root )
|
415
|
+
if root.empty?
|
416
|
+
raise IndexError, 'can not get parent for unrooted tree' if self.root.empty?
|
417
|
+
root = self.root
|
418
|
+
end
|
419
|
+
ancestor = {}
|
420
|
+
root.each do |r|
|
421
|
+
ancestor[ r ] = super( node, r )
|
422
|
+
end
|
423
|
+
ancestor
|
424
|
+
end
|
425
|
+
end #end class Tree
|
426
|
+
|
427
|
+
class IntTree < Tree
|
428
|
+
def initialize( id = nil, options = {}, &block )
|
429
|
+
super
|
430
|
+
end
|
431
|
+
|
432
|
+
def add_edge( edge )
|
433
|
+
edge.length = edge.length.to_i
|
434
|
+
super
|
435
|
+
end
|
436
|
+
|
437
|
+
def create_edge( options = {} )
|
438
|
+
edge = IntEdge.new( Bio::NeXML.generate_id( IntEdge ), options )
|
439
|
+
self << edge
|
440
|
+
edge
|
441
|
+
end
|
442
|
+
|
443
|
+
def create_rootedge( options = {} )
|
444
|
+
rootedge = IntRootEdge.new( Bio::NeXML.generate_id( IntRootEdge ), options )
|
445
|
+
self << rootedge
|
446
|
+
rootedge
|
447
|
+
end
|
448
|
+
|
449
|
+
end
|
450
|
+
|
451
|
+
class FloatTree < Tree
|
452
|
+
def initialize( id = nil, options = {}, &block )
|
453
|
+
super
|
454
|
+
end
|
455
|
+
|
456
|
+
def add_edge( edge )
|
457
|
+
edge.length = edge.length.to_f
|
458
|
+
super
|
459
|
+
end
|
460
|
+
|
461
|
+
def create_edge( options = {} )
|
462
|
+
edge = FloatEdge.new( Bio::NeXML.generate_id( FloatEdge ), options )
|
463
|
+
self << edge
|
464
|
+
edge
|
465
|
+
end
|
466
|
+
|
467
|
+
def create_rootedge( options = {} )
|
468
|
+
rootedge = FloatRootEdge.new( Bio::NeXML.generate_id( FloatRootEdge ), options )
|
469
|
+
self << rootedge
|
470
|
+
rootedge
|
471
|
+
end
|
472
|
+
|
473
|
+
end
|
474
|
+
|
475
|
+
class Network < Tree
|
476
|
+
@@writer = Bio::NeXML::Writer.new
|
477
|
+
belongs_to :trees
|
478
|
+
def initialize( id, options = {}, &block )
|
479
|
+
super
|
480
|
+
end
|
481
|
+
|
482
|
+
def to_xml
|
483
|
+
node = @@writer.create_node( "network", @@writer.attributes( self, :id, :'xsi:type', :label ) )
|
484
|
+
|
485
|
+
self.each_node do |n|
|
486
|
+
node << n.to_xml
|
487
|
+
end
|
488
|
+
|
489
|
+
self.each_edge do |edge|
|
490
|
+
node << edge.to_xml
|
491
|
+
end
|
492
|
+
|
493
|
+
node
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
class IntNetwork < Network
|
498
|
+
def initialize( id, options = {}, &block )
|
499
|
+
super
|
500
|
+
end
|
501
|
+
|
502
|
+
def add_edge( edge )
|
503
|
+
edge.length = edge.length.to_i
|
504
|
+
super
|
505
|
+
end
|
506
|
+
|
507
|
+
def create_edge( options = {} )
|
508
|
+
edge = IntEdge.new( Bio::NeXML.generate_id( IntEdge ), options )
|
509
|
+
self << edge
|
510
|
+
edge
|
511
|
+
end
|
512
|
+
|
513
|
+
end
|
514
|
+
|
515
|
+
class FloatNetwork < Network
|
516
|
+
def initialize( id, options = {}, &block )
|
517
|
+
super
|
518
|
+
end
|
519
|
+
|
520
|
+
def add_edge( edge )
|
521
|
+
edge.length = edge.length.to_f
|
522
|
+
super
|
523
|
+
end
|
524
|
+
|
525
|
+
def create_edge( options = {} )
|
526
|
+
edge = FloatEdge.new( Bio::NeXML.generate_id( FloatEdge ), options )
|
527
|
+
self << edge
|
528
|
+
edge
|
529
|
+
end
|
530
|
+
|
531
|
+
end
|
532
|
+
|
533
|
+
class Trees
|
534
|
+
include Mapper
|
535
|
+
@@writer = Bio::NeXML::Writer.new
|
536
|
+
|
537
|
+
def to_xml
|
538
|
+
node = @@writer.create_node( "trees", @@writer.attributes( self, :id, :label, :otus ) )
|
539
|
+
|
540
|
+
self.each_tree do |tree|
|
541
|
+
node << tree.to_xml
|
542
|
+
end
|
543
|
+
|
544
|
+
self.each_network do |network|
|
545
|
+
node << network.to_xml
|
546
|
+
end
|
547
|
+
|
548
|
+
node
|
549
|
+
end
|
550
|
+
|
551
|
+
def create_tree( int = false, options = {} )
|
552
|
+
type = int ? Bio::NeXML::IntTree : Bio::NeXML::FloatTree
|
553
|
+
tree = type.new( Bio::NeXML.generate_id( type ), options )
|
554
|
+
self << tree
|
555
|
+
tree
|
556
|
+
end
|
557
|
+
|
558
|
+
def create_network( int = false, options = {} )
|
559
|
+
type = int ? Bio::NeXML::IntNetwork : Bio::NeXML::FloatNetwork
|
560
|
+
network = type.new( Bio::NeXML.generate_id( type ), options )
|
561
|
+
self << network
|
562
|
+
network
|
563
|
+
end
|
564
|
+
|
565
|
+
attr_accessor :id
|
566
|
+
attr_accessor :label
|
567
|
+
|
568
|
+
# A trees refers links to an otu.
|
569
|
+
belongs_to :otus
|
570
|
+
|
571
|
+
# Trees is a container for trees and networks.
|
572
|
+
has_n :trees
|
573
|
+
has_n :networks
|
574
|
+
|
575
|
+
belongs_to :nexml
|
576
|
+
|
577
|
+
# Create a trees object.
|
578
|
+
def initialize( id = nil, options = {}, &block )
|
579
|
+
@id = id
|
580
|
+
properties( options ) unless options.empty?
|
581
|
+
block.arity < 1 ? instance_eval( &block ) : block.call( self ) if block_given?
|
582
|
+
end
|
583
|
+
|
584
|
+
# Add a tree to self.
|
585
|
+
def add_tree; end if false # dummy for rdoc
|
586
|
+
|
587
|
+
# Add a networ to self.
|
588
|
+
def add_network; end if false # dummy for rdoc
|
589
|
+
|
590
|
+
# Add a tree or a network to self.
|
591
|
+
def <<( object )
|
592
|
+
case object
|
593
|
+
when Network
|
594
|
+
add_network( object )
|
595
|
+
when Tree
|
596
|
+
add_tree( object )
|
597
|
+
end
|
598
|
+
self
|
599
|
+
end
|
600
|
+
|
601
|
+
# Delete a tree from self.
|
602
|
+
def delete_tree; end if false # dummy for rdoc
|
603
|
+
|
604
|
+
# Delete a network from self.
|
605
|
+
def delete_network; end if false # dummy for rdoc
|
606
|
+
|
607
|
+
# Fetch a tree by id.
|
608
|
+
def get_tree_by_id; end if false # dummy for rdoc
|
609
|
+
|
610
|
+
# Fetch a network by id.
|
611
|
+
def get_network_by_id; end if false # dummy for rdoc
|
612
|
+
|
613
|
+
# Fetch a tree or a network by id.
|
614
|
+
def []( id )
|
615
|
+
get_tree_by_id( id ) ||
|
616
|
+
get_network_by_id( id )
|
617
|
+
end
|
618
|
+
|
619
|
+
# Returns true if tree is containes in self.
|
620
|
+
def has_tree?( tree ); end if false # dummy for rdoc
|
621
|
+
|
622
|
+
# Returns true if the given network is containes in self; false otherwise.
|
623
|
+
def has_network?( tree ); end if false # dummy for rdoc
|
624
|
+
|
625
|
+
def include?( object )
|
626
|
+
has_tree?( object ) ||
|
627
|
+
has_network?( object )
|
628
|
+
end
|
629
|
+
alias has? include?
|
630
|
+
|
631
|
+
# Returns the number of trees contained in self.
|
632
|
+
def number_of_trees; end if false # dummy for rdoc
|
633
|
+
|
634
|
+
# Returns the number of networks contained in self.
|
635
|
+
def number_of_networks; end if false # dummy for rdoc
|
636
|
+
|
637
|
+
# Returns total number of trees and networks.
|
638
|
+
def count
|
639
|
+
number_of_trees + number_of_networks
|
640
|
+
end
|
641
|
+
alias length count
|
642
|
+
|
643
|
+
# Iterate over each tree. Returns an Enumerator if no block is given.
|
644
|
+
def each_tree( &block ); end if false # dummy for rdoc
|
645
|
+
|
646
|
+
# Iterate over each tree passing the id and the tree itself to the block.
|
647
|
+
# Returns an Enumerator if no block is given.
|
648
|
+
def each_tree_with_id( &block ); end if false # dummy for rdoc
|
649
|
+
|
650
|
+
# Iterate over each network. Returns an Enumerator if no block is given.
|
651
|
+
def each_network( &block ); end if false # dummy for rdoc
|
652
|
+
|
653
|
+
# Iterate over each network passing the id and the tree itself to the block.
|
654
|
+
# Returns an Enumerator if no block is given.
|
655
|
+
def each_network_with_id( &block ); end if false # dummy for rdoc
|
656
|
+
|
657
|
+
# Iterate over each element. Returns an Enumerator if no block is given.
|
658
|
+
def each( &block )
|
659
|
+
@trees.merge( @networks ).each( &block )
|
660
|
+
end
|
661
|
+
end #end class Trees
|
662
|
+
end #end module NeXML
|
663
|
+
end #end module Bio
|