rbgraph 0.0.15 → 0.1.0

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.
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