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.
Files changed (42) hide show
  1. data/.gitignore +1 -2
  2. data/Guardfile +1 -2
  3. data/README.md +2 -0
  4. data/TODO.todo +2 -0
  5. data/bin/diaspora-cluster +11 -8
  6. data/diaspora-cluster-creator.gemspec +2 -0
  7. data/features/cluster.feature +1 -1
  8. data/features/command_line.feature +165 -0
  9. data/features/node.feature +13 -0
  10. data/features/step_definitions/cluster_steps.rb +3 -3
  11. data/features/step_definitions/command_line_steps.rb +7 -0
  12. data/features/step_definitions/node_steps.rb +16 -0
  13. data/features/support/aruba.rb +1 -0
  14. data/features/support/world.rb +4 -8
  15. data/lib/diaspora-cluster-creator.rb +12 -9
  16. data/lib/diaspora-cluster-creator/attribute.rb +29 -0
  17. data/lib/diaspora-cluster-creator/attribute_collection_factory.rb +29 -0
  18. data/lib/diaspora-cluster-creator/cluster.rb +31 -18
  19. data/lib/diaspora-cluster-creator/edge_drawer.rb +41 -0
  20. data/lib/diaspora-cluster-creator/guarantor.rb +21 -0
  21. data/lib/diaspora-cluster-creator/node.rb +71 -0
  22. data/lib/diaspora-cluster-creator/node_attribute.rb +41 -0
  23. data/lib/diaspora-cluster-creator/node_collection_factory.rb +30 -0
  24. data/lib/diaspora-cluster-creator/template.rb +23 -16
  25. data/lib/diaspora-cluster-creator/version.rb +1 -1
  26. data/spec/diaspora-cluster-creator/attribute_collection_factory_spec.rb +31 -0
  27. data/spec/diaspora-cluster-creator/attribute_spec.rb +69 -0
  28. data/spec/diaspora-cluster-creator/cluster_spec.rb +66 -15
  29. data/spec/diaspora-cluster-creator/edge_drawer_spec.rb +21 -0
  30. data/spec/diaspora-cluster-creator/guarantor_spec.rb +54 -0
  31. data/spec/diaspora-cluster-creator/node_attribute_spec.rb +36 -0
  32. data/spec/diaspora-cluster-creator/node_collection_factory_spec.rb +27 -0
  33. data/spec/diaspora-cluster-creator/node_spec.rb +65 -0
  34. data/spec/diaspora-cluster-creator/template_integration_spec.rb +9 -10
  35. data/spec/diaspora-cluster-creator/template_spec.rb +9 -2
  36. metadata +78 -34
  37. data/features/star_system.feature +0 -13
  38. data/features/step_definitions/star_system_steps.rb +0 -16
  39. data/lib/diaspora-cluster-creator/graph.rb +0 -58
  40. data/lib/diaspora-cluster-creator/star_system.rb +0 -80
  41. data/spec/diaspora-cluster-creator/graph_spec.rb +0 -34
  42. 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 :graph
7
- def initialize(graph)
8
- raise RuntimeError unless graph.respond_to?(:nodes)
9
- raise RuntimeError unless graph.respond_to?(:edges)
10
- @graph = graph
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 = 'graph.dot')
16
+ def to_dot(filename = 'cluster.dot')
16
17
  canvas.output(:dot => "#{filename}")
17
18
  end
18
- def to_png(filename = 'graph.png')
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
- template = GraphViz.new(graph.to_s, :type => :graph )
24
- nodes = {}
25
- graph.nodes.each do |node|
26
- nodes[node] = template.add_nodes(node.to_s, :label => (node.respond_to?(:label) ? node.label : node.to_s))
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
- graph.edges.each do |edge|
35
+
36
+ cluster.each_edge do |edge|
30
37
  to = edge[0]
31
38
  from = edge[1]
32
- template.add_edges(to.to_s, from.to_s)
39
+ @canvas.add_edges(to.to_s, from.to_s)
33
40
  end
34
-
35
- template
41
+
42
+ @canvas
36
43
  end
37
44
  end
38
45
  end
@@ -1,7 +1,7 @@
1
1
  module Diaspora
2
2
  module Cluster
3
3
  module Creator
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
6
6
  end
7
7
  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 '#each' do
9
- it 'should yield built star system' do
10
- built_object = Object.new
11
- transformed_object = Object.new
12
- guarantor = MiniTest::Mock.new
13
- builder = MiniTest::Mock.new
14
- builder.expect(:call, built_object, [subject,'a'])
15
- guarantor.expect(:call, [transformed_object], [[built_object]])
16
-
17
- subject.star_system_builder = builder
18
- subject.star_system_guarantor = guarantor
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.each {|object| @yielded << object }
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