rbgraph 0.0.15 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49534fbbe6268b998015e30ff1c3b6cc45741461
4
- data.tar.gz: afa679d7e2217b464feba66f74cb9f5c1596ca58
3
+ metadata.gz: 6802faf7d27b90722ed3e60db98fb448c2bcaf4e
4
+ data.tar.gz: dbbc67f346e322fba63e9400d3f45fcab0b2e9c8
5
5
  SHA512:
6
- metadata.gz: 7df14ad8a194fcf3afaea356d8cd7bb1bfba38759878fbef1fbef24c5e6806e674fcea9e3622b7cf0c5ebb59f7e44efb539054f08348178d1116f465403fca28
7
- data.tar.gz: 32e8c30c071a98c4103629f92976b911345d4d13f67bdaed0f202858beff05e67f82bd9bf4ca6f60e59b7f7398daf64cb7c2374e6958bb74a5efac61c83f8486
6
+ metadata.gz: a5ad1891b6dd29d0dcbcac9c66769009a7fb0e55e4abbf469482efe6da486616b40613a779cd990c8ee07ea5d7d14786e390dc07a5e514fd338f0e5624861fdb
7
+ data.tar.gz: 233f7cf3a5e6bc70b738a91f3de6d7c0c06ce22c904fda430315bd26953d81c0ad57318162c2cb41771770b68ee4782f0c0bb34174e5a5677e6c9214628a4697
data/lib/rbgraph/edge.rb CHANGED
@@ -7,17 +7,18 @@ module Rbgraph
7
7
  attr_accessor :node1
8
8
  attr_accessor :node2
9
9
  attr_accessor :weight
10
- attr_accessor :directed
11
- attr_accessor :attributes
12
-
13
- def initialize(node1, node2, attributes = {})
14
- self.node1 = node1
15
- self.node2 = node2
16
- self.directed = !!attributes.delete(:directed)
17
- interpolated_node_ids = directed ? [node1.id, node2.id] : [node1.id, node2.id].sort
18
- self.id = attributes.delete(:id) || ("%s=#{attributes[:kind]}=%s" % interpolated_node_ids)
19
- self.weight = attributes.delete(:weight) || 1
20
- self.attributes = attributes
10
+ attr_accessor :kind
11
+ attr_accessor :data
12
+
13
+ def initialize(graph, node1, node2, weight, kind, data = {})
14
+ self.graph = graph
15
+ self.node1 = node1
16
+ self.node2 = node2
17
+ self.weight = weight.nil? ? 1 : weight.to_i
18
+ self.kind = kind
19
+ nodes_ids = graph.directed? ? [node1.id, node2.id] : [node1.id, node2.id].sort
20
+ self.id = "%s=#{kind}=%s" % nodes_ids
21
+ self.data = data
21
22
  end
22
23
 
23
24
  def ==(node)
@@ -26,7 +27,11 @@ module Rbgraph
26
27
  alias_method :==, :eql?
27
28
 
28
29
  def hash
29
- id
30
+ id.hash
31
+ end
32
+
33
+ def attributes
34
+ {id: id, weight: weight, kind: kind, data: data}
30
35
  end
31
36
 
32
37
  def has_node?(node)
@@ -38,45 +43,33 @@ module Rbgraph
38
43
  node == node1 ? node2 : node1
39
44
  end
40
45
 
41
- def merge(edge)
42
- raise "Cannot merge directed and undirected edge!" if directed ^ edge.directed # XOR
46
+ def merge!(edge, &block)
43
47
  self.weight += edge.weight unless edge.weight.nil?
44
- attributes.merge!(edge.attributes)
48
+ raise "Cannot merging edges of different kind!" if kind != edge.kind
49
+ data.merge!(edge.data, &block)
50
+ graph.remove_edge!(edge)
45
51
  self
46
52
  end
47
53
 
48
54
  def out_for?(node)
49
- if directed
50
- node == node1
51
- else
52
- has_node?(node)
53
- end
55
+ graph.directed? ? node == node1 : has_node?(node)
54
56
  end
55
57
 
56
58
  def in_for?(node)
57
- if directed
58
- node == node2
59
- else
60
- has_node?(node)
61
- end
62
- end
63
-
64
- def original_attributes
65
- attributes.merge({directed: directed, weight: weight})
59
+ graph.directed? ? node == node2 : has_node?(node)
66
60
  end
67
61
 
68
62
  def to_s
69
- "[#{node1.id} #{directed ?
70
- "=(#{attributes[:kind]}(#{weight}))=>>" :
71
- "==(#{attributes[:kind]}(#{weight}))=="} #{node2.id}]"
63
+ descr = graph.directed? ? ["=", "=>>"] : ["==", "=="]
64
+ "[#{node1.id} %s(#{attributes[:kind]}(#{weight}))%s #{node2.id}]" % descr
72
65
  end
