graph_builder 1.0.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +100 -0
- data/Rakefile +2 -0
- data/graph_builder.gemspec +17 -0
- data/lib/graph_builder/linkable.rb +17 -0
- data/lib/graph_builder/version.rb +3 -0
- data/lib/graph_builder.rb +203 -0
- data/test/graph_builder_test.rb +311 -0
- metadata +55 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Thomas Sonntag
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# GraphBuilder
|
2
|
+
|
3
|
+
DSL to build directed graphs
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'graph_builder'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install graph_builder
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
GraphBuilder provides a DSL to build a graph of arbritary objects.
|
22
|
+
|
23
|
+
The objects must implement
|
24
|
+
|
25
|
+
link_to( other )
|
26
|
+
|
27
|
+
which must implement a link between self and other.
|
28
|
+
|
29
|
+
|
30
|
+
### Examples:
|
31
|
+
|
32
|
+
#### A simple chain: a → b → c
|
33
|
+
|
34
|
+
GraphBuilder::Builder.build do |builder|
|
35
|
+
builder.add a
|
36
|
+
builder.add b
|
37
|
+
builder.add c
|
38
|
+
end
|
39
|
+
|
40
|
+
#### A simple branch: a → b, a → c
|
41
|
+
|
42
|
+
GraphBuilder::Builder.build do |builder|
|
43
|
+
builder.add a
|
44
|
+
builder.branch do
|
45
|
+
builder.add b
|
46
|
+
builder.add c
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#### Diamond shaped graph: a → l → b, a → r → b
|
51
|
+
|
52
|
+
GraphBuilder::Builder.build do |builder|
|
53
|
+
builder.add a
|
54
|
+
builder.branch do
|
55
|
+
builder.add l
|
56
|
+
builder.add r
|
57
|
+
end
|
58
|
+
builder.add b
|
59
|
+
end
|
60
|
+
|
61
|
+
#### Diamond with chains: a → l1 → l2 → b, a → r1 → r2 → r3 → b
|
62
|
+
|
63
|
+
GraphBuilder::Builder.build do |builder|
|
64
|
+
builder.add a
|
65
|
+
builder.branch do
|
66
|
+
builder.chain do
|
67
|
+
builder.add l1
|
68
|
+
builder.add l2
|
69
|
+
end
|
70
|
+
builder.chain do
|
71
|
+
builder.add r1
|
72
|
+
builder.add r2
|
73
|
+
builder.add r3
|
74
|
+
end
|
75
|
+
end
|
76
|
+
builder.add b
|
77
|
+
end
|
78
|
+
|
79
|
+
### Implemention of #link_to
|
80
|
+
|
81
|
+
graph_builder comes with the module GraphBuilder::Linkable which implements
|
82
|
+
|
83
|
+
# links self to other
|
84
|
+
link_to( other )
|
85
|
+
|
86
|
+
# returns an array of objects self is linked to
|
87
|
+
link_to
|
88
|
+
|
89
|
+
# returns an array of pairs [ [ self, other1 ], [ self, other2 ], ... ]
|
90
|
+
# for linked objects other1, other2, ...
|
91
|
+
links
|
92
|
+
|
93
|
+
|
94
|
+
## Contributing
|
95
|
+
|
96
|
+
1. Fork it
|
97
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
98
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
99
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
100
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/graph_builder/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Thomas Sonntag"]
|
6
|
+
gem.email = ["git@sonntagsbox.de"]
|
7
|
+
gem.description = %q{DSL for building directed graphs}
|
8
|
+
gem.summary = %q{DSL for building directed graphs}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "graph_builder"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = GraphBuilder::VERSION
|
17
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module GraphBuilder
|
2
|
+
class BuilderError < StandardError; end
|
3
|
+
|
4
|
+
DEBUG = false
|
5
|
+
|
6
|
+
# implements an AND/OR tree
|
7
|
+
# An Branch represents a branch
|
8
|
+
# An Chain represents a chain
|
9
|
+
# A Leaf contains a thing
|
10
|
+
class Base
|
11
|
+
attr_reader :parent, :opts, :children
|
12
|
+
|
13
|
+
def initialize parent, opts = {}
|
14
|
+
@parent, @opts, @children = parent, opts, []
|
15
|
+
end
|
16
|
+
|
17
|
+
def process; children.each &:process; end
|
18
|
+
def empty?; children.all? &:empty?; end
|
19
|
+
|
20
|
+
def dump recursive = true
|
21
|
+
debug{self.to_s} or return false
|
22
|
+
children.each{|c|c.dump(recursive)} if recursive
|
23
|
+
end
|
24
|
+
|
25
|
+
def debug &proc
|
26
|
+
DEBUG or return false
|
27
|
+
puts indent + proc.call
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def indent; " " * depth; end
|
32
|
+
def depth; ancestors.count; end
|
33
|
+
def ancestors; parent ? parent.ancestors << parent : []; end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Node < Base
|
37
|
+
def add_leaf child
|
38
|
+
add_node Leaf.new(self,child)
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_node node
|
42
|
+
@children << node
|
43
|
+
node
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
"[#{self.class.name.split('::').last},empty?=#{empty?},f=#{first_things},l=#{last_things}]"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
class Leaf < Base
|
53
|
+
attr_reader :thing
|
54
|
+
def initialize parent, thing
|
55
|
+
@thing = thing
|
56
|
+
super parent
|
57
|
+
end
|
58
|
+
|
59
|
+
def empty?; false; end
|
60
|
+
def last_things; thing; end
|
61
|
+
def first_things; thing; end
|
62
|
+
def to_s; "[#{thing}]"; end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Chain < Node
|
66
|
+
def last_things; children.map(&:last_things).last; end
|
67
|
+
def first_things; children.map(&:first_things).first; end
|
68
|
+
|
69
|
+
def process
|
70
|
+
children.each &:process
|
71
|
+
|
72
|
+
debug{"processing #{self}"}
|
73
|
+
debug{" children: #{children.map(&:to_s).join(',')}" }
|
74
|
+
|
75
|
+
# Connect the pairs of a chain:
|
76
|
+
# connect all last_things of child with the first_things of the following child
|
77
|
+
children.each_cons(2) do |pair|
|
78
|
+
debug{" pair: (#{pair.first},#{pair.last})"}
|
79
|
+
froms = [pair.first.last_things].flatten
|
80
|
+
tos = [pair.last.first_things].flatten
|
81
|
+
debug{" froms= last_things of #{pair.first}: #{froms.map(&:to_s).join(',')}"}
|
82
|
+
debug{" tos= first_things of #{pair.last}: #{tos.map(&:to_s).join(',')}"}
|
83
|
+
tos.each do |to|
|
84
|
+
froms.each do |from|
|
85
|
+
debug{" link from=#{from} to=#{to}"}
|
86
|
+
from.link_to to
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
class Branch < Node
|
95
|
+
def last_things; children.map &:last_things; end
|
96
|
+
def first_things; children.map &:first_things; end
|
97
|
+
end
|
98
|
+
|
99
|
+
class Builder
|
100
|
+
def self.build opts={}, &proc
|
101
|
+
b = new opts
|
102
|
+
proc.call b
|
103
|
+
b.send :process
|
104
|
+
end
|
105
|
+
|
106
|
+
attr_reader :logger
|
107
|
+
|
108
|
+
def initialize opts = {}
|
109
|
+
@cur = @root = Chain.new(nil)
|
110
|
+
@logger = opts.delete(:logger)
|
111
|
+
@opts = opts # global opts
|
112
|
+
debug{"initialize"}
|
113
|
+
dump_tree
|
114
|
+
end
|
115
|
+
|
116
|
+
def add thing
|
117
|
+
raise InvalidBlockError if block_given?
|
118
|
+
add_thing thing
|
119
|
+
end
|
120
|
+
|
121
|
+
def chain opts = {}, &proc ; node Chain, opts, proc; end
|
122
|
+
def branch opts = {}, &proc ; node Branch, opts, proc; end
|
123
|
+
|
124
|
+
alias_method :with, :chain
|
125
|
+
|
126
|
+
# yield each child of the children of the recent thing
|
127
|
+
def children opts = {}
|
128
|
+
debug{">> children"}
|
129
|
+
debug{"children: @cur=#{@cur}, last_things=#{@cur.last_things}"}
|
130
|
+
recent_things = [@cur.last_things].flatten
|
131
|
+
unless recent_things.size == 1
|
132
|
+
raise BuilderError, "invalid recent_thing #{recent_things}, @cur=#{@cur}. children() expects one recent thing"
|
133
|
+
end
|
134
|
+
recent_thing = recent_things.first
|
135
|
+
unless recent_thing.resource
|
136
|
+
raise BuilderError, "no resource for recent_thing #{recent_thing}"
|
137
|
+
end
|
138
|
+
|
139
|
+
debug{"children: resource=#{recent_thing.resource}"}
|
140
|
+
|
141
|
+
branch opts do
|
142
|
+
recent_thing.children.map do |child|
|
143
|
+
chain(opts.merge(:resource => child)){ yield child }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
debug{"<< children"}
|
147
|
+
end
|
148
|
+
|
149
|
+
def options opts
|
150
|
+
res = @opts.merge(@cur.opts).merge(opts)
|
151
|
+
debug{"options: opts=#{opts.inspect}, current.opts=#{@cur.opts.inspect}, @opts=#{@opts}, options=#{res.inspect}"}
|
152
|
+
res
|
153
|
+
end
|
154
|
+
|
155
|
+
# set or get global opt
|
156
|
+
def global_opt key,value
|
157
|
+
if value
|
158
|
+
@opts[key] = value
|
159
|
+
else
|
160
|
+
@opts[key]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
# perform block with given opts
|
167
|
+
def node clazz, opts, proc
|
168
|
+
debug{">> #{clazz}"}
|
169
|
+
# push
|
170
|
+
prev = @cur
|
171
|
+
@cur = clazz.new(prev,opts)
|
172
|
+
proc.call
|
173
|
+
debug{"-- @cur=#{@cur}"}
|
174
|
+
prev.add_node @cur unless @cur.empty?
|
175
|
+
# pop
|
176
|
+
raise BuilderError, "stack error: no parent for @cur = #{@cur}" unless @cur.parent
|
177
|
+
@cur = prev
|
178
|
+
dump_tree
|
179
|
+
debug{"<< #{clazz}"}
|
180
|
+
end
|
181
|
+
|
182
|
+
def process
|
183
|
+
@root.process
|
184
|
+
end
|
185
|
+
|
186
|
+
def add_thing thing
|
187
|
+
@cur.add_leaf thing
|
188
|
+
debug{"add_thing #{thing}"}
|
189
|
+
dump_tree
|
190
|
+
thing
|
191
|
+
end
|
192
|
+
|
193
|
+
def dump_tree
|
194
|
+
@root.debug{"*** whole tree ***"} or return
|
195
|
+
@root.dump true
|
196
|
+
@root.debug{'**************'}
|
197
|
+
end
|
198
|
+
|
199
|
+
def debug
|
200
|
+
@root.debug{yield}
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
$:.unshift File.expand_path( '../lib/', File.dirname( __FILE__))
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
require 'graph_builder'
|
6
|
+
require 'graph_builder/linkable'
|
7
|
+
|
8
|
+
class MyResource
|
9
|
+
attr_reader :children, :name
|
10
|
+
|
11
|
+
def initialize(name, children = [])
|
12
|
+
@name, @children = name, children
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Thing
|
21
|
+
include GraphBuilder::Linkable
|
22
|
+
|
23
|
+
attr_reader :resource
|
24
|
+
|
25
|
+
def initialize resource=nil
|
26
|
+
@resource = resource
|
27
|
+
end
|
28
|
+
|
29
|
+
def children
|
30
|
+
resource.children
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.links(things)
|
34
|
+
things.inject([]) {|res,t| r = t.links; res +=r unless r.empty?; res }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.links_s(things)
|
38
|
+
links(things).map{|r|"#{r.first}=>#{r.last}"}.join(",")
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
s = "#{self.class}"
|
43
|
+
s += "(#{resource})" if resource
|
44
|
+
s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Thing0 < Thing; end
|
49
|
+
class Thing1 < Thing; end
|
50
|
+
class Thing2 < Thing; end
|
51
|
+
class Thing3 < Thing; end
|
52
|
+
class Thing4 < Thing; end
|
53
|
+
class Thing11 < Thing; end
|
54
|
+
class Thing12 < Thing; end
|
55
|
+
class Thing21 < Thing; end
|
56
|
+
class Thing22 < Thing; end
|
57
|
+
class Thing23 < Thing; end
|
58
|
+
class Thing31 < Thing; end
|
59
|
+
class Thing32 < Thing; end
|
60
|
+
class ThingT < Thing; end
|
61
|
+
class TestThing < Thing; end
|
62
|
+
class ThingA < Thing; end
|
63
|
+
class ThingB < Thing; end
|
64
|
+
|
65
|
+
class GraphBuilderTest < MiniTest::Unit::TestCase
|
66
|
+
|
67
|
+
# thing1 -> thing2 -> TestThing
|
68
|
+
def test_simple
|
69
|
+
#puts "---------------test_simple-----------------"
|
70
|
+
t1= Thing1.new
|
71
|
+
t2 = nil
|
72
|
+
tt = nil
|
73
|
+
GraphBuilder::Builder.build do |b|
|
74
|
+
b.add t1
|
75
|
+
assert (nil != t2 = b.add(Thing2.new))
|
76
|
+
assert_instance_of Thing2, t2
|
77
|
+
assert (nil != tt = b.add(TestThing.new))
|
78
|
+
assert_instance_of TestThing, tt
|
79
|
+
end
|
80
|
+
|
81
|
+
r = Thing.links([t1,t2,tt])
|
82
|
+
assert_equal 2, r.size
|
83
|
+
assert r.include? [t1,t2]
|
84
|
+
assert r.include? [t2,tt]
|
85
|
+
end
|
86
|
+
|
87
|
+
# thing1
|
88
|
+
def test_empty
|
89
|
+
#puts "---------------test_empty-----------------"
|
90
|
+
t1 = nil
|
91
|
+
GraphBuilder::Builder.build do |b|
|
92
|
+
t1 = b.add(Thing1.new)
|
93
|
+
end
|
94
|
+
|
95
|
+
r = Thing.links([t1])
|
96
|
+
assert_equal 0, r.size
|
97
|
+
end
|
98
|
+
|
99
|
+
# t1 -> (t2 -> t3) -> t4
|
100
|
+
def test_chain
|
101
|
+
#puts "---------------test_chain-----------------"
|
102
|
+
|
103
|
+
t1 = t2 = t3 = t4 = nil
|
104
|
+
GraphBuilder::Builder.build do |b|
|
105
|
+
t1 = b.add(Thing1.new)
|
106
|
+
b.chain do
|
107
|
+
t2 = b.add(Thing2.new)
|
108
|
+
t3 = b.add(Thing3.new)
|
109
|
+
end
|
110
|
+
t4 = b.add(Thing4.new)
|
111
|
+
end
|
112
|
+
|
113
|
+
r = Thing.links([t1,t2,t3,t4])
|
114
|
+
assert_equal 3, r.size
|
115
|
+
assert r.include? [t1,t2]
|
116
|
+
assert r.include? [t2,t3]
|
117
|
+
assert r.include? [t3,t4]
|
118
|
+
end
|
119
|
+
|
120
|
+
# t1 -> () -> t4
|
121
|
+
def test_empty_chain
|
122
|
+
#puts "---------------test_chain-----------------"
|
123
|
+
|
124
|
+
t1 = t2 = t3 = t4 = nil
|
125
|
+
GraphBuilder::Builder.build do |b|
|
126
|
+
t1 = b.add(Thing1.new)
|
127
|
+
b.chain do
|
128
|
+
end
|
129
|
+
t4 = b.add(Thing4.new)
|
130
|
+
end
|
131
|
+
|
132
|
+
r = Thing.links([t1,t4])
|
133
|
+
assert_equal 1, r.size
|
134
|
+
assert r.include? [t1,t4]
|
135
|
+
end
|
136
|
+
|
137
|
+
# t1 -> t11 -> t2, t1 -> t12 -> t2
|
138
|
+
def test_branch
|
139
|
+
#puts "---------------test_branch-----------------"
|
140
|
+
t1= nil
|
141
|
+
t2 = nil
|
142
|
+
t11 = nil
|
143
|
+
t12 = nil
|
144
|
+
GraphBuilder::Builder.build do |b|
|
145
|
+
t1 = b.add(Thing1.new)
|
146
|
+
b.branch do
|
147
|
+
t11 = b.add(Thing11.new)
|
148
|
+
t12 = b.add(Thing12.new)
|
149
|
+
end
|
150
|
+
t2 = b.add(Thing2.new)
|
151
|
+
end
|
152
|
+
|
153
|
+
r = Thing.links([t1,t2,t11,t12])
|
154
|
+
assert_equal 4, r.size
|
155
|
+
assert r.include? [t1,t11]
|
156
|
+
assert r.include? [t1,t12]
|
157
|
+
assert r.include? [t11,t2]
|
158
|
+
assert r.include? [t12,t2]
|
159
|
+
end
|
160
|
+
|
161
|
+
# t1 -> (empty) -> t2
|
162
|
+
def test_empty_branch
|
163
|
+
#puts "---------------test_branch-----------------"
|
164
|
+
t1 = t2 = nil
|
165
|
+
GraphBuilder::Builder.build do |b|
|
166
|
+
t1 = b.add(Thing1.new)
|
167
|
+
b.branch do
|
168
|
+
end
|
169
|
+
t2 = b.add(Thing2.new)
|
170
|
+
end
|
171
|
+
|
172
|
+
r = Thing.links([t1,t2])
|
173
|
+
assert_equal 1, r.size
|
174
|
+
assert r.include? [t1,t2]
|
175
|
+
end
|
176
|
+
|
177
|
+
# t1 -> t11 -> t12 -> t2, t1 -> t21 -> t22 -> t2
|
178
|
+
def test_branch_chain
|
179
|
+
#puts "---------------test_branch_chain-----------------"
|
180
|
+
|
181
|
+
t1= t2 = t11 = t12 = t21 = t22 = nil
|
182
|
+
GraphBuilder::Builder.build do |b|
|
183
|
+
t1 = b.add(Thing1.new)
|
184
|
+
b.branch do
|
185
|
+
b.chain do
|
186
|
+
t11 = b.add(Thing11.new)
|
187
|
+
t12 = b.add(Thing12.new)
|
188
|
+
end
|
189
|
+
b.chain do
|
190
|
+
t21 = b.add(Thing21.new)
|
191
|
+
t22 = b.add(Thing22.new)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
t2 = b.add(Thing2.new)
|
195
|
+
end
|
196
|
+
|
197
|
+
r = Thing.links([t1,t2,t11,t12,t21,t22])
|
198
|
+
assert r.include? [t1,t11]
|
199
|
+
assert r.include? [t11,t12]
|
200
|
+
assert r.include? [t12,t2]
|
201
|
+
|
202
|
+
assert r.include? [t1,t21]
|
203
|
+
assert r.include? [t21,t22]
|
204
|
+
assert r.include? [t22,t2]
|
205
|
+
|
206
|
+
assert_equal 6, r.size
|
207
|
+
end
|
208
|
+
|
209
|
+
# t1 -> t11 -> t12 -> t2, t1 -> t21 -> t23 -> t2, t1 -> t31 -> t32 -> t23 -> t2
|
210
|
+
def test_branch_chain2
|
211
|
+
#puts "---------------test_branch_chain2-----------------"
|
212
|
+
|
213
|
+
t1= t2 = t11 = t12 = t21 = t23 = t31 = t32 = nil
|
214
|
+
GraphBuilder::Builder.build do |b|
|
215
|
+
t1 = b.add(Thing1.new)
|
216
|
+
b.branch do
|
217
|
+
b.chain do
|
218
|
+
t11 = b.add(Thing11.new)
|
219
|
+
t12 = b.add(Thing12.new)
|
220
|
+
end
|
221
|
+
b.chain do
|
222
|
+
b.branch do
|
223
|
+
t21 = b.add(Thing21.new)
|
224
|
+
b.chain do
|
225
|
+
t31 = b.add(Thing31.new)
|
226
|
+
t32 = b.add(Thing32.new)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
t23 = b.add(Thing23.new)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
t2 = b.add(Thing2.new)
|
233
|
+
end
|
234
|
+
|
235
|
+
r = Thing.links([t1,t2,t11,t12,t21,t23,t31,t32])
|
236
|
+
assert r.include? [t1,t11]
|
237
|
+
assert r.include? [t1,t21]
|
238
|
+
assert r.include? [t1,t31]
|
239
|
+
|
240
|
+
assert r.include? [t11,t12]
|
241
|
+
assert r.include? [t12,t2]
|
242
|
+
|
243
|
+
assert r.include? [t21,t23]
|
244
|
+
assert r.include? [t23,t2]
|
245
|
+
|
246
|
+
assert r.include? [t31,t32]
|
247
|
+
assert r.include? [t32,t23]
|
248
|
+
|
249
|
+
assert_equal 9, r.size
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
# t0(order) -> t1(pos1) -> t11(batch11) -> t12(batch11) -> t2(order)
|
254
|
+
# t0(order) -> t1(pos1) -> t11(batch12) -> t12(batch12) -> t2(order)
|
255
|
+
# t0(order) -> t1(pos2) -> t11(batch21) -> t12(batch21) -> t2(order)
|
256
|
+
# t0(order) -> t1(pos2) -> t11(batch22) -> t12(batch22) -> t2(order)
|
257
|
+
def test_children
|
258
|
+
#puts "---------------test_children-----------------"
|
259
|
+
t= {}
|
260
|
+
|
261
|
+
batch11 = MyResource.new :batch11
|
262
|
+
batch12 = MyResource.new :batch12
|
263
|
+
batch21 = MyResource.new :batch21
|
264
|
+
batch22 = MyResource.new :batch22
|
265
|
+
pos1 = MyResource.new :pos1, [ batch11, batch12 ]
|
266
|
+
pos2 = MyResource.new :pos2, [ batch21, batch22 ]
|
267
|
+
order = MyResource.new :order, [pos1, pos2]
|
268
|
+
|
269
|
+
GraphBuilder::Builder.build do |b|
|
270
|
+
t[:order] = [ b.add(Thing0.new(order)) ]
|
271
|
+
|
272
|
+
b.children do |pos|
|
273
|
+
t[pos.name] = b.add Thing1.new(pos)
|
274
|
+
b.children do |batch|
|
275
|
+
b1 = b.add Thing11.new(batch)
|
276
|
+
b2 = b.add Thing12.new(batch)
|
277
|
+
t[batch.name] = [b1, b2]
|
278
|
+
end
|
279
|
+
end
|
280
|
+
t[:order] << b.add( Thing2.new(order))
|
281
|
+
end
|
282
|
+
|
283
|
+
r = Thing.links(t.values.flatten)
|
284
|
+
assert_instance_of Thing0, t[:order].first
|
285
|
+
assert_instance_of Thing2, t[:order].last
|
286
|
+
assert_instance_of Thing1, t[:pos1]
|
287
|
+
assert_instance_of Thing1, t[:pos2]
|
288
|
+
assert_instance_of Thing11, t[:batch11].first
|
289
|
+
assert_instance_of Thing12, t[:batch12].last
|
290
|
+
assert_instance_of Thing11, t[:batch21].first
|
291
|
+
assert_instance_of Thing12, t[:batch22].last
|
292
|
+
|
293
|
+
assert r.include? [t[:order].first,t[:pos1]]
|
294
|
+
assert r.include? [t[:order].first,t[:pos2]]
|
295
|
+
assert r.include? [t[:pos1],t[:batch11].first]
|
296
|
+
assert r.include? [t[:pos1],t[:batch12].first]
|
297
|
+
assert r.include? [t[:pos2],t[:batch21].first]
|
298
|
+
assert r.include? [t[:pos2],t[:batch22].first]
|
299
|
+
assert r.include? [t[:batch11].first,t[:batch11].last]
|
300
|
+
assert r.include? [t[:batch12].first,t[:batch12].last]
|
301
|
+
assert r.include? [t[:batch21].first,t[:batch21].last]
|
302
|
+
assert r.include? [t[:batch22].first,t[:batch22].last]
|
303
|
+
assert r.include? [t[:batch11].last,t[:order].last]
|
304
|
+
assert r.include? [t[:batch12].last,t[:order].last]
|
305
|
+
assert r.include? [t[:batch21].last,t[:order].last]
|
306
|
+
assert r.include? [t[:batch22].last,t[:order].last]
|
307
|
+
|
308
|
+
assert_equal 14, r.size
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: graph_builder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Sonntag
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-04 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: DSL for building directed graphs
|
15
|
+
email:
|
16
|
+
- git@sonntagsbox.de
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- graph_builder.gemspec
|
27
|
+
- lib/graph_builder.rb
|
28
|
+
- lib/graph_builder/linkable.rb
|
29
|
+
- lib/graph_builder/version.rb
|
30
|
+
- test/graph_builder_test.rb
|
31
|
+
homepage: ''
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.11
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: DSL for building directed graphs
|
55
|
+
test_files: []
|