graphs 0.1.4-x86-linux → 0.1.5-x86-linux

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/lib/graph.rb CHANGED
@@ -8,7 +8,8 @@ require 'yaml'
8
8
  # @!attribute [rw] edges
9
9
  # @return [EdgeArray] array of current Graph's edges
10
10
  # @!attribute [rw] attrs
11
- # @return [Hash] attributes of the current Graph (e.g. author, description, …)
11
+ # @return [Hash] attributes of the current Graph (e.g. author, description, …).
12
+ # By default, the graph is directed, i.e. the :directed attribute is set to `true`.
12
13
  class Graph
13
14
 
14
15
  # Return a new Graph which is the intersection of every given graph.
@@ -46,11 +47,60 @@ class Graph
46
47
  perform_graphs_group_op(*graphs, &:^)
47
48
  end
48
49
 
49
- # An array of nodes, each node is an hash of label/value paires
50
+ # A node. This class is just a wrapper around a hash of
51
+ # attributes since in version <= 0.1.5 nodes were simple hashes
52
+ class Node
53
+
54
+ attr_accessor :attrs
55
+
56
+ def initialize(attrs=nil)
57
+ @attrs = attrs || {}
58
+ end
59
+
60
+ # compare two nodes
61
+ # @param other [Node]
62
+ def ==(other)
63
+ return false if !other.is_a?(Node)
64
+
65
+ @attrs == other.attrs
66
+ end
67
+
68
+ def method_missing(method, *args, &block)
69
+ @attrs.send(method, *args, &block)
70
+ end
71
+
72
+ end
73
+
74
+ # An edge. This class is just a wrapper around a hash of
75
+ # attributes since in version <= 0.1.5 edges were simple hashes
76
+ class Edge
77
+
78
+ attr_accessor :attrs
79
+
80
+ def initialize(attrs=nil)
81
+ @attrs = attrs || {}
82
+ end
83
+
84
+ # compare two edges
85
+ # @param other [Edge]
86
+ def ==(other)
87
+ return false if !other.is_a?(Edge)
88
+
89
+ @attrs == other.attrs
90
+ end
91
+
92
+ def method_missing(method, *args, &block)
93
+ @attrs.send(method, *args, &block)
94
+ end
95
+
96
+ end
97
+
98
+ # An array of Node objects
50
99
  class NodeArray < Array
51
100
 
52
- def initialize(*args)
53
- super(*args)
101
+ def initialize(li)
102
+ nodes = li.map { |n| n.is_a?(Node) ? n : Node.new(n) }
103
+ super(nodes)
54
104
  @defaults = {}
55
105
  end
56
106
 
@@ -64,19 +114,43 @@ class Graph
64
114
  end
65
115
 
66
116
  # Add the given node at the end of the list
67
- # @param o [Node]
68
- def push(o)
69
- if (!o.is_a?(Hash))
70
- raise TypeError.new "#{o.inspect} is not an Hash!"
117
+ # @param n [Node]
118
+ def push(n)
119
+ if (!n.is_a?(Hash) && !n.is_a?(Node))
120
+ raise TypeError.new "#{n.inspect} is not an Hash or a Node!"
71
121
  end
72
- o2 = o.clone
73
- o2.update(@defaults)
74
- super(o2)
122
+
123
+ super(n.clone.update(@defaults))
75
124
  end
76
125
  end
77
126
 
78
- # An array of edges, each edge is an hash of label/value paires
79
- class EdgeArray < NodeArray
127
+ # An array of Edge objects
128
+ class EdgeArray < Array
129
+ def initialize(li)
130
+ edges = li.map { |n| n.is_a?(Edge) ? n : Edge.new(n) }
131
+ super(edges)
132
+ @defaults = {}
133
+ end
134
+
135
+ # Set some default values for current elements.
136
+ # @note This method can be called multiple times.
137
+ # @example Set all edges's 'created-at' value to '2012-05-03'
138
+ # myEdgeList.set_default({'created-at'=>'2012-05-03'})
139
+ # @param dict [Hash]
140
+ def set_default(dict)
141
+ @defaults.update(dict)
142
+ self.map! { |e| e.update(@defaults) }
143
+ end
144
+
145
+ # Add the given edge at the end of the list
146
+ # @param e [Edge]
147
+ def push(e)
148
+ if (!e.is_a?(Hash) && !e.is_a?(Edge))
149
+ raise TypeError.new "#{e.inspect} is not an Hash or an Edge!"
150
+ end
151
+
152
+ super(e.clone.update(@defaults))
153
+ end
80
154
  end