73
66
 
74
67
  def inspect
75
- "<Rbgraph::Edge:##{id} #{to_s} #{attributes.inspect}>"
68
+ "<Rbgraph::Edge:##{id} #{attributes.inspect}>"
76
69
  end
77
70
 
78
- def to_json
79
- {id: id}.merge(original_attributes).to_json
71
+ def to_json(options = {})
72
+ attributes.reject { |k, v| v.nil? || (v.respond_to?(:empty?) && v.empty?) }.to_json(options)
80
73
  end
81
74
 
82
75
  end
data/lib/rbgraph/graph.rb CHANGED
@@ -14,29 +14,34 @@ module Rbgraph
14
14
  nodes.values.length
15
15
  end
16
16
 
17
- def add_node!(node)
18
- node = node.is_a?(Node) ? node : Node.new(node)
19
- node.graph = self
20
- if nodes[node.id].nil?
21
- nodes[node.id] = node
17
+ def directed?
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def add_node!(node_id, node_data, &block)
22
+ if nodes[node_id].nil?
23
+ nodes[node_id] = Node.new(self, node_id, node_data)
22
24
  else
23
- nodes[node.id].merge(node)
25
+ nodes[node_id] = yield(self, nodes[node.id], node_data) if block_given?
24
26
  end
25
- nodes[node.id]
27
+ nodes[node_id]
26
28
  end
27
29
 
28
- def add_edge!(node1, node2, edge_attributes = {})
29
- node1 = add_node!(node1)
30
- node2 = add_node!(node2)
31
- edge = Edge.new(node1, node2, edge_attributes)
32
- edge.graph = self
33
- edge = if edges[edge.id].nil?
34
- edges[edge.id] = edge
30
+ def add_edge!(node1, node2, weight = 1, kind = nil, edge_data = {}, &block)
31
+ node1 = add_node!(node1[:id], node1[:data])
32
+ node2 = add_node!(node2[:id], node2[:data])
33
+ new_edge = Edge.new(self, node1, node2, weight, kind, edge_data)
34
+ if edges[new_edge.id].nil?
35
+ edges[new_edge.id] = new_edge
35
36
  else
36
- edges[edge.id].merge(edge)
37
+ if block_given?
38
+ edges[new_edge.id] = yield(self, edges[edge.id], new_edge)
39
+ else
40
+ edges[new_edge.id].weight += weight
41
+ end
37
42
  end
38
- connect_nodes(node1, node2, edge)
39
- edge
43
+ connect_nodes(node1, node2, edges[new_edge.id])
44
+ edges[new_edge.id]
40
45
  end
41
46
 
42
47
  def remove_node!(node)
@@ -56,25 +61,26 @@ module Rbgraph
56
61
  edges.delete(edge.id)
57
62
  end
58
63
 
59
- def merge_nodes!(node_ids, new_attrs = {})
60
- node_ids = node_ids.map { |node_id| nodes[node_id].nil? ? nil : node_id } .compact
64
+ def merge_nodes!(node_ids, new_node_id = nil, new_node_data = {}, merge_options = {}, &block)
65
+ node_ids = nodes.values_at(*node_ids).compact.map(&:id)
61
66
  return nil if node_ids.empty?
62
- new_id = new_attrs[:id]
63
- new_node = nil
64
- if new_id.nil?
65
- if nodes[new_id].nil?
66
- new_node = nodes[node_ids.shift]
67
+ if new_node_id.nil?
68
+ # If new_node_id is nil then select the first from the list as the surviving node.
69
+ new_node = nodes[node_ids.shift]
70
+ else
71
+ # Otherwise either check if a node with the given id exists, or create a new one.
72
+ if nodes[new_node_id].nil?
73
+ new_node = add_node!(new_node_id, new_node_data)
67
74
  else
68
- new_node = nodes[new_id]
69
- node_ids.delete(new_id)
75
+ new_node = nodes[new_node_id]
76
+ random_not_existent_id = nodes.keys.sort_by { |k| -k.to_s.length } .first.to_s + "_"
77
+ new_node.merge!(Node.new(self, 0, new_node_data))
78
+ node_ids.delete(new_node_id)
70
79
  end
71
- new_node.merge(Node.new({id: 0}.merge(new_attrs)))
72
- else
73
- new_node = add_node!(new_attrs)
74
80
  end
75
81
  node_ids.each do |node_id|
76
82
  node = nodes[node_id]
