diaspora-cluster-creator 0.2.0 → 0.3.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.
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