graph_builder 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in graph_builder.gemspec
4
+ gemspec
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,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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,17 @@
1
+ module GraphBuilder
2
+ module Linkable
3
+
4
+ def link_to other
5
+ linked_to << other
6
+ end
7
+
8
+ def linked_to
9
+ @linked_to ||= []
10
+ end
11
+
12
+ def links
13
+ linked_to.map{|to|[self,to]}
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module GraphBuilder
2
+ VERSION = "1.0.0"
3
+ 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: []