77
- new_node.absorb!(node)
83
+ new_node.merge!(node, merge_options, &block)
78
84
  end
79
85
  new_node
80
86
  end
@@ -84,7 +90,7 @@ module Rbgraph
84
90
  end
85
91
 
86
92
  def inspect
87
- edges.map(&:inspect)
93
+ edges.values.map(&:inspect)
88
94
  end
89
95
 
90
96
  end
@@ -2,8 +2,8 @@ module Rbgraph
2
2
 
3
3
  class DirectedGraph < Graph
4
4
 
5
- def add_edge!(node1, node2, edge_attributes = {})
6
- super(node1, node2, {directed: true}.merge(edge_attributes))
5
+ def directed?
6
+ true
7
7
  end
8
8
 
9
9
  def connect_nodes(node1, node2, edge)
@@ -2,8 +2,8 @@ module Rbgraph
2
2
 
3
3
  class UndirectedGraph < Graph
4
4
 
5
- def add_edge!(node1, node2, edge_attributes = {})
6
- super(node1, node2, {directed: false}.merge(edge_attributes))
5
+ def directed?
6
+ false
7
7
  end
8
8
 
9
9
  def connect_nodes(node1, node2, edge)
data/lib/rbgraph/node.rb CHANGED
@@ -4,16 +4,17 @@ module Rbgraph
4
4
 
5
5
  attr_accessor :id
6
6
  attr_accessor :graph
7
- attr_accessor :attributes
8
7
  attr_accessor :neighbors
9
8
  attr_accessor :edges
10
-
11
- def initialize(attributes = {})
12
- self.attributes = attributes
13
- raise "Node should have an id attribute!" if attributes[:id].nil?
14
- self.id = attributes.delete(:id)
15
- self.neighbors = {}
16
- self.edges = {}
9
+ attr_accessor :data
10
+
11
+ def initialize(graph, id, data = {})
12
+ raise "Node should have a non-nil id!" if id.nil?
13
+ self.graph = graph
14
+ self.id = id
15
+ self.neighbors = {}
16
+ self.edges = {}
17
+ self.data = data || {}
17
18
  end
18
19
 
19
20
  def ==(node)
@@ -22,12 +23,15 @@ module Rbgraph
22
23
  alias_method :==, :eql?
23
24
 
24
25
  def hash
25
- id
26
+ id.hash
26
27
  end
27
28
 
28
- def merge(node)
29
- attributes.merge!(node.attributes.reject { |k, v| k == :id })
30
- self
29
+ def attributes
30
+ {id: id, data: data}
31
+ end
32
+
33
+ def [](key)
34
+ attributes.fetch(key.to_sym)
31
35
  end
32
36
 
33
37
  def connect_to(node, edge)
@@ -38,18 +42,27 @@ module Rbgraph
38
42
  self
39
43
  end
40
44
 
41
- def absorb!(node)
42
- node.edges.values.each do |edge|
43
- other_node = edge.other_node(node)
44
- if edge.out_for?(node)
45
- graph.add_edge!(self, other_node, edge.original_attributes) unless other_node == self
46
- elsif edge.in_for?(node)
47
- graph.add_edge!(other_node, self, edge.original_attributes) unless other_node == self
45
+ def merge!(node, options = {}, &block)
46
+ node.edges.values.group_by(&:kind).each do |kind, edges|
47
+ edges.each do |edge|
48
+ other_node = edge.other_node(node)
49
+ edge_kind = edge.kind || options[:edge_kind]
50
+ unless other_node == self
51
+ if edge.out_for?(node)
52
+ graph.add_edge!(self, other_node, edge.weight, edge_kind, edge.data, &block)
53
+ elsif edge.in_for?(node)
54
+ graph.add_edge!(other_node, self, edge.weight, edge_kind, edge.data, &block)
55
+ end
56
+ end
48
57
  end
49
58
  end
50
59
  graph.remove_node!(node)
51
60
  end
52
61
 
62
+ def merge_data!(node)
63
+ data.merge!(node.data)
64
+ end
65
+
53
66
  def outgoing_edges
54
67
  edges.select { |eid, edge| edge.out_for?(self) }
55
68
  end
@@ -67,11 +80,11 @@ module Rbgraph
67
80
  end
68
81
 
69
82
  def inspect
70
- "<Rbgraph::Node:##{id} #{attributes.inspect}>"
83
+ "<Rbgraph::Node:##{id} #{data.inspect}>"
71
84
  end
72
85
 
73
- def to_json
74
- {id: id}.merge(attributes).to_json
86
+ def to_json(options = {})
87
+ attributes.to_json(options)
75
88
  end
76
89
 
77
90
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbgraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Lamprianidis