graph_builder 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|