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 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: []