81
155
 
82
156
  attr_accessor :nodes, :edges, :attrs
@@ -86,7 +160,7 @@ class Graph
86
160
  def initialize(nodes=nil, edges=nil)
87
161
  @nodes = NodeArray.new(nodes || [])
88
162
  @edges = EdgeArray.new(edges || [])
89
- @attrs = {}
163
+ @attrs = { :directed => true }
90
164
  end
91
165
 
92
166
  # Test if current graph has same nodes and edges as the other
@@ -148,6 +222,7 @@ class Graph
148
222
  # Perform an OR operation on the current Graph and the given one. Returns a
149
223
  # new graph which every node is in the current Graph and/or the other
150
224
  # (idem for edges).
225
+ # @param other [Graph]
151
226
  def |(other)
152
227
  if (!other.is_a?(Graph))
153
228
  return nil
@@ -178,6 +253,12 @@ class Graph
178
253
  self - other
179
254
  end
180
255
 
256
+ # Return true if the Graph is directed.
257
+ # @see Graph.attrs
258
+ def directed?()
259
+ self.attrs[:directed]
260
+ end
261
+
181
262
  # Clone the current graph. All nodes and edges are also cloned. A new Graph
182
263
  # is returned.
183
264
  def clone()
@@ -220,6 +301,111 @@ class Graph
220
301
 
221
302
  end
222
303
 
304
+ # Return the degree of the node n in the current graph, i.e. the number
305
+ # of edges which are connected to this node. Note that this is useful
306
+ # only for a undirected graph, for a directed one, you should use
307
+ # Graph#in_degree_of and/or Graph#out_degree_of.
308
+ #
309
+ # Edges must have the 'node1' and 'node2' attributes, which must contain
310
+ # the 'label' attributes of nodes.
311
+ #
312
+ # @param n [Node,String] A node or a label of one
313
+ # @see Graph#in_degree_of
314
+ # @see Graph#out_degree_of
315
+ def degree_of(n)
316
+ label = Graph::get_label_from_node(n)
317
+
318
+ degree = 0
319
+
320
+ # This is more efficient than in_degree_of(n)+out_degree_of(n)
321
+ # since it goes only once through the edges array
322
+ self.edges.each do |e|
323
+ degree += 1 if (e['node1'] || e[:node1]).to_s == label
324
+ degree += 1 if (e['node2'] || e[:node2]).to_s == label
325
+ end
326
+
327
+ degree
328
+ end
329
+
330
+ # Return the “in degree” of the node n in the current graph, i.e. the number
331
+ # of edges which are directed to this node. Note that the graph must be oriented.
332
+ #
333
+ # Edges must have the 'node1' and 'node2' attributes, which must contain
334
+ # the 'label' attributes of nodes.
335
+ #
336
+ # @param n [Node,String] A node or a label of one
337
+ # @see Graph#degree_of
338
+ # @see Graph#out_degree_of
339
+ def in_degree_of(n)
340
+ label = Graph::get_label_from_node(n)
341
+
342
+ degree = 0
343
+
344
+ self.edges.each do |e|
345
+ degree += 1 if (e['node2'] || e[:node2]).to_s == label
346
+ end
347
+
348
+ degree
349
+ end
350
+
351
+ # Return the “out degree” of the node n in the current graph, i.e. the number
352
+ # of edges which are directed from this node. Note that the graph must be oriented.
353
+ #
354
+ # Edges must have the 'node1' and 'node2' attributes, which must contain
355
+ # the 'label' attributes of nodes.
356
+ #
357
+ # @param n [Node,String] A node or a label of one
358
+ # @see Graph#degree_of
359
+ # @see Graph#out_degree_of
360
+ def out_degree_of(n)
361
+ label = Graph::get_label_from_node(n)
362
+
363
+ degree = 0
364
+
365
+ self.edges.each do |e|
366
+ degree += 1 if (e['node1'] || e[:node1]).to_s == label
367
+ end
368
+
369
+ degree
370
+ end
371
+
372
+ # Return the “in degree” of the node n in the current graph, i.e. the number
373
+ # of edges which are directed to this node. Note that the graph must be oriented.
374
+ #
375
+ # Edges must have the 'node1' and 'node2' attributes, which must contain
376
+ # the 'label' attributes of nodes.
377
+ #
378
+ # @param n [Node,String] A node or a label of one
379
+ # @see Graph#degree_of
380
+ # @see Graph#out_degree_of
381
+ def in_degree_of(n)
382
+ label = Graph::get_label_from_node(n)
383
+
384
+ degree = 0
385
+
386
+ # This is more efficient than in_degree_of(n)+out_degree_of(n)
387
+ # since it goes only once through the edges array
388
+ self.edges.each do |e|
389
+ degree += 1 if (e['node2'] || e[:node2]).to_s == label
390
+ end
391
+
392
+ degree
393
+ end
394
+
395
+
396
+ # return the label of a node. Raise a TypeError exception if the argument
397
+ # is not a Node nor a String object.
398
+ # @param n [Node,String] A node with a 'label' or :label attribute, or a string
399
+ def Graph::get_label_from_node(n)
400
+ label = n.is_a?(Node) \
401
+ ? (n['label'] || n[:label]).to_s \
402
+ : n.is_a?(String) ? n : nil
403
+
404
+ raise TypeError.new("#{n.inspect} must be a Node or String object.") if label.nil?
405
+
406
+ label
407
+ end
408
+
223
409
  # return the provided set of graphs, from which every node/edge label which
