ruby_ex 0.1.1
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/AUTHORS +51 -0
- data/ChangeLog +1763 -0
- data/NEWS +3 -0
- data/README +1 -0
- data/Rakefile +8 -0
- data/SPEC.dyn.yml +10 -0
- data/SPEC.gem.yml +269 -0
- data/SPEC.yml +36 -0
- data/src/abstract.rb +253 -0
- data/src/abstract_node.rb +85 -0
- data/src/algorithms.rb +12 -0
- data/src/algorithms/simulated_annealing.rb +142 -0
- data/src/ask.rb +100 -0
- data/src/attributed_class.rb +303 -0
- data/src/cache.rb +350 -0
- data/src/checkout.rb +12 -0
- data/src/choose.rb +271 -0
- data/src/commands.rb +20 -0
- data/src/commands/command.rb +492 -0
- data/src/commands/datas.rb +16 -0
- data/src/commands/datas/composite.rb +31 -0
- data/src/commands/datas/data.rb +65 -0
- data/src/commands/datas/factory.rb +69 -0
- data/src/commands/datas/temp.rb +26 -0
- data/src/commands/factory.rb +67 -0
- data/src/commands/helpers.rb +81 -0
- data/src/commands/pipe.rb +66 -0
- data/src/commands/runners.rb +16 -0
- data/src/commands/runners/exec.rb +50 -0
- data/src/commands/runners/fork.rb +130 -0
- data/src/commands/runners/runner.rb +140 -0
- data/src/commands/runners/system.rb +57 -0
- data/src/commands/seq.rb +32 -0
- data/src/config_file.rb +95 -0
- data/src/const_regexp.rb +57 -0
- data/src/daemon.rb +135 -0
- data/src/diff.rb +665 -0
- data/src/dlogger.rb +62 -0
- data/src/drb/drb_observable.rb +95 -0
- data/src/drb/drb_observable_pool.rb +27 -0
- data/src/drb/drb_service.rb +44 -0
- data/src/drb/drb_undumped_attributes.rb +56 -0
- data/src/drb/drb_undumped_indexed_object.rb +55 -0
- data/src/drb/insecure_protected_methods.rb +101 -0
- data/src/drb_ex.rb +12 -0
- data/src/dumpable_proc.rb +57 -0
- data/src/filetype.rb +229 -0
- data/src/generate_id.rb +44 -0
- data/src/histogram.rb +222 -0
- data/src/hookable.rb +283 -0
- data/src/hooker.rb +54 -0
- data/src/indexed_node.rb +65 -0
- data/src/io_marshal.rb +99 -0
- data/src/ioo.rb +193 -0
- data/src/labeled_node.rb +62 -0
- data/src/logger_observer.rb +24 -0
- data/src/md5sum.rb +70 -0
- data/src/module/autoload_tree.rb +65 -0
- data/src/module/hierarchy.rb +334 -0
- data/src/module/instance_method_visibility.rb +71 -0
- data/src/node.rb +81 -0
- data/src/object_monitor.rb +143 -0
- data/src/object_monitor_activity.rb +34 -0
- data/src/observable.rb +138 -0
- data/src/observable_pool.rb +291 -0
- data/src/orderedhash.rb +252 -0
- data/src/pp_hierarchy.rb +30 -0
- data/src/random_generators.rb +29 -0
- data/src/random_generators/random_generator.rb +33 -0
- data/src/random_generators/ruby.rb +25 -0
- data/src/ruby_ex.rb +124 -0
- data/src/safe_eval.rb +346 -0
- data/src/sendmail.rb +214 -0
- data/src/service_manager.rb +122 -0
- data/src/shuffle.rb +30 -0
- data/src/spring.rb +134 -0
- data/src/spring_set.rb +134 -0
- data/src/symtbl.rb +108 -0
- data/src/synflow.rb +474 -0
- data/src/thread_mutex.rb +11 -0
- data/src/timeout_ex.rb +79 -0
- data/src/trace.rb +26 -0
- data/src/uri/druby.rb +78 -0
- data/src/uri/file.rb +63 -0
- data/src/uri/ftp_ex.rb +36 -0
- data/src/uri/http_ex.rb +41 -0
- data/src/uri/pgsql.rb +136 -0
- data/src/uri/ssh.rb +87 -0
- data/src/uri/svn.rb +113 -0
- data/src/uri_ex.rb +71 -0
- data/src/verbose_object.rb +70 -0
- data/src/yaml/basenode_ext.rb +63 -0
- data/src/yaml/chop_header.rb +24 -0
- data/src/yaml/transform.rb +450 -0
- data/src/yaml/yregexpath.rb +76 -0
- data/test/algorithms/simulated_annealing_test.rb +102 -0
- data/test/check-pkg-ruby_ex.yml +15 -0
- data/test/check-ruby_ex.yml +12 -0
- data/test/resources/autoload_tree/A.rb +11 -0
- data/test/resources/autoload_tree/B.rb +10 -0
- data/test/resources/autoload_tree/foo/C.rb +18 -0
- data/test/resources/foo.txt +6 -0
- data/test/sanity-suite.yml +12 -0
- data/test/sanity/multiple-requires.yml +20 -0
- data/test/sanity/single-requires.yml +24 -0
- data/test/test-unit-setup.rb +6 -0
- data/test/unit-suite.yml +14 -0
- metadata +269 -0
data/src/spring_set.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: spring_set.rb 258 2005-06-01 00:22:51Z ertai $
|
7
|
+
|
8
|
+
|
9
|
+
require 'spring'
|
10
|
+
|
11
|
+
|
12
|
+
class SpringSet
|
13
|
+
|
14
|
+
def initialize(*springs)
|
15
|
+
@springs = {}
|
16
|
+
springs.flatten.each do |s|
|
17
|
+
@springs[s.object_id] = {
|
18
|
+
:spring => s,
|
19
|
+
:num_collecter => s.num_collecter,
|
20
|
+
:size => s.size
|
21
|
+
}
|
22
|
+
s.add_observer(self)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def update(spring_id, msg, collecter_id)
|
27
|
+
case msg
|
28
|
+
when Spring::SIGN_UP
|
29
|
+
@springs[spring_id][:num_collecter] += 1
|
30
|
+
when Spring::GET
|
31
|
+
@springs[spring_id][:size] -= 1 if @springs[spring_id][:size] > 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_most_free
|
36
|
+
calc_stat(:num_collecter) { |a, b| a < b }
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_most_busy
|
40
|
+
calc_stat(:num_collecter) { |a, b| a > b }
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_most_full
|
44
|
+
calc_stat(:size) { |a, b| a > b }
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_most_empty
|
48
|
+
calc_stat(:size) { |a, b| a < b }
|
49
|
+
end
|
50
|
+
|
51
|
+
def size
|
52
|
+
@springs.size
|
53
|
+
end
|
54
|
+
|
55
|
+
alias length size
|
56
|
+
|
57
|
+
def num_collecter(spring_id)
|
58
|
+
@springs[spring_id][:num_collecter]
|
59
|
+
end
|
60
|
+
|
61
|
+
def spring_size(spring_id)
|
62
|
+
@springs[spring_id][:size]
|
63
|
+
end
|
64
|
+
|
65
|
+
alias spring_length spring_size
|
66
|
+
|
67
|
+
def each
|
68
|
+
@springs.values.each { |v| yield(v[:spring]) }
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
def calc_stat(field, &cmp)
|
73
|
+
spring = nil
|
74
|
+
@springs.values.each do |s|
|
75
|
+
if spring.nil? or cmp[s[field], spring[field]]
|
76
|
+
spring = s
|
77
|
+
end
|
78
|
+
end
|
79
|
+
return spring[:spring]
|
80
|
+
end
|
81
|
+
|
82
|
+
end # class SpringSet
|
83
|
+
|
84
|
+
|
85
|
+
#
|
86
|
+
# Unit test suite
|
87
|
+
#
|
88
|
+
test_section __FILE__ do
|
89
|
+
|
90
|
+
|
91
|
+
class SpringSetTest < Test::Unit::TestCase
|
92
|
+
|
93
|
+
#
|
94
|
+
# tests
|
95
|
+
#
|
96
|
+
def test_simple
|
97
|
+
s1 = Spring.new('hello', 'world')
|
98
|
+
s2 = Spring.new('bonjour', 'tout', 'monde')
|
99
|
+
s = SpringSet.new(s1, s2)
|
100
|
+
assert_equal(s1.num_collecter, s.num_collecter(s1.object_id))
|
101
|
+
assert_equal(s2.num_collecter, s.num_collecter(s2.object_id))
|
102
|
+
assert_equal(s1.size, s.spring_size(s1.object_id))
|
103
|
+
assert_equal(s2.length, s.spring_length(s2.object_id))
|
104
|
+
thread = Thread.new do
|
105
|
+
sleep(0.0001)
|
106
|
+
assert_equal(2, s.size)
|
107
|
+
assert_equal(2, s.length)
|
108
|
+
assert_equal(s2, s.get_most_full)
|
109
|
+
assert_equal(s1, s.get_most_empty)
|
110
|
+
s1.sign_up(thread.object_id)
|
111
|
+
assert_equal(s1.num_collecter, s.num_collecter(s1.object_id))
|
112
|
+
assert_equal(s1, s.get_most_busy)
|
113
|
+
assert_equal(s2, s.get_most_free)
|
114
|
+
s2.sign_up(thread.object_id)
|
115
|
+
assert_equal(s2.num_collecter, s.num_collecter(s2.object_id), 'bad num collecter')
|
116
|
+
assert_equal('bonjour', s2.get(thread.object_id))
|
117
|
+
assert_equal(s2.size, s.spring_size(s2.object_id), 'bad size')
|
118
|
+
assert_equal('tout', s2.get(thread.object_id))
|
119
|
+
assert_equal(s2.size, s.spring_size(s2.object_id))
|
120
|
+
assert_equal('monde', s2.get(thread.object_id))
|
121
|
+
assert_equal(s2.size, s.spring_size(s2.object_id))
|
122
|
+
assert_equal(nil, s2.get(thread.object_id))
|
123
|
+
assert_equal(s2.size, s.spring_size(s2.object_id))
|
124
|
+
assert_equal(0, s.spring_size(s2.object_id))
|
125
|
+
assert_equal(s1, s.get_most_full)
|
126
|
+
assert_equal(s2, s.get_most_empty)
|
127
|
+
end
|
128
|
+
thread.join
|
129
|
+
end
|
130
|
+
|
131
|
+
end # class SpringSetTest
|
132
|
+
|
133
|
+
|
134
|
+
end
|
data/src/symtbl.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# Author: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
2
|
+
# Copyright: Copyright (c) 2004 Nicolas Pouillard. All rights reserved.
|
3
|
+
# License: Ruby license.
|
4
|
+
|
5
|
+
# $LastChangedBy: ertai $
|
6
|
+
# $Id: symtbl.rb 266 2005-06-01 14:27:18Z ertai $
|
7
|
+
|
8
|
+
require 'ruby_ex'
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
class SymTbl
|
12
|
+
|
13
|
+
@@sid = -1
|
14
|
+
|
15
|
+
attr_reader :sid, :local, :father
|
16
|
+
|
17
|
+
def initialize ( father_env=nil, default=nil )
|
18
|
+
@father = father_env
|
19
|
+
@sid = (@@sid += 1)
|
20
|
+
@local = Hash.new(default)
|
21
|
+
end
|
22
|
+
|
23
|
+
def [] ( aKey )
|
24
|
+
if @local.has_key? aKey
|
25
|
+
@local[aKey]
|
26
|
+
elsif @father.nil?
|
27
|
+
@local.default
|
28
|
+
else
|
29
|
+
@father[aKey]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def []= ( aKey, aValue )
|
34
|
+
@local[aKey] = aValue
|
35
|
+
end
|
36
|
+
|
37
|
+
# FIXME
|
38
|
+
def each ( &block )
|
39
|
+
key_set = Set.new
|
40
|
+
blk = lambda do |k,v|
|
41
|
+
block[k, v] unless key_set.include? k
|
42
|
+
key_set << k
|
43
|
+
end
|
44
|
+
@local.each(&blk)
|
45
|
+
@father.each(&blk) unless @father.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
def ancestors
|
49
|
+
(@father.is_a?(SymTbl))? [self] + @father.ancestors : [self]
|
50
|
+
end
|
51
|
+
|
52
|
+
def desc_one
|
53
|
+
if defined? @already_described
|
54
|
+
return sid
|
55
|
+
else
|
56
|
+
@already_described = true
|
57
|
+
return { sid => @local }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def desc
|
62
|
+
ancestors.map{ |s| s.desc_one }.to_yaml
|
63
|
+
end
|
64
|
+
|
65
|
+
end # class SymTbl
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
test_section __FILE__ do
|
70
|
+
|
71
|
+
require 'ruby_ex'
|
72
|
+
class SymTblTest < Test::Unit::TestCase
|
73
|
+
|
74
|
+
def test1
|
75
|
+
root = SymTbl.new
|
76
|
+
|
77
|
+
root[:a] = 0
|
78
|
+
root[:b] = 1
|
79
|
+
|
80
|
+
assert_equal(1, root[:b], 't1')
|
81
|
+
assert_equal(0, root[:a], 't2')
|
82
|
+
|
83
|
+
sub1 = SymTbl.new(root)
|
84
|
+
|
85
|
+
sub1[:a] = 2
|
86
|
+
sub1[:c] = 3
|
87
|
+
|
88
|
+
assert_equal(1, sub1[:b], 't3')
|
89
|
+
assert_equal(2, sub1[:a], 't4')
|
90
|
+
assert_equal(3, sub1[:c], 't5')
|
91
|
+
|
92
|
+
assert_equal(0, root[:a], 't6')
|
93
|
+
|
94
|
+
sub2 = SymTbl.new(sub1)
|
95
|
+
|
96
|
+
assert_equal(2, sub2[:a], 't7')
|
97
|
+
|
98
|
+
sub2[:a] = 42
|
99
|
+
|
100
|
+
assert_equal(42, sub2[:a], 't8')
|
101
|
+
|
102
|
+
assert_equal([{2=>{:a=>42}}, {1=>{:a=>2, :c=>3}}, {0=>{:b=>1, :a=>0}}],
|
103
|
+
YAML::load(sub2.desc))
|
104
|
+
end
|
105
|
+
|
106
|
+
end # class SymTblTest
|
107
|
+
|
108
|
+
end
|
data/src/synflow.rb
ADDED
@@ -0,0 +1,474 @@
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Pouillard. All rights reserved.
|
2
|
+
# Author: Nicolas Pouillard <ertai@lrde.epita.fr>.
|
3
|
+
# License: Gnu General Public License.
|
4
|
+
|
5
|
+
# $LastChangedBy$
|
6
|
+
# $Id$
|
7
|
+
|
8
|
+
#
|
9
|
+
# Efficients control flows for synchronisation (and mutual exclusion) in
|
10
|
+
# parallel systems.
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'ruby_ex'
|
14
|
+
require 'thread'
|
15
|
+
require 'set'
|
16
|
+
|
17
|
+
#
|
18
|
+
# The +SynFlowFactory+ define the common part for a set of flows.
|
19
|
+
#
|
20
|
+
# A SynFlow is like an automaton (finite state machine):
|
21
|
+
# * states
|
22
|
+
# * transitions
|
23
|
+
# * an alphabet
|
24
|
+
# * an initial state
|
25
|
+
# * a set of final states
|
26
|
+
#
|
27
|
+
# With this automaton (diagram, graph...) you can easily describe important
|
28
|
+
# steps of your program control flow.
|
29
|
+
#
|
30
|
+
# Your automaton describe a model of execution and constraint every execution
|
31
|
+
# to it.
|
32
|
+
#
|
33
|
+
# When a thread want to change the state of its flow it proceed like that:
|
34
|
+
# flow << :a_symbol_of_the_alphabet
|
35
|
+
#
|
36
|
+
# If a transition between the _current_ state and a state _destination_ is
|
37
|
+
# labeled by _symbol_, then the state is updated to _destination_.
|
38
|
+
# Otherwise the thread is constraint to wait the modification of the _current_
|
39
|
+
# state.
|
40
|
+
#
|
41
|
+
# See examples below to know how to use these class.
|
42
|
+
#
|
43
|
+
class SynFlowFactory
|
44
|
+
|
45
|
+
class Transition
|
46
|
+
attr_reader :src, :dest, :label
|
47
|
+
|
48
|
+
def initialize ( src, label, dest )
|
49
|
+
@src, @label, @dest = src, label, dest
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_a
|
53
|
+
[@src, @label, @dest]
|
54
|
+
end
|
55
|
+
|
56
|
+
def == ( rhs )
|
57
|
+
rhs.is_a? self.class and
|
58
|
+
@label == rhs.label and
|
59
|
+
@dest == rhs.dest and
|
60
|
+
@src == rhs.src
|
61
|
+
end
|
62
|
+
end # class Transition
|
63
|
+
|
64
|
+
|
65
|
+
class TransitionSet
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
@val = {}
|
69
|
+
end
|
70
|
+
|
71
|
+
def include? ( *a )
|
72
|
+
case a.size
|
73
|
+
when 1
|
74
|
+
t = a[0]
|
75
|
+
case t
|
76
|
+
when Array
|
77
|
+
return include?(*t)
|
78
|
+
else
|
79
|
+
return delta(t.src, t.label) == t.dest
|
80
|
+
end
|
81
|
+
when 2
|
82
|
+
state, label = a
|
83
|
+
return ! delta(state, label).nil?
|
84
|
+
when 3
|
85
|
+
state, label, dest = a
|
86
|
+
return delta(state, label) == dest
|
87
|
+
else
|
88
|
+
raise ArgumentError, 'bad transition'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def add ( src, label, dest )
|
93
|
+
@val[src] ||= {}
|
94
|
+
@val[src][label] = dest
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_transition ( t )
|
98
|
+
add(t.src, t.label, t.dest)
|
99
|
+
end
|
100
|
+
|
101
|
+
def delta ( src, label )
|
102
|
+
@val[src] ||= {}
|
103
|
+
@val[src][label]
|
104
|
+
end
|
105
|
+
|
106
|
+
def << ( transition )
|
107
|
+
case transition
|
108
|
+
when Array
|
109
|
+
add(*transition)
|
110
|
+
when Hash
|
111
|
+
transition.each do |src, x|
|
112
|
+
unless x.is_a? Hash
|
113
|
+
raise TypeError, "bad transtion: #{transition.inspect}"
|
114
|
+
end
|
115
|
+
x.each do |label, dest|
|
116
|
+
add(src, label, dest)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
when Transition
|
120
|
+
add_transition(transition)
|
121
|
+
else
|
122
|
+
raise TypeError, "bad transtion: #{transition.inspect}"
|
123
|
+
end
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
end # class TransitionSet
|
128
|
+
|
129
|
+
|
130
|
+
attr_accessor :initial, :transitions
|
131
|
+
|
132
|
+
|
133
|
+
def initialize
|
134
|
+
@transitions = TransitionSet.new
|
135
|
+
@initial = nil
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
def << ( transition )
|
140
|
+
@transitions << transition
|
141
|
+
self
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def include? ( *transition )
|
146
|
+
@transitions.include?(*transition)
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def delta ( src, label )
|
151
|
+
@transitions.delta(src, label)
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
def new_flow
|
156
|
+
SynFlow.new(self, @initial)
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
def initial? ( state )
|
161
|
+
state == @initial
|
162
|
+
end
|
163
|
+
|
164
|
+
end # class SynFlowFactory
|
165
|
+
|
166
|
+
|
167
|
+
class SynFlow
|
168
|
+
|
169
|
+
class Error < Exception
|
170
|
+
end
|
171
|
+
|
172
|
+
attr_reader :state
|
173
|
+
attr_reader :i
|
174
|
+
|
175
|
+
@@i = -1
|
176
|
+
def initialize ( factory, initial_state )
|
177
|
+
@i = (@@i += 1)
|
178
|
+
super()
|
179
|
+
@mutex = Mutex.new
|
180
|
+
@condition = ConditionVariable.new
|
181
|
+
@factory = factory
|
182
|
+
@state = initial_state
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
def feed ( label )
|
187
|
+
D "#@i: Want read label #{label} (#@state)"
|
188
|
+
@mutex.synchronize do
|
189
|
+
while not @factory.include?(@state, label)
|
190
|
+
begin
|
191
|
+
@condition.wait(@mutex)
|
192
|
+
rescue ThreadError
|
193
|
+
raise Error,
|
194
|
+
'Cannot wait for change state because only one thread is running'
|
195
|
+
end
|
196
|
+
end
|
197
|
+
dest = @factory.delta(@state, label)
|
198
|
+
D "#@i: Ok change state with label #{label} (#@state -> #{dest})"
|
199
|
+
@state = dest
|
200
|
+
@condition.broadcast
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
alias advance feed
|
205
|
+
alias << feed
|
206
|
+
|
207
|
+
|
208
|
+
def try_feed ( label )
|
209
|
+
D "#@i: Try read label #{label} (#@state)"
|
210
|
+
if @mutex.try_lock
|
211
|
+
begin
|
212
|
+
if @factory.include?(@state, label)
|
213
|
+
dest = @factory.delta(@state, label)
|
214
|
+
D "#@i: Ok change state with label #{label} (#@state -> #{dest})"
|
215
|
+
@state = dest
|
216
|
+
@condition.broadcast
|
217
|
+
return true
|
218
|
+
end
|
219
|
+
ensure
|
220
|
+
@mutex.unlock
|
221
|
+
end
|
222
|
+
end
|
223
|
+
D "#@i: Ko you cannot change state"
|
224
|
+
return false
|
225
|
+
end
|
226
|
+
|
227
|
+
alias try_advance try_feed
|
228
|
+
|
229
|
+
|
230
|
+
def destroy
|
231
|
+
@i = @mutex = @condition = @factory = @state = nil
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
@@out = []
|
236
|
+
|
237
|
+
def self.debug_out
|
238
|
+
@@out
|
239
|
+
end
|
240
|
+
|
241
|
+
def D ( msg )
|
242
|
+
# @@out << msg
|
243
|
+
# STDERR.puts msg
|
244
|
+
end
|
245
|
+
private :D
|
246
|
+
|
247
|
+
end # class SynFlow
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
test_section __FILE__ do
|
252
|
+
|
253
|
+
require 'timeout'
|
254
|
+
|
255
|
+
|
256
|
+
class SynFlowTest < Test::Unit::TestCase
|
257
|
+
|
258
|
+
T = SynFlowFactory::Transition
|
259
|
+
TSet = SynFlowFactory::TransitionSet
|
260
|
+
|
261
|
+
def test_aa_simple_transition
|
262
|
+
assert_equal(T.new(:a, :b, :c), T.new(:a, :b, :c))
|
263
|
+
assert_not_equal(T.new(:b, :a, :c), T.new(:a, :b, :d))
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_ab_simple_transition_set
|
267
|
+
s = TSet.new
|
268
|
+
s << T.new(:a, :b, :c) << T.new(:b, :a, :d) << [:e, :f, :g]
|
269
|
+
assert(s.include?(:a, :b))
|
270
|
+
assert(s.include?(T.new(:a, :b, :c)))
|
271
|
+
assert(s.include?(:b, :a, :d))
|
272
|
+
assert(s.include?([:e, :f]))
|
273
|
+
end
|
274
|
+
|
275
|
+
def test_ac_bad_transition_set
|
276
|
+
s = TSet.new
|
277
|
+
s << T.new(:a, :b, :c) << T.new(:b, :a, :d)
|
278
|
+
assert(! s.include?(T.new(:b, :b, :c)))
|
279
|
+
assert(! s.include?(:a, :d, :c))
|
280
|
+
assert(! s.include?([:c, :b]))
|
281
|
+
end
|
282
|
+
|
283
|
+
#
|
284
|
+
# g
|
285
|
+
# +---------------------------+
|
286
|
+
# | |
|
287
|
+
# v a b c d |
|
288
|
+
# 1 ---> 2 ---> 3 ---> 4 ---> 5
|
289
|
+
# | ^
|
290
|
+
# | e f |
|
291
|
+
# +----> 6 -----+
|
292
|
+
#
|
293
|
+
def make_simple_factory
|
294
|
+
f = SynFlowFactory.new
|
295
|
+
f << [1, :a, 2] \
|
296
|
+
<< [6, :f, 4] \
|
297
|
+
<< SynFlowFactory::Transition.new(3, :c, 4)
|
298
|
+
f << { 2 => { :e => 6, :b => 3 },
|
299
|
+
4 => { :d => 5 },
|
300
|
+
5 => { :g => 1 }
|
301
|
+
}
|
302
|
+
f.initial = 1
|
303
|
+
return f
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_ad_simple_factory
|
307
|
+
f = nil
|
308
|
+
assert_nothing_raised do
|
309
|
+
f = make_simple_factory
|
310
|
+
end
|
311
|
+
transitions =
|
312
|
+
[[1, :a, 2],
|
313
|
+
[6, :f, 4],
|
314
|
+
[3, :c, 4],
|
315
|
+
[2, :e, 6],
|
316
|
+
[2, :b, 3],
|
317
|
+
[4, :d, 5],
|
318
|
+
[5, :g, 1]]
|
319
|
+
transitions.each do |s, l, d|
|
320
|
+
assert(f.transitions.include?(s, l, d))
|
321
|
+
end
|
322
|
+
|
323
|
+
assert(! f.transitions.include?(1, :a, 3))
|
324
|
+
assert(! f.transitions.include?(2, :a))
|
325
|
+
assert(! f.transitions.include?(1, :a, 1))
|
326
|
+
|
327
|
+
assert(f.initial?(1))
|
328
|
+
assert(! f.initial?(2))
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_ba_simple_flow
|
332
|
+
f = make_simple_factory
|
333
|
+
m = nil
|
334
|
+
assert_nothing_raised { m = f.new_flow }
|
335
|
+
assert_nothing_raised do
|
336
|
+
Timeout.timeout(2) do
|
337
|
+
assert_equal(1, m.state)
|
338
|
+
m << :a
|
339
|
+
assert_equal(2, m.state)
|
340
|
+
m << :b
|
341
|
+
assert_equal(3, m.state)
|
342
|
+
m << :c
|
343
|
+
assert_equal(4, m.state)
|
344
|
+
m << :d
|
345
|
+
assert_equal(5, m.state)
|
346
|
+
m << :g
|
347
|
+
assert_equal(1, m.state)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def test_bb_simple_loop
|
353
|
+
f = make_simple_factory
|
354
|
+
f << [6, :e, 6]
|
355
|
+
m = f.new_flow
|
356
|
+
assert_nothing_raised do
|
357
|
+
Timeout.timeout(2) do
|
358
|
+
assert_equal(1, m.state)
|
359
|
+
m << :a
|
360
|
+
assert_equal(2, m.state)
|
361
|
+
m << :e
|
362
|
+
assert_equal(6, m.state)
|
363
|
+
m << :e
|
364
|
+
assert_equal(6, m.state)
|
365
|
+
m << :f
|
366
|
+
assert_equal(4, m.state)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_bc_simple_try_advance
|
372
|
+
f = make_simple_factory
|
373
|
+
m = f.new_flow
|
374
|
+
assert_nothing_raised do
|
375
|
+
Timeout.timeout(2) do
|
376
|
+
assert(m.try_advance(:a))
|
377
|
+
assert_equal(2, m.state)
|
378
|
+
m << :b
|
379
|
+
assert_equal(3, m.state)
|
380
|
+
assert(! m.try_advance(:e))
|
381
|
+
assert_equal(3, m.state)
|
382
|
+
m << :c
|
383
|
+
assert_equal(4, m.state)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_c_avanced_flow
|
389
|
+
f = make_simple_factory
|
390
|
+
m = f.new_flow
|
391
|
+
th = Thread.new { sleep ; m << :e }
|
392
|
+
assert_raise(Timeout::Error) do
|
393
|
+
Timeout.timeout(0.2) do
|
394
|
+
th.wakeup
|
395
|
+
th.join
|
396
|
+
end
|
397
|
+
end
|
398
|
+
assert_nothing_raised do
|
399
|
+
Timeout.timeout(2) do
|
400
|
+
m << :a
|
401
|
+
sleep 0.1
|
402
|
+
assert_equal(6, m.state)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
assert_nothing_raised do
|
406
|
+
Timeout.timeout(2) do
|
407
|
+
m << :f
|
408
|
+
assert_equal(4, m.state)
|
409
|
+
m << :d
|
410
|
+
assert_equal(5, m.state)
|
411
|
+
m << :g
|
412
|
+
assert_equal(1, m.state)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def test_d_multi_threads
|
418
|
+
f = make_simple_factory
|
419
|
+
m = f.new_flow
|
420
|
+
|
421
|
+
assert_nothing_raised do
|
422
|
+
Timeout.timeout(5) do
|
423
|
+
t = []
|
424
|
+
t << Thread.new { m << :d }
|
425
|
+
t << Thread.new { m << :c }
|
426
|
+
t << Thread.new { m << :a }
|
427
|
+
t << Thread.new { m << :b }
|
428
|
+
t.each { |t| t.join }
|
429
|
+
end
|
430
|
+
end
|
431
|
+
assert_equal(5, m.state)
|
432
|
+
end
|
433
|
+
|
434
|
+
class E < Exception
|
435
|
+
end
|
436
|
+
|
437
|
+
def test_e_with_block
|
438
|
+
f = make_simple_factory
|
439
|
+
m = f.new_flow
|
440
|
+
|
441
|
+
assert_nothing_raised do
|
442
|
+
Timeout.timeout(5) do
|
443
|
+
t1 = Thread.new do
|
444
|
+
sleep
|
445
|
+
m << :a
|
446
|
+
sleep
|
447
|
+
end
|
448
|
+
t2 = Thread.new do
|
449
|
+
m << :e
|
450
|
+
t1.raise E
|
451
|
+
end
|
452
|
+
t1.wakeup
|
453
|
+
t2.join
|
454
|
+
assert_raise(E) { t1.join }
|
455
|
+
end
|
456
|
+
end
|
457
|
+
assert_equal(6, m.state)
|
458
|
+
end
|
459
|
+
|
460
|
+
def test_f_dumpable
|
461
|
+
f = make_simple_factory
|
462
|
+
m = f.new_flow
|
463
|
+
|
464
|
+
assert_nothing_raised do
|
465
|
+
Marshal.load(Marshal.dump(m))
|
466
|
+
end
|
467
|
+
assert_nothing_raised do
|
468
|
+
Marshal.load(Marshal.dump(f))
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
end # class SynFlowTest
|
473
|
+
|
474
|
+
end
|