yargi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENCE +25 -0
- data/README +79 -0
- data/lib/yargi/digraph.rb +287 -0
- data/lib/yargi/digraph_edge.rb +81 -0
- data/lib/yargi/digraph_vertex.rb +98 -0
- data/lib/yargi/edge_set.rb +38 -0
- data/lib/yargi/element_set.rb +166 -0
- data/lib/yargi/markable.rb +59 -0
- data/lib/yargi/predicate.rb +229 -0
- data/lib/yargi/vertex_set.rb +56 -0
- data/lib/yargi.rb +30 -0
- data/test/test_all.rb +8 -0
- data/test/yargi/README-example.dot +33 -0
- data/test/yargi/README-example.gif +0 -0
- data/test/yargi/digraph_set_features_test.rb +96 -0
- data/test/yargi/digraph_test.rb +360 -0
- data/test/yargi/digraph_vertex_test.rb +61 -0
- data/test/yargi/documentation_test.rb +44 -0
- data/test/yargi/element_set_test.rb +17 -0
- data/test/yargi/hypotheses_test.rb +30 -0
- data/test/yargi/markable_test.rb +56 -0
- data/test/yargi/predicate_test.rb +90 -0
- data/test/yargi/source-sink.dot +38 -0
- data/test/yargi/source-sink.gif +0 -0
- data/test/yargi/star.dot +144 -0
- data/test/yargi/vertex_set_test.rb +43 -0
- metadata +85 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Yargi
|
4
|
+
|
5
|
+
# Main module of VertexSet and EdgeSet
|
6
|
+
class ElementSet < Array
|
7
|
+
|
8
|
+
### Factory section #######################################################
|
9
|
+
|
10
|
+
# Creates a ElementSet instance using _elements_ varargs.
|
11
|
+
def self.[](*elements)
|
12
|
+
ElementSet.new(elements)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
### Array handling ########################################################
|
17
|
+
|
18
|
+
# Same as Array.dup
|
19
|
+
def dup() # :nodoc: #
|
20
|
+
extend_result(super)
|
21
|
+
end
|
22
|
+
|
23
|
+
# See Array.compact
|
24
|
+
def compact() # :nodoc: #
|
25
|
+
extend_result(super)
|
26
|
+
end
|
27
|
+
|
28
|
+
# See Array.flatten
|
29
|
+
def flatten() # :nodoc: #
|
30
|
+
extend_result(super)
|
31
|
+
end
|
32
|
+
|
33
|
+
# See Array.reverse
|
34
|
+
def reverse() # :nodoc: #
|
35
|
+
extend_result(super)
|
36
|
+
end
|
37
|
+
|
38
|
+
# See Array.uniq
|
39
|
+
def uniq() # :nodoc: #
|
40
|
+
extend_result(super)
|
41
|
+
end
|
42
|
+
|
43
|
+
# See Array.sort
|
44
|
+
def sort(&block) # :nodoc: #
|
45
|
+
extend_result(super(&block))
|
46
|
+
end
|
47
|
+
|
48
|
+
# See Array.concat
|
49
|
+
def concat(other) # :nodoc: #
|
50
|
+
extend_result(super(other))
|
51
|
+
end
|
52
|
+
|
53
|
+
# See Array.[]
|
54
|
+
def [](*args) # :nodoc: #
|
55
|
+
result = super(*args)
|
56
|
+
Array===result ? extend_result(result) : result
|
57
|
+
end
|
58
|
+
|
59
|
+
# See Array.+
|
60
|
+
def +(right) # :nodoc: #
|
61
|
+
extend_result(super(right))
|
62
|
+
end
|
63
|
+
|
64
|
+
# See Array.-
|
65
|
+
def -(right) # :nodoc: #
|
66
|
+
extend_result(super(right))
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
### Enumerable handling ###################################################
|
71
|
+
|
72
|
+
# See Enumerable.each_cons
|
73
|
+
def each_cons(n) # :nodoc: #
|
74
|
+
super(n) {|c| yield extend_result(c)}
|
75
|
+
end
|
76
|
+
|
77
|
+
# See Enumerable.each_slice
|
78
|
+
def each_slice(n) # :nodoc: #
|
79
|
+
super(n) {|c| yield extend_result(c)}
|
80
|
+
end
|
81
|
+
|
82
|
+
# See Enumerable.select
|
83
|
+
def select(&block) # :nodoc: #
|
84
|
+
extend_result(super(&block))
|
85
|
+
end
|
86
|
+
|
87
|
+
# See Enumerable.find_all
|
88
|
+
def find_all(&block) # :nodoc: #
|
89
|
+
extend_result(super(&block))
|
90
|
+
end
|
91
|
+
|
92
|
+
# See Enumerable.grep
|
93
|
+
def grep(pattern, &block) # :nodoc: #
|
94
|
+
greped = super(pattern, &block)
|
95
|
+
block_given? ? greped : extend_result(greped)
|
96
|
+
end
|
97
|
+
|
98
|
+
# See Enumerable.reject
|
99
|
+
def partition(&block) # :nodoc: #
|
100
|
+
p = super(&block)
|
101
|
+
[extend_result(p[0]), extend_result(p[1])]
|
102
|
+
end
|
103
|
+
|
104
|
+
# See Enumerable.reject
|
105
|
+
def reject(&block) # :nodoc: #
|
106
|
+
extend_result(super(&block))
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
### Markable handling #####################################################
|
111
|
+
|
112
|
+
# Fired to each element of the group.
|
113
|
+
def tag(*modules)
|
114
|
+
self.each {|elm| elm.tag(*modules)}
|
115
|
+
end
|
116
|
+
|
117
|
+
# Collects result of get_mark invocation on each element of the
|
118
|
+
# group and returns it as an array.
|
119
|
+
def get_mark(key)
|
120
|
+
self.collect {|elm| elm.get_mark(key)}
|
121
|
+
end
|
122
|
+
|
123
|
+
# Fired to each element of the group. Values are duplicated by default.
|
124
|
+
# Put dup to false to avoid this behavior.
|
125
|
+
def set_mark(key, value, dup=true)
|
126
|
+
self.each {|elm| elm.set_mark(key, (dup and not(Symbol===value)) ? value.dup : value)}
|
127
|
+
end
|
128
|
+
|
129
|
+
# When _marks_ is provided, the invocation is fired to all group
|
130
|
+
# elements. When a block is given, it is called on each element,
|
131
|
+
# passing it as argument. If the block returns a hash, that hash
|
132
|
+
# is installed as marks on the iterated element.
|
133
|
+
# The two usages (_marks_ and block) can be used conjointly.
|
134
|
+
def add_marks(marks=nil)
|
135
|
+
self.each {|elm| elm.add_marks(marks)} if marks
|
136
|
+
if block_given?
|
137
|
+
self.each do |elm|
|
138
|
+
hash = yield elm
|
139
|
+
elm.add_marks(hash) if hash
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
alias :merge_marks :add_marks
|
144
|
+
|
145
|
+
|
146
|
+
### Query handling ########################################################
|
147
|
+
|
148
|
+
# Filters this set with a 'predicate and block' predicate
|
149
|
+
# (see Yargi::Predicate)
|
150
|
+
def filter(predicate=nil, &block)
|
151
|
+
pred = Yargi::Predicate.to_predicate(predicate, &block)
|
152
|
+
extend_result(self.select{|e| pred===e})
|
153
|
+
end
|
154
|
+
|
155
|
+
### Protected section #####################################################
|
156
|
+
protected
|
157
|
+
|
158
|
+
# Extends a resulting array with the module. This method is intended
|
159
|
+
# to be overrided by specialization of this module.
|
160
|
+
def extend_result(result)
|
161
|
+
ElementSet.new(result)
|
162
|
+
end
|
163
|
+
|
164
|
+
end # class ElementSet
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Yargi
|
2
|
+
|
3
|
+
#
|
4
|
+
# Allows users to put its own marks on graph elements. A Hash-like API for setting
|
5
|
+
# and getting these marks is provided through <tt>[]</tt> and <tt>[]=</tt>. When a
|
6
|
+
# Symbol object is used as a mark key (and provided it does'nt lead to a name
|
7
|
+
# collision), accessors are automatically defined as singleton methods (without
|
8
|
+
# creating an instance variable however).
|
9
|
+
#
|
10
|
+
module Markable
|
11
|
+
|
12
|
+
# Tag this element with some modules
|
13
|
+
def tag(*modules)
|
14
|
+
modules.each {|mod| self.extend(mod)}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the mark value installed under _key_. Returns nil if no such mark.
|
18
|
+
def get_mark(key)
|
19
|
+
@marks ? @marks[key] : nil;
|
20
|
+
end
|
21
|
+
alias :[] :get_mark
|
22
|
+
|
23
|
+
# Sets a key/value pair as a mark. Overrides previous mark value if _key_ is
|
24
|
+
# already in used. Automatically creates accessors if _key_ is a Symbol and such
|
25
|
+
# methods do not already exists.
|
26
|
+
def set_mark(key, value)
|
27
|
+
@marks = {} unless @marks
|
28
|
+
@marks[key] = value
|
29
|
+
if Symbol===key and not(self.respond_to?(key) or self.respond_to?("#{key}=".to_sym))
|
30
|
+
instance_eval %Q{
|
31
|
+
class << self
|
32
|
+
def #{key}() @marks[:#{key}]; end
|
33
|
+
def #{key}=(value) @marks[:#{key}]=value; end
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
alias :[]= :set_mark
|
39
|
+
|
40
|
+
# Add all marks provided by a Hash instance _marks_.
|
41
|
+
def add_marks(marks)
|
42
|
+
marks.each_pair {|k,v| self[k]=v}
|
43
|
+
end
|
44
|
+
alias :merge_marks :add_marks
|
45
|
+
|
46
|
+
# Converts this Markable to a Hash. When _nonil_ is true, nil mark values
|
47
|
+
# do not lead to hash entries.
|
48
|
+
def to_h(nonil=true)
|
49
|
+
return {} unless @marks
|
50
|
+
marks = @marks.dup
|
51
|
+
if nonil
|
52
|
+
marks.delete_if {|k,v| v.nil?}
|
53
|
+
end
|
54
|
+
marks
|
55
|
+
end
|
56
|
+
|
57
|
+
end # module Markable
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
module Yargi
|
2
|
+
|
3
|
+
#
|
4
|
+
# Predicate for graph elements.
|
5
|
+
#
|
6
|
+
# The following automatic conversions apply on Ruby standard classes
|
7
|
+
# when using predicates (see to_predicate in particular):
|
8
|
+
# [Predicate] itself
|
9
|
+
# [Module] TagPredicate
|
10
|
+
# [Proc] LambdaPredicate
|
11
|
+
# [TrueClass, NilClass] TruePredicate
|
12
|
+
# [FalseClass] FalsePredicate
|
13
|
+
# [otherwise] an ArgumentError is raised.
|
14
|
+
#
|
15
|
+
class Predicate
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Builds a 'what and block' predicate, according the automatic conversions
|
19
|
+
# descibed above.
|
20
|
+
def to_predicate(what=nil, &block)
|
21
|
+
(what, block = block, nil) if what.nil?
|
22
|
+
p = case what
|
23
|
+
when Predicate
|
24
|
+
what
|
25
|
+
when Module
|
26
|
+
TagPredicate.new(what)
|
27
|
+
when Proc
|
28
|
+
LambdaPredicate.new(&what)
|
29
|
+
when TrueClass, NilClass
|
30
|
+
ALL
|
31
|
+
when FalseClass
|
32
|
+
NONE
|
33
|
+
else
|
34
|
+
raise ArgumentError, "Unable to convert #{what} to a predicate"
|
35
|
+
end
|
36
|
+
if block
|
37
|
+
p & LambdaPredicate.new(&block)
|
38
|
+
else
|
39
|
+
p
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Builds a 'self and right' predicate
|
45
|
+
def &(right)
|
46
|
+
AndPredicate.new(*[self, Predicate.to_predicate(right)])
|
47
|
+
end
|
48
|
+
|
49
|
+
# Builds a 'self or right' predicate
|
50
|
+
def |(right)
|
51
|
+
OrPredicate.new(*[self, Predicate.to_predicate(right)])
|
52
|
+
end
|
53
|
+
|
54
|
+
# Builds a 'not(self)' predicate
|
55
|
+
def not()
|
56
|
+
NotPredicate.new(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
end # class Predicate
|
60
|
+
|
61
|
+
# Decorates _true_ as a predicate
|
62
|
+
class TruePredicate < Predicate
|
63
|
+
|
64
|
+
# Always returns true
|
65
|
+
def ===(elm)
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns 'true'
|
70
|
+
def inspect
|
71
|
+
"true"
|
72
|
+
end
|
73
|
+
|
74
|
+
end # class TruePredicate
|
75
|
+
|
76
|
+
# Decorates _false_ as a predicate
|
77
|
+
class FalsePredicate < Predicate
|
78
|
+
|
79
|
+
# Always returns false
|
80
|
+
def ===(elm)
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns 'false'
|
85
|
+
def inspect
|
86
|
+
"false"
|
87
|
+
end
|
88
|
+
|
89
|
+
end # class TruePredicate
|
90
|
+
|
91
|
+
# Decorates a module instance as a predicate
|
92
|
+
class TagPredicate < Predicate
|
93
|
+
|
94
|
+
# Creates a Tag predicate
|
95
|
+
def initialize(mod)
|
96
|
+
raise ArgumentError, "Module expected, #{mod} received" unless Module===mod
|
97
|
+
@mod = mod
|
98
|
+
end
|
99
|
+
|
100
|
+
# Predicate implementation
|
101
|
+
def ===(elm)
|
102
|
+
@mod===elm
|
103
|
+
end
|
104
|
+
|
105
|
+
# Helps debugging predicates
|
106
|
+
def inspect
|
107
|
+
"is_a?(#{@mod})"
|
108
|
+
end
|
109
|
+
|
110
|
+
end # class TagPredicate
|
111
|
+
|
112
|
+
# Decorates a block as a predicate
|
113
|
+
class LambdaPredicate < Predicate
|
114
|
+
|
115
|
+
# Creates a Tag predicate
|
116
|
+
def initialize(&block)
|
117
|
+
raise ArgumentError, "Block of arity 1 expected" unless (block and block.arity==1)
|
118
|
+
@block = block
|
119
|
+
end
|
120
|
+
|
121
|
+
# Predicate implementation
|
122
|
+
def ===(elm)
|
123
|
+
@block.call(elm)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Helps debugging predicates
|
127
|
+
def inspect
|
128
|
+
"lambda{...}"
|
129
|
+
end
|
130
|
+
|
131
|
+
end # class LambdaPredicate
|
132
|
+
|
133
|
+
# Negates another predicate
|
134
|
+
class NotPredicate < Predicate
|
135
|
+
|
136
|
+
# Creates a 'not(negated)' predicate
|
137
|
+
def initialize(negated)
|
138
|
+
@negated = Predicate.to_predicate(negated)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Predicate implementation
|
142
|
+
def ===(elm)
|
143
|
+
not(@negated === elm)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Helps debugging predicates
|
147
|
+
def inspect
|
148
|
+
"not(#{@negated})"
|
149
|
+
end
|
150
|
+
|
151
|
+
end # class NotPredicate
|
152
|
+
|
153
|
+
# Conjunction predicate
|
154
|
+
class AndPredicate < Predicate
|
155
|
+
|
156
|
+
# Builds a AND predicate
|
157
|
+
def initialize(*anded)
|
158
|
+
raise ArgumentError, "Predicates expected" unless anded.all?{|p| Predicate===p}
|
159
|
+
@anded = anded
|
160
|
+
end
|
161
|
+
|
162
|
+
# Predicate implementation
|
163
|
+
def ===(elm)
|
164
|
+
@anded.all?{|p| p===elm}
|
165
|
+
end
|
166
|
+
|
167
|
+
# Pushes _right_ in the anded array
|
168
|
+
def &(right)
|
169
|
+
@anded << Predicate.to_predicate(right)
|
170
|
+
self
|
171
|
+
end
|
172
|
+
|
173
|
+
# Helps debugging predicates
|
174
|
+
def inspect
|
175
|
+
@anded.inject('') do |memo,p|
|
176
|
+
if memo.empty?
|
177
|
+
p.inspect
|
178
|
+
else
|
179
|
+
"#{memo} and #{p.inspect}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
end # class AndPredicate
|
185
|
+
|
186
|
+
# Disjunction predicate
|
187
|
+
class OrPredicate < Predicate
|
188
|
+
|
189
|
+
# Builds a OR predicate
|
190
|
+
def initialize(*ored)
|
191
|
+
raise ArgumentError, "Predicates expected" unless ored.all?{|p| Predicate===p}
|
192
|
+
@ored = ored
|
193
|
+
end
|
194
|
+
|
195
|
+
# Predicate implementation
|
196
|
+
def ===(elm)
|
197
|
+
@ored.any?{|p| p===elm}
|
198
|
+
end
|
199
|
+
|
200
|
+
# Pushes _right_ in the ored array
|
201
|
+
def |(right)
|
202
|
+
@ored << Predicate.to_predicate(right)
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
# Helps debugging predicates
|
207
|
+
def inspect
|
208
|
+
@ored.inject('') do |memo,p|
|
209
|
+
if memo.empty?
|
210
|
+
p.inspect
|
211
|
+
else
|
212
|
+
"#{memo} or #{p.inspect}"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
end # class OrPredicate
|
218
|
+
|
219
|
+
class Predicate
|
220
|
+
|
221
|
+
# Predicates that always return true
|
222
|
+
ALL = TruePredicate.new
|
223
|
+
|
224
|
+
# Predicates that always return false
|
225
|
+
NONE = FalsePredicate.new
|
226
|
+
|
227
|
+
end # class Predicate
|
228
|
+
|
229
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Yargi
|
2
|
+
|
3
|
+
# A set of vertices
|
4
|
+
class VertexSet < ElementSet
|
5
|
+
|
6
|
+
### Factory section #######################################################
|
7
|
+
|
8
|
+
# Creates a VertexSet instance using _elements_ varargs.
|
9
|
+
def self.[](*elements)
|
10
|
+
VertexSet.new(elements)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
### Walking section #######################################################
|
15
|
+
|
16
|
+
# Returns incoming edges of all vertices of this set
|
17
|
+
def in_edges(filter=nil, &block)
|
18
|
+
r = self.collect {|v| v.in_edges(filter, &block) }
|
19
|
+
EdgeSet.new(r).flatten.uniq
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns all back-adjacent vertices reachable from this set
|
23
|
+
def in_adjacent(filter=nil, &block)
|
24
|
+
r = self.collect {|v| v.in_adjacent(filter, &block) }
|
25
|
+
VertexSet.new(r).flatten.uniq
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns all outgoing edges of all vertices of this set
|
29
|
+
def out_edges(filter=nil, &block)
|
30
|
+
r = self.collect {|v| v.out_edges(filter, &block) }
|
31
|
+
EdgeSet.new(r).flatten.uniq
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns all forward-adjacent vertices reachable from this set
|
35
|
+
def out_adjacent(filter=nil, &block)
|
36
|
+
r = self.collect {|v| v.out_adjacent(filter, &block) }
|
37
|
+
VertexSet.new(r).flatten.uniq
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns all adjacent vertices reachable from this set
|
41
|
+
def adjacent(filter=nil, &block)
|
42
|
+
(in_adjacent(filter, &block)+out_adjacent(filter, &block)).uniq
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
### Protected section #####################################################
|
47
|
+
protected
|
48
|
+
|
49
|
+
# Extends with VertexSet instead of ElementSet
|
50
|
+
def extend_result(result)
|
51
|
+
VertexSet.new(result)
|
52
|
+
end
|
53
|
+
|
54
|
+
end # module VertexSet
|
55
|
+
|
56
|
+
end
|
data/lib/yargi.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'yargi/predicate'
|
2
|
+
|
3
|
+
module Yargi
|
4
|
+
|
5
|
+
# Current Yargi version
|
6
|
+
VERSION = "0.1.0".freeze
|
7
|
+
|
8
|
+
# When _what_ is not nil, converts it to a predicate (typically a module).
|
9
|
+
# Otherwise, a block is expected, which is converted to a LambdaPredicate.
|
10
|
+
# Otherwise, return ALL.
|
11
|
+
def self.predicate(what=nil, &block)
|
12
|
+
Predicate.to_predicate(what, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Predicates that always return true
|
16
|
+
ALL = Yargi::Predicate.to_predicate(true)
|
17
|
+
|
18
|
+
# Predicates that always return false
|
19
|
+
NONE = Yargi::Predicate.to_predicate(false)
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'yargi/markable'
|
24
|
+
require 'yargi/digraph'
|
25
|
+
require 'yargi/digraph_vertex'
|
26
|
+
require 'yargi/digraph_edge'
|
27
|
+
require 'yargi/element_set'
|
28
|
+
require 'yargi/vertex_set'
|
29
|
+
require 'yargi/edge_set'
|
30
|
+
|
data/test/test_all.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
digraph G {
|
2
|
+
graph[]
|
3
|
+
V0 [shape="circle"label=""]
|
4
|
+
V1 [shape="circle"label=""]
|
5
|
+
V2 [shape="circle"label=""]
|
6
|
+
V3 [shape="circle"label=""]
|
7
|
+
V4 [shape="circle"label=""]
|
8
|
+
V0 -> V0 [label="From 0 to 0"]
|
9
|
+
V0 -> V1 [label="From 0 to 1"]
|
10
|
+
V0 -> V2 [label="From 0 to 2"]
|
11
|
+
V0 -> V3 [label="From 0 to 3"]
|
12
|
+
V0 -> V4 [label="From 0 to 4"]
|
13
|
+
V1 -> V0 [label="From 1 to 0"]
|
14
|
+
V1 -> V1 [label="From 1 to 1"]
|
15
|
+
V1 -> V2 [label="From 1 to 2"]
|
16
|
+
V1 -> V3 [label="From 1 to 3"]
|
17
|
+
V1 -> V4 [label="From 1 to 4"]
|
18
|
+
V2 -> V0 [label="From 2 to 0"]
|
19
|
+
V2 -> V1 [label="From 2 to 1"]
|
20
|
+
V2 -> V2 [label="From 2 to 2"]
|
21
|
+
V2 -> V3 [label="From 2 to 3"]
|
22
|
+
V2 -> V4 [label="From 2 to 4"]
|
23
|
+
V3 -> V0 [label="From 3 to 0"]
|
24
|
+
V3 -> V1 [label="From 3 to 1"]
|
25
|
+
V3 -> V2 [label="From 3 to 2"]
|
26
|
+
V3 -> V3 [label="From 3 to 3"]
|
27
|
+
V3 -> V4 [label="From 3 to 4"]
|
28
|
+
V4 -> V0 [label="From 4 to 0"]
|
29
|
+
V4 -> V1 [label="From 4 to 1"]
|
30
|
+
V4 -> V2 [label="From 4 to 2"]
|
31
|
+
V4 -> V3 [label="From 4 to 3"]
|
32
|
+
V4 -> V4 [label="From 4 to 4"]
|
33
|
+
}
|
Binary file
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'yargi'
|
3
|
+
|
4
|
+
module Yargi
|
5
|
+
|
6
|
+
# Tests all set-based features on graphs
|
7
|
+
class DigraphSetFeaturesTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
module Source; end
|
10
|
+
module Sink; end
|
11
|
+
module Additional; end
|
12
|
+
|
13
|
+
# Installs the souce-sink graph example under @graph
|
14
|
+
def setup
|
15
|
+
@graph = Yargi::Digraph.new
|
16
|
+
sources = @graph.add_n_vertices(5, Source)
|
17
|
+
sinks = @graph.add_n_vertices(5, Sink)
|
18
|
+
@graph.connect(sources, sinks)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_tag
|
22
|
+
@graph.vertices{|v| Source===v}.tag(Additional)
|
23
|
+
@graph.vertices.each {|v| assert_equal((Source===v), (Additional===v))}
|
24
|
+
assert @graph.vertices{|v| Source===v}.all?{|v|Additional===v}
|
25
|
+
assert @graph.vertices{|v| Sink===v}.all?{|v|not(Additional===v)}
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_set_and_get_mark
|
29
|
+
@graph.vertices{|v| Source===v}.set_mark(:kind, :source)
|
30
|
+
@graph.vertices{|v| Sink===v}.set_mark(:kind, :sink)
|
31
|
+
@graph.vertices.each do |v|
|
32
|
+
if Source===v
|
33
|
+
assert_equal :source, v.get_mark(:kind)
|
34
|
+
else
|
35
|
+
assert_equal :sink, v.get_mark(:kind)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_add_marks
|
41
|
+
@graph.vertices{|v| Source===v}.add_marks(:kind => :source, :priority => 1.0)
|
42
|
+
@graph.vertices.each do |v|
|
43
|
+
if Source===v
|
44
|
+
assert_equal :source, v.kind
|
45
|
+
assert_equal 1.0, v.priority
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_add_marks_with_block
|
51
|
+
@graph.vertices{|v| Source===v}.add_marks do |v|
|
52
|
+
v.set_mark(:test, true)
|
53
|
+
{:kind => :source, :priority => 1.0}
|
54
|
+
end
|
55
|
+
@graph.vertices{|v| Source===v}.all? do |v|
|
56
|
+
assert v.test==true
|
57
|
+
assert_equal :source, v.kind
|
58
|
+
assert_equal 1.0, v.priority
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_add_marks_with_both
|
63
|
+
@graph.vertices{|v| Source===v}.add_marks(:test2 => false) do |v|
|
64
|
+
v.set_mark(:test, true)
|
65
|
+
{:kind => :source, :priority => 1.0}
|
66
|
+
end
|
67
|
+
@graph.vertices{|v| Source===v}.all? do |v|
|
68
|
+
assert v.test2==false
|
69
|
+
assert v.test==true
|
70
|
+
assert_equal :source, v.kind
|
71
|
+
assert_equal 1.0, v.priority
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_to_dot
|
76
|
+
@graph.vertices{|v|Source===v}.add_marks(:label => '', :shape => 'diamond', :fixedsize => true, :width => 0.5)
|
77
|
+
@graph.vertices{|v|Sink===v}.add_marks(:label => '', :shape => 'doublecircle', :fixedsize => true, :width => 0.5)
|
78
|
+
@graph.edges.add_marks do |e|
|
79
|
+
{:label => "from #{e.source.index} to #{e.target.index}"}
|
80
|
+
end
|
81
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
82
|
+
dotfile = File.join(dir,"source-sink.dot")
|
83
|
+
gitfile = File.join(dir,"source-sink.gif")
|
84
|
+
File.open(dotfile, 'w') {|f| f << @graph.to_dot}
|
85
|
+
begin
|
86
|
+
`dot -Tgif -o #{gitfile} #{dotfile}`
|
87
|
+
rescue => ex
|
88
|
+
$STDERR << "dot test failed, probably not installed\n#{ex.message}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
end # class DigraphSetFeaturesSet
|
95
|
+
|
96
|
+
end
|