224
410
  # is not in all graphs has been removed. So every returned graph has same
225
411
  # node/edge labels than each other
@@ -275,16 +461,17 @@ class Graph
275
461
  # from the arguments
276
462
  if graphs[-1].is_a?(Hash)
277
463
  return nil if graphs.length == 1
278
- opts.update(graphs.pop)
464
+
465
+ opts = graphs.pop
279
466
  end
280
467
 
281
468
  # return nil if one argument is not a graph
282
- graphs.each {|g|
283
- return nil if (!g.is_a?(Graph))
284
- }
469
+ graphs.each do |g|
470
+ return nil if !g.is_a?(Graph)
471
+ end
285
472
 
286
473
  # if :same_fields option is set, call `keep_only_same_fields` function
287
- *graphs = keep_only_same_fields(*graphs) if opts[:same_fields]
474
+ graphs = keep_only_same_fields(*graphs) if opts[:same_fields]
288
475
 
289
476
  # perform an and operation on all graph list
290
477
  graphs.inject(&block)
@@ -1,8 +1,6 @@
1
1
  #! /usr/bin/ruby1.9.1
2
2
 
3
- require 'graph'
4
- require 'graphs/gdf'
5
- require 'test/unit'
3
+ require_relative '../lib/graphs/gdf'
6
4
 
7
5
  module Utils
8
6
  def self.get_sample_graph
@@ -1,5 +1,4 @@
1
1
  #! /usr/bin/ruby1.9.1
2
2
  # -*- coding: UTF-8 -*-
3
3
 
4
- require 'test/unit'
5
4
  # require 'graphs/gexf'
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'test/unit'
5
5
  require 'yaml'
6
- require 'graph'
6
+ require_relative '../lib/graph'
7
7
 
8
8
  class Graph_test < Test::Unit::TestCase
9
9
 
@@ -40,9 +40,10 @@ class Graph_test < Test::Unit::TestCase
40
40
 
41
41
  # == Graph#attrs == #
42
42
 
43
- def test_graph_attrs
43
+ def test_empty_graph_attrs
44
44
  g = @@empty
45
- assert_equal({}, g.attrs)
45
+ assert_equal({:directed => true}, g.attrs)
46
+ assert_equal(true, g.directed?)
46
47
 
47
48
  g.attrs['mode'] = 'static'
48
49
  g.attrs['defaultedgetype'] = 'directed'
@@ -181,6 +182,9 @@ class Graph_test < Test::Unit::TestCase
181
182
 
182
183
  assert_equal(21, g.nodes[0]['age'])
183
184
  assert_equal(21, g.nodes[1]['age'])
185
+
186
+ assert_equal(21, g.nodes[0]['age'])
187
+ assert_equal(21, g.nodes[1]['age'])
184
188
  end
185
189
 
186
190
  def test_nodearray_set_default_existing_property
@@ -467,8 +471,8 @@ class Graph_test < Test::Unit::TestCase
467
471
  def test_union_sample_graph_and_itself
468
472
  g = @@sample_graph
469
473
 
470
- assert_equal(g, Graph::intersection(g, g))
471
- assert_equal(g, Graph::intersection(g, g, g, g))
474
+ assert_equal(g, Graph::union(g, g))
475
+ assert_equal(g, Graph::union(g, g, g, g))
472
476
  end
473
477
 
474
478
  def test_union_sample_graph_and_other_sample_graph
