Skip to content

Commit

Permalink
Added Graph#get_neighbours
Browse files Browse the repository at this point in the history
+ Added Graph#get_node
+ (Edge|Node).update now returns an object of the same class
+ Added Edge|Node support for x.foo aliased to x['foo'] or x[:foo]
+ tests added.
  • Loading branch information
bfontaine committed Feb 12, 2013
1 parent 960a447 commit 10c2810
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 7 deletions.
92 changes: 85 additions & 7 deletions lib/graph.rb
Expand Up @@ -65,7 +65,15 @@ def ==(other)
@attrs == other.attrs
end

def update(h)
Node.new super(h)
end

def method_missing(method, *args, &block)

return @attrs[method.to_sym] if @attrs.has_key? method.to_sym
return @attrs[method.to_s] if @attrs.has_key? method.to_s

@attrs.send(method, *args, &block)
end

Expand All @@ -89,7 +97,15 @@ def ==(other)
@attrs == other.attrs
end

def update(h)
Edge.new super(h)
end

def method_missing(method, *args, &block)

return @attrs[method.to_sym] if @attrs.has_key? method.to_sym
return @attrs[method.to_s] if @attrs.has_key? method.to_s

@attrs.send(method, *args, &block)
end

Expand Down Expand Up @@ -117,11 +133,14 @@ def set_default(dict)
# @param n [Node]
def push(n)
if (!n.is_a?(Hash) && !n.is_a?(Node))
raise TypeError.new "#{n.inspect} is not an Hash or a Node!"
raise TypeError.new "#{n.inspect} is not an Hash nor a Node!"
end

n = Node.new(n) if (n.is_a?(Hash))

super(n.clone.update(@defaults))
end

end

# An array of Edge objects
Expand All @@ -146,11 +165,14 @@ def set_default(dict)
# @param e [Edge]
def push(e)
if (!e.is_a?(Hash) && !e.is_a?(Edge))
raise TypeError.new "#{e.inspect} is not an Hash or an Edge!"
raise TypeError.new "#{e.inspect} is not an Hash nor an Edge!"
end

e = Edge.new(e) if (e.is_a?(Hash))

super(e.clone.update(@defaults))
end

end

attr_accessor :nodes, :edges, :attrs
Expand Down Expand Up @@ -313,7 +335,7 @@ def write(filename, opts=nil)
# @see Graph#in_degree_of
# @see Graph#out_degree_of
def degree_of(n)
label = Graph::get_label_from_node(n)
label = Graph::get_label(n)

degree = 0

Expand All @@ -337,7 +359,7 @@ def degree_of(n)
# @see Graph#degree_of
# @see Graph#out_degree_of
def in_degree_of(n)
label = Graph::get_label_from_node(n)
label = Graph::get_label(n)

degree = 0

Expand All @@ -358,7 +380,7 @@ def in_degree_of(n)
# @see Graph#degree_of
# @see Graph#out_degree_of
def out_degree_of(n)
label = Graph::get_label_from_node(n)
label = Graph::get_label(n)

degree = 0

Expand All @@ -369,12 +391,68 @@ def out_degree_of(n)
degree
end

# return the first node which mach the given label in the current graph
# @param label [String] A node's label
def get_node(label)

label = Graph::get_label(label)

self.nodes.find { |n| n.label == label }

end

# return an array of the neighbours of a node in the current graph.
# @param n [Node,String] A node with a 'label' or :label attribute, or a string
def get_neighbours(n)

label = Graph::get_label(n)
neighbours = NodeArray.new []

self.edges.each do |e|

begin

l1 = e.node1
l2 = e.node2

rescue NoMethodError; next; end

if l2 && l1 == label

n2 = self.get_node l2

unless neighbours.include?(l2)

neighbours.push(n2)

end

end

if l1 && l2 == label && self.directed?

n1 = self.get_node l1

unless neighbours.include?(n1)

neighbours.push(n1)

end

end

end

neighbours

end

# return the label of a node. Raise a TypeError exception if the argument
# is not a Node nor a String object.
# @param n [Node,String] A node with a 'label' or :label attribute, or a string
def Graph::get_label_from_node(n)
def Graph::get_label(n)
label = n.is_a?(Node) \
? (n['label'] || n[:label]).to_s \
? n.label.to_s \
: n.is_a?(String) ? n : nil

raise TypeError.new("#{n.inspect} must be a Node or String object.") if label.nil?
Expand Down
46 changes: 46 additions & 0 deletions tests/edge_tests.rb
@@ -0,0 +1,46 @@
#! /usr/bin/ruby1.9.1
# -*- coding: UTF-8 -*-

class Edge_test < Test::Unit::TestCase

def setup
@@empty = Graph::Node.new
@@alice = Graph::Node.new('label' => 'Alice')

# Alice ----> Bob
# ↑ ↑
# | |
# Oscar -------'
@@sample_graph = Graph.new(
[
{ 'label' => 'Alice' },
{ 'label' => 'Bob' },
{ 'label' => 'Oscar' }
],
[
{ 'node1' => 'Alice', 'node2' => 'Bob' },
{ :node1 => 'Oscar', 'node2' => 'Alice'},
{ 'node1' => 'Oscar', :node2 => 'Bob'}
]
)

end

def test_edge_node1_attr
assert_equal('Alice', @@sample_graph.edges[0].node1)
assert_equal('Oscar', @@sample_graph.edges[1].node1)
end

def test_edge_node2_attr
assert_equal('Alice', @@sample_graph.edges[1].node2)
assert_equal('Bob', @@sample_graph.edges[2].node2)
end

def test_edge_update

e = Graph::Edge.new

assert_equal(true, e.update({}).is_a?(Graph::Edge))
end

end
47 changes: 47 additions & 0 deletions tests/graph_tests.rb
Expand Up @@ -551,4 +551,51 @@ def test_graph_write_unknow_ext
end
assert_equal(false, File.exists?(f))
end

# == Graph#get_node == #

def test_graph_get_node_unexisting_label

n = @@sample_graph.get_node 'foobar'

assert_equal(nil, n)
end

def test_graph_get_node_existing_label

g = @@sample_graph;

n = g.get_node 'foo'

assert_equal(g.nodes[0], n)
end

# == Graph#get_neighbours == #

def test_graph_get_neighbours_unexisting_node_label

n = @@sample_graph.get_neighbours 'moo'

assert_equal([], n)

end

def test_graph_get_neighbours_unexisting_node_object

n = @@sample_graph.get_neighbours Graph::Node.new( :label => 'moo' )

assert_equal([], n)

end

def test_graph_get_neighbours

g = @@sample_graph

n = g.get_neighbours 'foo'

assert_equal([ 'bar', 'chuck' ], n.map { |m| m.label })

end

end
11 changes: 11 additions & 0 deletions tests/node_tests.rb
Expand Up @@ -81,4 +81,15 @@ def test_node_out_degree_by_object
assert_equal(1, @@sample_graph.out_degree_of(@@alice))
end

def test_node_label_attr
assert_equal('Alice', @@alice.label)
end

def test_node_update

n = Graph::Node.new

assert_equal(true, n.update({}).is_a?(Graph::Node))
end

end

0 comments on commit 10c2810

Please sign in to comment.