graphs 0.1.0-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
data/lib/graph.rb ADDED
@@ -0,0 +1,81 @@
1
+ # -*- coding: UTF-8 -*-
2
+
3
+ require 'yaml'
4
+
5
+ class Graph
6
+
7
+ class NodeArray < Array
8
+
9
+ def initialize(*args)
10
+ super(*args)
11
+ @defaults = {}
12
+ end
13
+
14
+ def set_default(dict)
15
+ @defaults.update(dict)
16
+ self.map! { |e| e.update(@defaults) }
17
+ end
18
+
19
+ def push(o)
20
+ if (!o.is_a?(Hash))
21
+ raise TypeError.new "#{o.inspect} is not an Hash!"
22
+ end
23
+ o2 = o.clone
24
+ o2.update(@defaults)
25
+ super
26
+ end
27
+ end
28
+
29
+ class EdgeArray < NodeArray
30
+ end
31
+
32
+ attr_accessor :nodes, :edges
33
+
34
+ def initialize(nodes=nil, edges=nil)
35
+ @nodes = NodeArray.new(nodes || [])
36
+ @edges = EdgeArray.new(edges || [])
37
+ end
38
+
39
+ def ==(other)
40
+ if (!other.is_a?(Graph))
41
+ return false
42
+ end
43
+ (self.nodes === other.nodes) && (self.edges == other.edges)
44
+ end
45
+
46
+ def &(other)
47
+ if (!other.is_a?(Graph))
48
+ return nil
49
+ end
50
+
51
+ nodes = @nodes & other.nodes
52
+ edges = @edges & other.edges
53
+
54
+ Graph.new(nodes, edges)
55
+ end
56
+
57
+ def write(filename, opts=nil)
58
+
59
+ has_ext = filename.split('.')
60
+
61
+ if ((has_ext.length == 1) || (has_ext[-1] == 'yml'))
62
+ # YAML (default)
63
+ nodes = self.nodes.to_a
64
+ edges = self.edges.to_a
65
+
66
+ data = {'nodes'=>nodes, 'edges'=>edges}.to_yaml
67
+ f = open(filename+'.yml', 'w')
68
+ f.write(data)
69
+ f.close
70
+ else
71
+ ext = has_ext[-1]
72
+
73
+ m = (self.methods - Object.methods).map {|e| e.to_s}
74
+
75
+ if (m.include? '_write_'+ext.downcase)
76
+ self.send('_write_'+ext.downcase, filename, opts)
77
+ end
78
+ end
79
+
80
+ end
81
+ end
data/lib/graphs/gdf.rb ADDED
@@ -0,0 +1,182 @@
1
+ # -*- coding: UTF-8 -*-
2
+
3
+ require_relative '../graph'
4
+
5
+ class Graph
6
+ def to_gdf(opts=nil)
7
+ GDF::unparse(self, opts)
8
+ end
9
+
10
+ def _write_gdf(filename, opts=nil)
11
+ gdf = GDF::unparse(self, opts)
12
+ f = File.open(filename, 'w')
13
+ f.write(gdf)
14
+ f.close
15
+ end
16
+ end
17
+
18
+ module GDF
19
+
20
+ def self.load(filename)
21
+ self.parse(File.read(filename))
22
+ end
23
+
24
+ def self.parse(content)
25
+
26
+ if (content.nil? || content.length == 0)
27
+ return Graph.new([],[])
28
+ end
29
+
30
+ content = content.split("\n")
31
+
32
+ # lines index of 'nodedef>' and 'edgedef>'
33
+ nodes_def_index = -1
34
+ edges_def_index = -1
35
+
36
+ content.each_with_index {|l,i|
37
+ if l.start_with? 'nodedef>'
38
+ nodes_def_index = i
39
+ elsif l.start_with? 'edgedef>'
40
+ edges_def_index = i
41
+ end
42
+
43
+ if ((nodes_def_index >= 0) && (edges_def_index >= 0))
44
+ break
45
+ end
46
+ }
47
+
48
+ # no edges
49
+ if (edges_def_index == -1)
50
+ edges = []
51
+ edges_def_index = content.length
52
+ else
53
+ edges = content[edges_def_index+1..content.length]
54
+ end
55
+
56
+ fields_split = /[\t ]*,[\t ]*/
57
+
58
+ # only nodes lines
59
+ nodes = content[nodes_def_index+1..[edges_def_index-1, content.length].min] || []
60
+
61
+ nodes_def = content[nodes_def_index]
62
+ nodes_def = nodes_def['nodedef>'.length..nodes_def.length].strip.split(fields_split)
63
+ nodes_def.each_index {|i|
64
+ nodes_def[i] = read_def(nodes_def[i])
65
+ }
66
+
67
+ nodes.each_with_index {|n,i|
68
+ n2 = {}
69
+ n = n.split(fields_split)
70
+ n.zip(nodes_def).each {|val,label_type|
71
+ label, type = label_type
72
+ n2[label] = parse_field(val, type)
73
+ }
74
+ nodes[i] = n2
75
+ }
76
+
77
+ if (edges === [])
78
+ return Graph.new(nodes)
79
+ end
80
+
81
+ # only edges lines
82
+ edges_def = content[edges_def_index]
83
+ edges_def = edges_def['edgedef>'.length..edges_def.length].strip.split(fields_split)
84
+ edges_def.each_index {|i|
85
+ edges_def[i] = read_def(edges_def[i])
86
+ }
87
+
88
+ edges.each_with_index {|e,i|
89
+ e2 = {}
90
+ e = e.split(fields_split)
91
+
92
+ e.zip(edges_def).each {|val,label_type|
93
+ label, type = label_type
94
+ e2[label] = parse_field(val, type)
95
+ }
96
+ edges[i] = e2
97
+ }
98
+
99
+ Graph.new(nodes, edges)
100
+ end
101
+
102
+ def self.unparse(graph, opts=nil)
103
+
104
+ # nodes
105
+ gdf_s = 'nodedef>'
106
+
107
+ if (graph.nodes.length == 0)
108
+ return gdf_s
109
+ end
110
+
111
+ keys = graph.nodes[0].keys
112
+ nodedef = keys.map { |k| [k, self.get_type(graph.nodes[0][k], opts)] }
113
+
114
+ gdf_s += (nodedef.map {|nd| nd.join(' ')}).join(',') + "\n"
115
+
116
+ graph.nodes.each { |n|
117
+ gdf_s += n.values.join(',') + "\n"
118
+ }
119
+
120
+ # edges
121
+ gdf_s += 'edgedef>'
122
+
123
+ if (graph.edges.length == 0)
124
+ return gdf_s
125
+ end
126
+
127
+ keys = graph.edges[0].keys
128
+ edgedef = keys.map { |k| [k, self.get_type(graph.edges[0][k], opts)] }
129
+
130
+ gdf_s += (edgedef.map {|ed| ed.join(' ')}).join(',') + "\n"
131
+
132
+ graph.edges.each { |e|
133
+ gdf_s += e.values.join(',') + "\n"
134
+ }
135
+
136
+ gdf_s
137
+ end
138
+
139
+ private
140
+
141
+ # read the value of a node|edge field, and return the value's type (String)
142
+ def self.get_type(v, opts=nil)
143
+ opts = opts || {}
144
+
145
+ if v.is_a?(Fixnum)
146
+ return 'INT'
147
+ elsif v.is_a?(Bignum)
148
+ return opts[:gephi] ? 'INT' : 'BIGINT'
149
+ elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
150
+ return 'BOOLEAN'
151
+ elsif v.is_a?(Float)
152
+ return 'FLOAT'
153
+ else
154
+ return 'VARCHAR'
155
+ end
156
+ end
157
+
158
+ # read a (node|edge)def, and return ['label', 'type of value']
159
+ def self.read_def(s)
160
+ *label, value_type = s.split /\s+/
161
+ if /((tiny|small|medium|big)?int|integer)/i.match(value_type)
162
+ value_type = 'int'
163
+ elsif /(float|real|double)/i.match(value_type)
164
+ value_type = 'float'
165
+ elsif (value_type.downcase === 'boolean')
166
+ value_type = 'boolean'
167
+ end
168
+
169
+ [label.join(' '), value_type]
170
+ end
171
+
172
+ # read a field and return its value
173
+ def self.parse_field(f, value_type)
174
+ case value_type
175
+ when 'int' then f.to_i
176
+ when 'float' then f.to_f
177
+ when 'boolean' then !(/(null|false)/i =~ f)
178
+ else f
179
+ end
180
+ end
181
+
182
+ end
@@ -0,0 +1,220 @@
1
+ #! /usr/bin/ruby1.9.1
2
+
3
+ require '../lib/graph'
4
+ require '../lib/graphes/gdf'
5
+ require 'test/unit'
6
+
7
+ module Utils
8
+ def self.get_sample_graph
9
+ @@sample_graph_1
10
+ end
11
+
12
+ @@sample_graph_1 = "nodedef>label VARCHAR,num INT,biglabel VARCHAR\n"
13
+ @@sample_graph_1 += "toto,14,TOTO\nlala,5,LALA\ntiti,988,TITI\n"
14
+ @@sample_graph_1 += "edgedef>node1 VARCHAR,node2 VARCHAR,directed BOOLEAN\n"
15
+ @@sample_graph_1 += "toto,lala,true\nlala,titi,true\n"
16
+ @@sample_graph_1 += "titi,lala,false\ntiti,toto,true\n"
17
+ end
18
+
19
+ class GDF_Graph_test < Test::Unit::TestCase
20
+
21
+ # == Graph#to_gdf == #
22
+
23
+ def test_empty_graph_to_gdf
24
+ g = Graph.new
25
+ empty_gdf = "nodedef>"
26
+
27
+ assert_equal(empty_gdf, g.to_gdf)
28
+ end
29
+
30
+ def test_sample_graph_to_gdf
31
+ gdf = Utils::get_sample_graph
32
+ g = GDF::parse(gdf)
33
+ assert_equal(gdf, g.to_gdf)
34
+ end
35
+
36
+ # == Graph#write('….gdf') == #
37
+
38
+ def test_empty_graph_write_gdf
39
+ g = Graph.new
40
+ g.write('/tmp/_graph_test.gdf')
41
+ g2 = GDF.load('/tmp/_graph_test.gdf')
42
+ assert_equal(g, g2)
43
+ end
44
+
45
+ def setup
46
+ if File.exists? '/tmp/_graph_test.gdf'
47
+ File.delete '/tmp/_graph_test.gdf'
48
+ end
49
+ end
50
+ end
51
+
52
+ class GDF_test < Test::Unit::TestCase
53
+
54
+ # == GDF::parse == #
55
+
56
+ def test_parse_empty_graph
57
+ g = GDF::parse('')
58
+
59
+ assert_equal([], g.nodes)
60
+ assert_equal([], g.edges)
61
+ end
62
+
63
+ def test_parse_empty_graph_with_nodedef
64
+
65
+ s = "nodedef>label VARCHAR\n"
66
+
67
+ g = GDF::parse(s)
68
+
69
+ assert_equal([], g.nodes)
70
+ assert_equal([], g.edges)
71
+ end
72
+
73
+ def test_parse_empty_graph_with_nodedef_and_edgedef
74
+ s = "nodedef>label VARCHAR\nedgedef>node1 VARCHAR,node2 VARCHAR\n"
75
+ g = GDF::parse(s)
76
+
77
+ assert_equal([], g.nodes)
78
+ assert_equal([], g.edges)
79
+ end
80
+
81
+ def test_parse_one_node_no_edge_string_field
82
+ s = "nodedef>label VARCHAR\nfoo\n"
83
+ g = GDF::parse(s)
84
+
85
+ assert_equal(1, g.nodes.length)
86
+ assert_equal('foo', g.nodes[0]['label'])
87
+ assert_equal([], g.edges)
88
+ end
89
+
90
+ def test_parse_one_node_no_edge_tinyint_field
91
+ s = "nodedef>num TINYINT\n3\n"
92
+ g = GDF::parse(s)
93
+
94
+ assert_equal(1, g.nodes.length)
95
+ assert_equal(3, g.nodes[0]['num'])
96
+ assert_equal([], g.edges)
97
+ end
98
+
99
+ def test_parse_one_node_no_edge_smallint_field
100
+ s = "nodedef>num SMALLINT\n3\n"
101
+ g = GDF::parse(s)
102
+
103
+ assert_equal(1, g.nodes.length)
104
+ assert_equal(3, g.nodes[0]['num'])
105
+ assert_equal([], g.edges)
106
+ end
107
+
108
+ def test_parse_one_node_no_edge_int_field
109
+ s = "nodedef>num INT\n3\n"
110
+ g = GDF::parse(s)
111
+
112
+ assert_equal(1, g.nodes.length)
113
+ assert_equal(3, g.nodes[0]['num'])
114
+ assert_equal([], g.edges)
115
+ end
116
+
117
+ def test_parse_one_node_no_edge_negative_int_field
118
+ s = "nodedef>num INT\n-1337\n"
119
+ g = GDF::parse(s)
120
+
121
+ assert_equal(1, g.nodes.length)
122
+ assert_equal(-1337, g.nodes[0]['num'])
123
+ assert_equal([], g.edges)
124
+ end
125
+
126
+ def test_parse_one_node_no_edge_bigint_field
127
+ s = "nodedef>num BIGINT\n3\n"
128
+ g = GDF::parse(s)
129
+
130
+ assert_equal(1, g.nodes.length)
131
+ assert_equal(3, g.nodes[0]['num'])
132
+ assert_equal([], g.edges)
133
+ end
134
+
135
+ def test_parse_one_node_no_edge_float_field
136
+ s = "nodedef>num FLOAT\n3\n"
137
+ g = GDF::parse(s)
138
+
139
+ assert_equal(1, g.nodes.length)
140
+ assert_equal(3.0, g.nodes[0]['num'])
141
+ assert_equal([], g.edges)
142
+ end
143
+
144
+ def test_parse_one_node_no_edge_double_field
145
+ s = "nodedef>num FLOAT\n3\n"
146
+ g = GDF::parse(s)
147
+
148
+ assert_equal(1, g.nodes.length)
149
+ assert_equal(3.0, g.nodes[0]['num'])
150
+ assert_equal([], g.edges)
151
+ end
152
+
153
+ def test_parse_one_node_no_edge_real_field
154
+ s = "nodedef>num FLOAT\n3\n"
155
+ g = GDF::parse(s)
156
+
157
+ assert_equal(1, g.nodes.length)
158
+ assert_equal(3.0, g.nodes[0]['num'])
159
+ assert_equal([], g.edges)
160
+ end
161
+
162
+ def test_parse_one_node_no_edge_negative_real_field
163
+ s = "nodedef>num FLOAT\n-42.14\n"
164
+ g = GDF::parse(s)
165
+
166
+ assert_equal(1, g.nodes.length)
167
+ assert_equal(-42.14, g.nodes[0]['num'])
168
+ assert_equal([], g.edges)
169
+ end
170
+
171
+ def test_parse_one_node_no_edge_unknow_field_type
172
+ s = "nodedef>foo BAR\nfoobar"
173
+ g = GDF::parse(s)
174
+
175
+ assert_equal(1, g.nodes.length)
176
+ assert_equal('foobar', g.nodes[0]['foo'])
177
+ assert_equal([], g.edges)
178
+ end
179
+
180
+ def test_parse_sample_graph
181
+ g = GDF::parse(Utils::get_sample_graph)
182
+
183
+ assert_equal(3, g.nodes.length)
184
+ assert_equal(4, g.edges.length)
185
+
186
+ assert_equal('toto', g.nodes[0]['label'])
187
+ assert_equal('TOTO', g.nodes[0]['biglabel'])
188
+ assert_equal(988, g.nodes[2]['num'])
189
+
190
+ assert_equal('toto', g.edges[0]['node1'])
191
+ assert_equal('lala', g.edges[0]['node2'])
192
+ assert_equal(false, g.edges[2]['directed'])
193
+
194
+ end
195
+
196
+ # == GDF::unparse == #
197
+
198
+ def test_unparse_empty_graph
199
+ g = Graph.new
200
+
201
+ s = GDF::unparse(g)
202
+
203
+ assert_equal("nodedef>", s)
204
+ end
205
+
206
+ def test_unparse_sample_graph
207
+ g1 = GDF::parse(Utils::get_sample_graph)
208
+ g2 = GDF::parse(GDF::unparse(g1))
209
+
210
+ assert_equal(g1, g2)
211
+ end
212
+
213
+ def test_unparse_big_int_gephi
214
+ g = Graph.new([{'n'=>9999999999999999}])
215
+ gdf = GDF::unparse(g, {:gephi=>true})
216
+
217
+ assert_equal("nodedef>n INT\n9999999999999999\nedgedef>", gdf)
218
+
219
+ end
220
+ end
@@ -0,0 +1,5 @@
1
+ #! /usr/bin/ruby1.9.1
2
+ # -*- coding: UTF-8 -*-
3
+
4
+ require 'test/unit'
5
+ require '../lib/graphes/gexf'
@@ -0,0 +1,174 @@
1
+ #! /usr/bin/ruby1.9.1
2
+ # -*- coding: UTF-8 -*-
3
+
4
+ require 'test/unit'
5
+ require 'yaml'
6
+ require_relative '../lib/graph'
7
+
8
+ class Graph_test < Test::Unit::TestCase
9
+
10
+ @@sample_graph = Graph.new(
11
+ [
12
+ {'label'=>'foo', 'id'=>2},
13
+ {'label'=>'bar', 'id'=>1},
14
+ {'label'=>'chuck', 'id'=>3}
15
+ ],
16
+ [
17
+ {'node1'=>'foo', 'node2'=>'bar'},
18
+ {'node1'=>'bar', 'node2'=>'foo'},
19
+ {'node1'=>'bar', 'node2'=>'chuck'},
20
+ {'node1'=>'foo', 'node2'=>'chuck'}
21
+ ]
22
+ )
23
+
24
+ def test_new_empty_graph
25
+ g = Graph.new
26
+
27
+ assert_equal([], g.nodes)
28
+ assert_equal([], g.edges)
29
+ end
30
+
31
+ # == Graph#== == #
32
+
33
+ def test_equal_graphs
34
+ g1 = @@sample_graph
35
+ g2 = @@sample_graph.clone()
36
+
37
+ assert_equal(true, g1==g2)
38
+ end
39
+
40
+ # == Graph::NodeArray#set_default == #
41
+
42
+ def test_nodearray_set_default_unexisting_property
43
+ g = Graph.new([{'name'=>'foo'}, {'name'=>'bar'}])
44
+ g.nodes.set_default 'age' => 21
45
+
46
+ assert_equal(21, g.nodes[0]['age'])
47
+ assert_equal(21, g.nodes[1]['age'])
48
+ end
49
+
50
+ def test_nodearray_set_default_existing_property
51
+ g = Graph.new([{'name'=>'foo', 'age'=>42}, {'name'=>'bar'}])
52
+ g.nodes.set_default 'age' => 21
53
+
54
+ assert_equal(21, g.nodes[0]['age'])
55
+ assert_equal(21, g.nodes[1]['age'])
56
+ end
57
+
58
+ def test_nodearray_set_default_unexisting_property_before_push
59
+ g = Graph.new([{'name'=>'foo'}])
60
+ g.nodes.set_default 'city' => 'Paris'
61
+ g.nodes.push({'name' => 'bar'})
62
+
63
+ assert_equal('Paris', g.nodes[0]['city'])
64
+ assert_equal('Paris', g.nodes[0]['city'])
65
+ end
66
+
67
+ def test_nodearray_set_default_existing_property_before_push
68
+ g = Graph.new([{'name'=>'foo', 'city'=>'London'}])
69
+ g.nodes.set_default 'city' => 'Paris'
70
+ g.nodes.push({'name' => 'bar'})
71
+
72
+ assert_equal('Paris', g.nodes[0]['city'])
73
+ assert_equal('Paris', g.nodes[0]['city'])
74
+ end
75
+
76
+ # == Graph::edgeArray#set_default == #
77
+
78
+ def test_edgearray_set_default_unexisting_property
79
+ g = Graph.new([],[{'node1'=>'foo', 'node2'=>'bar'}])
80
+ g.edges.set_default 'directed' => true
81
+
82
+ assert_equal(true, g.edges[0]['directed'])
83
+ end
84
+
85
+ def test_edgearray_set_default_existing_property
86
+ g = Graph.new([],
87
+ [{'node1'=>'foo', 'node2'=>'bar', 'directed'=>true},
88
+ {'node1'=>'bar', 'node2'=>'foo'}])
89
+ g.edges.set_default 'directed' => false
90
+
91
+ assert_equal(false, g.edges[0]['directed'])
92
+ assert_equal(false, g.edges[1]['directed'])
93
+ end
94
+
95
+ def test_edgearray_set_default_unexisting_property_before_push
96
+ g = Graph.new([], [{'node1'=>'foo', 'node2'=>'bar'}])
97
+ g.edges.set_default 'directed' => true
98
+ g.edges.push({'node1' => 'bar', 'node2'=>'foo'})
99
+
100
+ assert_equal(true, g.edges[0]['directed'])
101
+ assert_equal(true, g.edges[0]['directed'])
102
+ end
103
+
104
+ def test_edgearray_set_default_existing_property_before_push
105
+ g = Graph.new([],
106
+ [{'node1'=>'foo', 'node2'=>'bar', 'directed'=>true}])
107
+ g.edges.set_default 'node2' => 'foo'
108
+ g.edges.push({'node1' => 'bar', 'node2' => 'foo'})
109
+
110
+ assert_equal('foo', g.edges[0]['node2'])
111
+ assert_equal('foo', g.edges[0]['node2'])
112
+ end
113
+
114
+ # == Graph#& == #
115
+
116
+ def test_empty_graph_AND_empty_graph
117
+ g1 = Graph.new
118
+ g2 = Graph.new
119
+
120
+ assert_equal(g1, g1 & g2)
121
+ end
122
+
123
+ def test_one_node_graph_AND_empty_graph
124
+ g = Graph.new([{'label'=>'foo'}])
125
+ empty = Graph.new
126
+
127
+ assert_equal(empty, g & empty)
128
+ end
129
+
130
+ def test_empty_graph_AND_one_node_graph
131
+ g = Graph.new([{'label'=>'foo'}])
132
+ empty = Graph.new
133
+
134
+ assert_equal(empty, empty & g)
135
+ end
136
+
137
+ def test_sample_graph_AND_itself
138
+ g = @@sample_graph
139
+
140
+ assert_equal(g, g & g)
141
+ end
142
+
143
+ def test_one_node_graph_AND_one_other_node_graph
144
+ g = Graph.new([{'label'=>'foo'}])
145
+ h = Graph.new([{'label'=>'bar'}])
146
+ empty = Graph.new
147
+
148
+ assert_equal(empty, g & h)
149
+ end
150
+
151
+ def test_sample_graph_AND_no_graph
152
+ g = @@sample_graph
153
+
154
+ assert_equal(nil, g & 2)
155
+ assert_equal(nil, g & true)
156
+ assert_equal(nil, g & false)
157
+ assert_equal(nil, g & ['foo', 'bar'])
158
+ assert_equal(nil, g & {'foo'=>'bar'})
159
+ assert_equal(nil, g & 'foo')
160
+ end
161
+
162
+ # == Graph#write == #
163
+
164
+ def test_graph_write_no_ext
165
+ g = @@sample_graph
166
+ f = '/tmp/_graph_test'
167
+ g.write(f)
168
+ assert_equal(true, File.exists?(f))
169
+
170
+ dict = YAML.load(File.open(f))
171
+ assert_equal(g.nodes, dict['nodes'])
172
+ assert_equal(g.edges, dict['edges'])
173
+ end
174
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: graphs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: x86-linux
7
+ authors:
8
+ - Baptiste Fontaine
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-02 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Provide functions to (un)parse GDF files and generate graphs
15
+ email: batifon@yahoo.fr
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/graph.rb
21
+ - lib/graphs/gdf.rb
22
+ - tests/tests_gexf.rb
23
+ - tests/tests_graph.rb
24
+ - tests/tests_gdf.rb
25
+ homepage: https://github.com/bfontaine/Graph.rb
26
+ licenses:
27
+ - MIT
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 1.8.24
47
+ signing_key:
48
+ specification_version: 3
49
+ summary: Utilities to manipulate graph files
50
+ test_files:
51
+ - tests/tests_gexf.rb
52
+ - tests/tests_graph.rb
53
+ - tests/tests_gdf.rb