@@ -0,0 +1,84 @@
1
+ #! /usr/bin/ruby1.9.1
2
+ # -*- coding: UTF-8 -*-
3
+
4
+ class Node_test < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @@empty = Graph::Node.new
8
+ @@alice = Graph::Node.new('label' => 'Alice')
9
+
10
+ # Alice ----> Bob
11
+ # ↑ ↑
12
+ # | |
13
+ # Oscar -------'
14
+ @@sample_graph = Graph.new(
15
+ [
16
+ { 'label' => 'Alice' },
17
+ { 'label' => 'Bob' },
18
+ { 'label' => 'Oscar' }
19
+ ],
20
+ [
21
+ { 'node1' => 'Alice', 'node2' => 'Bob' },
22
+ { 'node1' => 'Oscar', 'node2' => 'Alice'},
23
+ { 'node1' => 'Oscar', 'node2' => 'Bob'}
24
+ ]
25
+ )
26
+
27
+ end
28
+
29
+ def test_create_graph_with_node_objects
30
+ g1 = Graph.new([
31
+ Graph::Node.new('label' => 'Foo')
32
+ ])
33
+
34
+ g2 = Graph.new([
35
+ { 'label' => 'Foo' }
36
+ ])
37
+
38
+ assert_equal(g2, g1)
39
+ end
40
+
41
+ def test_node_attrs
42
+ a = @@alice
43
+
44
+ a['foo'] = 'bar'
45
+
46
+ assert_equal('Alice', @@alice['label'])
47
+ assert_equal('bar', @@alice['foo'])
48
+ assert_equal(nil, @@alice['fooo'])
49
+ end
50
+
51
+ def test_node_degree_by_label
52
+ assert_equal(2, @@sample_graph.degree_of('Alice'))
53
+ assert_equal(2, @@sample_graph.degree_of('Oscar'))
54
+ assert_equal(2, @@sample_graph.degree_of('Bob'))
55
+ assert_equal(0, @@sample_graph.degree_of('not found'))
56
+ end
57
+
58
+ def test_node_degree_by_object
59
+ assert_equal(2, @@sample_graph.degree_of(@@alice))
60
+ end
61
+
62
+ def test_node_in_degree_by_label
63
+ assert_equal(1, @@sample_graph.in_degree_of('Alice'))
64
+ assert_equal(2, @@sample_graph.in_degree_of('Bob'))
65
+ assert_equal(0, @@sample_graph.in_degree_of('Oscar'))
66
+ assert_equal(0, @@sample_graph.in_degree_of('not found'))
67
+ end
68
+
69
+ def test_node_in_degree_by_object
70
+ assert_equal(1, @@sample_graph.in_degree_of(@@alice))
71
+ end
72
+
73
+ def test_node_out_degree_by_label
74
+ assert_equal(1, @@sample_graph.out_degree_of('Alice'))
75
+ assert_equal(0, @@sample_graph.out_degree_of('Bob'))
76
+ assert_equal(2, @@sample_graph.out_degree_of('Oscar'))
77
+ assert_equal(0, @@sample_graph.out_degree_of('not found'))
78
+ end
79
+
80
+ def test_node_out_degree_by_object
81
+ assert_equal(1, @@sample_graph.out_degree_of(@@alice))
82
+ end
83
+
84
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  prerelease:
6
6
  platform: x86-linux
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-06 00:00:00.000000000 Z
12
+ date: 2012-10-23 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Provide functions to (un)parse GDF files and generate graphs
15
15
  email: batifon@yahoo.fr
@@ -19,9 +19,10 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - lib/graph.rb
21
21
  - lib/graphs/gdf.rb
22
- - tests/tests_gexf.rb
23
- - tests/tests_graph.rb
24
- - tests/tests_gdf.rb
22
+ - tests/graph_tests.rb
23
+ - tests/gdf_tests.rb
24
+ - tests/node_tests.rb
25
+ - tests/gexf_tests.rb
25
26
  homepage: https://github.com/bfontaine/Graphs.rb
26
27
  licenses:
27
28
  - MIT
@@ -48,6 +49,7 @@ signing_key:
48
49
  specification_version: 3
49
50
  summary: Utilities to manipulate graph files
50
51
  test_files:
51
- - tests/tests_gexf.rb
52
- - tests/tests_graph.rb
53
- - tests/tests_gdf.rb
52
+ - tests/graph_tests.rb
53
+ - tests/gdf_tests.rb
54
+ - tests/node_tests.rb
55
+ - tests/gexf_tests.rb