diaspora-cluster-creator 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -2
- data/Guardfile +1 -2
- data/README.md +2 -0
- data/TODO.todo +2 -0
- data/bin/diaspora-cluster +11 -8
- data/diaspora-cluster-creator.gemspec +2 -0
- data/features/cluster.feature +1 -1
- data/features/command_line.feature +165 -0
- data/features/node.feature +13 -0
- data/features/step_definitions/cluster_steps.rb +3 -3
- data/features/step_definitions/command_line_steps.rb +7 -0
- data/features/step_definitions/node_steps.rb +16 -0
- data/features/support/aruba.rb +1 -0
- data/features/support/world.rb +4 -8
- data/lib/diaspora-cluster-creator.rb +12 -9
- data/lib/diaspora-cluster-creator/attribute.rb +29 -0
- data/lib/diaspora-cluster-creator/attribute_collection_factory.rb +29 -0
- data/lib/diaspora-cluster-creator/cluster.rb +31 -18
- data/lib/diaspora-cluster-creator/edge_drawer.rb +41 -0
- data/lib/diaspora-cluster-creator/guarantor.rb +21 -0
- data/lib/diaspora-cluster-creator/node.rb +71 -0
- data/lib/diaspora-cluster-creator/node_attribute.rb +41 -0
- data/lib/diaspora-cluster-creator/node_collection_factory.rb +30 -0
- data/lib/diaspora-cluster-creator/template.rb +23 -16
- data/lib/diaspora-cluster-creator/version.rb +1 -1
- data/spec/diaspora-cluster-creator/attribute_collection_factory_spec.rb +31 -0
- data/spec/diaspora-cluster-creator/attribute_spec.rb +69 -0
- data/spec/diaspora-cluster-creator/cluster_spec.rb +66 -15
- data/spec/diaspora-cluster-creator/edge_drawer_spec.rb +21 -0
- data/spec/diaspora-cluster-creator/guarantor_spec.rb +54 -0
- data/spec/diaspora-cluster-creator/node_attribute_spec.rb +36 -0
- data/spec/diaspora-cluster-creator/node_collection_factory_spec.rb +27 -0
- data/spec/diaspora-cluster-creator/node_spec.rb +65 -0
- data/spec/diaspora-cluster-creator/template_integration_spec.rb +9 -10
- data/spec/diaspora-cluster-creator/template_spec.rb +9 -2
- metadata +78 -34
- data/features/star_system.feature +0 -13
- data/features/step_definitions/star_system_steps.rb +0 -16
- data/lib/diaspora-cluster-creator/graph.rb +0 -58
- data/lib/diaspora-cluster-creator/star_system.rb +0 -80
- data/spec/diaspora-cluster-creator/graph_spec.rb +0 -34
- data/spec/diaspora-cluster-creator/star_system_spec.rb +0 -103
@@ -0,0 +1,41 @@
|
|
1
|
+
module Diaspora
|
2
|
+
module Cluster
|
3
|
+
module Creator
|
4
|
+
class EdgeDrawer
|
5
|
+
extend DependencyInjector
|
6
|
+
def_injector(:dice) { FateDice.new }
|
7
|
+
attr_reader :cluster
|
8
|
+
def initialize(cluster)
|
9
|
+
@cluster = cluster
|
10
|
+
end
|
11
|
+
|
12
|
+
def draw(nodes)
|
13
|
+
return @edges if @edges
|
14
|
+
nodes.each_with_index do |node, i|
|
15
|
+
result = dice.roll
|
16
|
+
if result < 0
|
17
|
+
connect(node, nodes[i+1])
|
18
|
+
elsif result == 0
|
19
|
+
connect(node, nodes[i+1], nodes[i+2])
|
20
|
+
elsif result > 0
|
21
|
+
connect(node, nodes[i+1], nodes[i+2], nodes[i+3])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
@edges
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def connect(node, *others)
|
30
|
+
@edges ||= []
|
31
|
+
others.flatten.compact.each do |other|
|
32
|
+
@edges << [node,other]
|
33
|
+
end
|
34
|
+
@edges
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Diaspora
|
2
|
+
module Cluster
|
3
|
+
module Creator
|
4
|
+
class Guarantor
|
5
|
+
attr_reader :attribute_name, :minimum_value
|
6
|
+
def initialize(attribute_name = :technology, minimum_value = 2)
|
7
|
+
@attribute_name, @minimum_value = attribute_name, minimum_value
|
8
|
+
end
|
9
|
+
def guarantee!(nodes)
|
10
|
+
return nodes if nodes.detect {|ss| ss.send(attribute_name) >= minimum_value }
|
11
|
+
working = nodes.sort
|
12
|
+
working.first.send("#{attribute_name}=", minimum_value)
|
13
|
+
working.last.send("#{attribute_name}=", minimum_value)
|
14
|
+
nodes
|
15
|
+
rescue NoMethodError => e
|
16
|
+
nodes
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'dependency_injector'
|
2
|
+
require 'set'
|
3
|
+
require_relative 'fate_dice'
|
4
|
+
require_relative 'node_attribute'
|
5
|
+
|
6
|
+
module Diaspora
|
7
|
+
module Cluster
|
8
|
+
module Creator
|
9
|
+
class Node
|
10
|
+
extend DependencyInjector
|
11
|
+
def_injector(:dice) { FateDice.new }
|
12
|
+
def_injector(:attribute_builder) { NodeAttribute.public_method(:new) }
|
13
|
+
|
14
|
+
attr_reader :cluster, :name, :attributes
|
15
|
+
def initialize(cluster, name_with_attribute_values)
|
16
|
+
@cluster = cluster
|
17
|
+
@attributes = []
|
18
|
+
yield(self) if block_given?
|
19
|
+
cluster.attributes.each do |attribute|
|
20
|
+
@attributes << attribute_builder.call(self,attribute)
|
21
|
+
end
|
22
|
+
set_name_and_attribute_values(name_with_attribute_values.to_s)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(method_name, *args, &block)
|
26
|
+
if attributes && attribute = attributes.detect {|a| a.to_sym == method_name.to_sym }
|
27
|
+
attribute.value
|
28
|
+
elsif attributes && attribute = attributes.detect {|a| "#{a.to_sym}=".to_sym == method_name.to_sym }
|
29
|
+
attribute.value = args.first
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
include Comparable
|
36
|
+
def <=>(other)
|
37
|
+
to_i <=> other.to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_i
|
41
|
+
attributes.inject(0) {|m,v| m += v.to_i}
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
name.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def label
|
49
|
+
attributes.inject("#{name}\n") {|m,attrib| m << "#{attrib.label} "}.strip
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
def set_name_and_attribute_values(name_with_attribtes)
|
54
|
+
/^(?<name>[^(?:\[|\{)]*)(?:(?:\[|\{)(?<encoded_attributes>[^(?:\]|\})]*)(?:\]|\}))?$/ =~ name_with_attribtes
|
55
|
+
@name = name.strip
|
56
|
+
extract_encoded_attributes(encoded_attributes)
|
57
|
+
end
|
58
|
+
def extract_encoded_attributes(encoded_attributes)
|
59
|
+
if encoded_attributes
|
60
|
+
encoded_attributes.split(/ +/).collect(&:strip).each do |option|
|
61
|
+
/(?<attribute_prefix>\w) *(?<attribute_value>-?\d)/ =~ option
|
62
|
+
if attribute = attributes.detect {|attrib| attrib.prefix =~ /^#{attribute_prefix}$/i}
|
63
|
+
attribute.value = attribute_value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'dependency_injector'
|
3
|
+
require_relative 'fate_dice'
|
4
|
+
require_relative 'attribute'
|
5
|
+
|
6
|
+
module Diaspora
|
7
|
+
module Cluster
|
8
|
+
module Creator
|
9
|
+
class NodeAttribute < DelegateClass(Attribute)
|
10
|
+
extend DependencyInjector
|
11
|
+
def_injector(:dice) { FateDice.new }
|
12
|
+
|
13
|
+
attr_reader :node
|
14
|
+
def initialize(node, attribute)
|
15
|
+
@node = node
|
16
|
+
super(attribute)
|
17
|
+
end
|
18
|
+
|
19
|
+
def value
|
20
|
+
@value ||= dice.roll
|
21
|
+
end
|
22
|
+
|
23
|
+
def value=(new_value)
|
24
|
+
@value = new_value.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_i
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"#{super}#{to_i}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def label
|
36
|
+
"#{super}#{to_i}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'dependency_injector'
|
2
|
+
require_relative 'node'
|
3
|
+
require_relative 'guarantor'
|
4
|
+
|
5
|
+
module Diaspora
|
6
|
+
module Cluster
|
7
|
+
module Creator
|
8
|
+
class NodeCollectionFactory
|
9
|
+
extend DependencyInjector
|
10
|
+
def_injector(:node_builder) { Node.public_method(:new) }
|
11
|
+
def_injector(:node_guarantor) { Guarantor.new(:technology, 2).public_method(:guarantee!) }
|
12
|
+
|
13
|
+
attr_reader :cluster
|
14
|
+
def initialize(cluster)
|
15
|
+
@cluster = cluster
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_from(names)
|
19
|
+
collection = []
|
20
|
+
names.each_with_object(collection) do |name,mem|
|
21
|
+
mem << node_builder.call(cluster, name)
|
22
|
+
end
|
23
|
+
node_guarantor.call(collection)
|
24
|
+
collection
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -3,36 +3,43 @@ module Diaspora
|
|
3
3
|
module Cluster
|
4
4
|
module Creator
|
5
5
|
class Template
|
6
|
-
attr_reader :
|
7
|
-
def initialize(
|
8
|
-
raise RuntimeError unless
|
9
|
-
raise RuntimeError unless
|
10
|
-
@
|
6
|
+
attr_reader :cluster
|
7
|
+
def initialize(cluster)
|
8
|
+
raise RuntimeError unless cluster.respond_to?(:each_node)
|
9
|
+
raise RuntimeError unless cluster.respond_to?(:each_edge)
|
10
|
+
@cluster = cluster
|
11
11
|
end
|
12
|
+
|
12
13
|
def to_s
|
13
14
|
canvas.to_s
|
14
15
|
end
|
15
|
-
def to_dot(filename = '
|
16
|
+
def to_dot(filename = 'cluster.dot')
|
16
17
|
canvas.output(:dot => "#{filename}")
|
17
18
|
end
|
18
|
-
def to_png(filename = '
|
19
|
+
def to_png(filename = 'cluster.png')
|
19
20
|
canvas.output(:png => "#{filename}")
|
20
21
|
end
|
22
|
+
def to_svg(filename = 'cluster.svg')
|
23
|
+
canvas.output(:svg => "#{filename}")
|
24
|
+
end
|
21
25
|
protected
|
22
26
|
def canvas
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
return @canvas if @canvas
|
28
|
+
@canvas = GraphViz.new(cluster.to_s, :type => :graph )
|
29
|
+
|
30
|
+
cluster.each_node do |node|
|
31
|
+
options = {}
|
32
|
+
options[:label] = (node.respond_to?(:label) ? node.label : node.to_s)
|
33
|
+
@canvas.add_nodes(node.to_s, options)
|
27
34
|
end
|
28
|
-
|
29
|
-
|
35
|
+
|
36
|
+
cluster.each_edge do |edge|
|
30
37
|
to = edge[0]
|
31
38
|
from = edge[1]
|
32
|
-
|
39
|
+
@canvas.add_edges(to.to_s, from.to_s)
|
33
40
|
end
|
34
|
-
|
35
|
-
|
41
|
+
|
42
|
+
@canvas
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../spec_helper_lite'
|
2
|
+
require 'attribute_collection_factory'
|
3
|
+
|
4
|
+
describe AttributeCollectionFactory do
|
5
|
+
subject { AttributeCollectionFactory.new(cluster)}
|
6
|
+
let(:cluster) { Object.new }
|
7
|
+
it 'should extract attributes from name' do
|
8
|
+
subject.attribute_builder = lambda {|string|
|
9
|
+
"attr-#{string}"
|
10
|
+
}
|
11
|
+
subject.build_from(['Magic','Trees','Cows']).must_equal(["attr-Magic", "attr-Trees", "attr-Cows"])
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should build from default when empty array is sent' do
|
15
|
+
attribute_builder = lambda {|string|
|
16
|
+
"attr-#{string}"
|
17
|
+
}
|
18
|
+
subject.attribute_builder = attribute_builder
|
19
|
+
expected = AttributeCollectionFactory::DEFAULT_ATTRIBUTE_NAMES.collect {|name| attribute_builder.call(name)}
|
20
|
+
subject.build_from([]).must_equal(expected)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should build from default when nil is sent' do
|
24
|
+
attribute_builder = lambda {|string|
|
25
|
+
"attr-#{string}"
|
26
|
+
}
|
27
|
+
subject.attribute_builder = attribute_builder
|
28
|
+
expected = AttributeCollectionFactory::DEFAULT_ATTRIBUTE_NAMES.collect {|name| attribute_builder.call(name)}
|
29
|
+
subject.build_from(nil).must_equal(expected)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative '../spec_helper_lite'
|
2
|
+
require 'attribute'
|
3
|
+
|
4
|
+
describe Attribute do
|
5
|
+
describe 'with assumed prefix' do
|
6
|
+
subject { Attribute.new('Hair Color')}
|
7
|
+
|
8
|
+
describe '#to_s' do
|
9
|
+
it 'should use the name' do
|
10
|
+
subject.to_s.must_equal 'Hair Color'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#to_sym' do
|
15
|
+
it 'should convert name to method friendly sym' do
|
16
|
+
subject.to_sym.must_equal :hair_color
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#name' do
|
21
|
+
it 'should have a name' do
|
22
|
+
subject.name.must_equal 'Hair Color'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
describe '#prefix' do
|
26
|
+
it 'should default to first character' do
|
27
|
+
subject.prefix.must_equal 'H'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#label' do
|
32
|
+
it 'should be the prefix' do
|
33
|
+
subject.label.must_equal(subject.prefix)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'with extracted prefix' do
|
39
|
+
subject { Attribute.new('H(a)ir Color')}
|
40
|
+
|
41
|
+
describe '#to_s' do
|
42
|
+
it 'should use the name' do
|
43
|
+
subject.to_s.must_equal 'Hair Color'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#to_sym' do
|
48
|
+
it 'should convert name to method friendly sym' do
|
49
|
+
subject.to_sym.must_equal :hair_color
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#name' do
|
54
|
+
it 'should have a name' do
|
55
|
+
subject.name.must_equal 'Hair Color'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
describe '#prefix' do
|
59
|
+
it 'should be extracted' do
|
60
|
+
subject.prefix.must_equal 'A'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe '#label' do
|
64
|
+
it 'should be the prefix' do
|
65
|
+
subject.label.must_equal(subject.prefix)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -2,25 +2,76 @@ require_relative '../spec_helper_lite'
|
|
2
2
|
require 'cluster'
|
3
3
|
|
4
4
|
describe Cluster do
|
5
|
-
subject { Cluster.new(names) }
|
5
|
+
subject { Cluster.new(names, attribute_names) }
|
6
|
+
let(:attribute_names) { ['tech'] }
|
6
7
|
let(:names) { ['a'] }
|
7
8
|
|
8
|
-
describe '#
|
9
|
-
it 'should yield
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
9
|
+
describe '#each_node' do
|
10
|
+
it 'should yield the nodes' do
|
11
|
+
expected_output = [1,2,3]
|
12
|
+
subject.node_collection_builder = lambda { expected_output }
|
13
|
+
@yielded = []
|
14
|
+
subject.each_node do |node|
|
15
|
+
@yielded << node
|
16
|
+
end
|
17
|
+
@yielded.must_equal(expected_output)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#nodes' do
|
22
|
+
it 'should delegate node creation to node_maker' do
|
23
|
+
expected_output = ['output']
|
24
|
+
maker = MiniTest::Mock.new
|
25
|
+
maker.expect(:call, expected_output)
|
26
|
+
subject.node_collection_builder = maker
|
27
|
+
subject.nodes.must_equal(expected_output)
|
28
|
+
maker.verify
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#each_edge' do
|
33
|
+
it 'should yield the edges' do
|
34
|
+
expected_output = [1,2,3]
|
35
|
+
subject.edge_collection_builder = lambda { expected_output }
|
19
36
|
@yielded = []
|
20
|
-
subject.
|
37
|
+
subject.each_edge do |edge|
|
38
|
+
@yielded << edge
|
39
|
+
end
|
40
|
+
@yielded.must_equal(expected_output)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#edges' do
|
45
|
+
it 'should delegate edge drawing to the edge_collection_builder' do
|
46
|
+
expected_output = ['output']
|
47
|
+
drawer = MiniTest::Mock.new
|
48
|
+
drawer.expect(:call, expected_output)
|
49
|
+
subject.edge_collection_builder = drawer
|
50
|
+
subject.edges.must_equal(expected_output)
|
51
|
+
drawer.verify
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#each_attribute' do
|
56
|
+
it 'should yield the attributes' do
|
57
|
+
expected_output = [1,2,3]
|
58
|
+
subject.attribute_collection_builder = lambda { expected_output }
|
59
|
+
@yielded = []
|
60
|
+
subject.each_attribute do |attribute|
|
61
|
+
@yielded << attribute
|
62
|
+
end
|
63
|
+
@yielded.must_equal(expected_output)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#attributes' do
|
68
|
+
it 'should delegate attribute creation to the attribute_collection_builder' do
|
69
|
+
expected_output = ['output']
|
70
|
+
builder = MiniTest::Mock.new
|
71
|
+
builder.expect(:call, expected_output)
|
72
|
+
subject.attribute_collection_builder = builder
|
73
|
+
subject.attributes.must_equal(expected_output)
|
21
74
|
builder.verify
|
22
|
-
guarantor.verify
|
23
|
-
@yielded.must_equal [transformed_object]
|
24
75
|
end
|
25
76
|
end
|
26
77
|
end
|