yargi 0.1.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/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
|