hegemon 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/hegemon.rb +195 -32
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b434952e8994ae0a8d76f3892f7519a3ef21fbd
|
4
|
+
data.tar.gz: dfcfaf716ddaefe24334316dbc03597bdb42150f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd1b9994151efd8aa79065d1f3cf96753661d17d57ee317ec2deb5d948cce280013996f1516eefca9353d0c082de73aca8417d683315f83ae879242849098d70
|
7
|
+
data.tar.gz: 138a26699c3523e855e554bb71f555f9154d8d11d66c086586cd19ec3208e1d7169a6f61ef43126df41476ffce105f15fa7cd1a3520cb064478eab3a407a7dcc
|
data/lib/hegemon.rb
CHANGED
@@ -4,53 +4,170 @@ Thread.abort_on_exception = true
|
|
4
4
|
|
5
5
|
module Hegemon
|
6
6
|
|
7
|
-
|
8
|
-
# Accessor
|
9
|
-
|
7
|
+
##
|
8
|
+
# :section: Accessor Methods
|
9
|
+
#
|
10
10
|
|
11
|
+
# Return the current state (as a symbol)
|
11
12
|
def state; @_hegemon_state; end
|
13
|
+
# Return the list of declared states (as an array of symbols)
|
12
14
|
def states; @_hegemon_states.keys; end
|
15
|
+
# Return the current state (as a HegemonState object)
|
13
16
|
def state_obj; @_hegemon_states[@_hegemon_state]; end
|
17
|
+
# Return the current state (as a Hash of HegemonState objects keyed by symbol)
|
14
18
|
def state_objs; @_hegemon_states.clone; end
|
15
19
|
|
16
|
-
threadlock :state, :states, :state_obj, :state_objs, :lock=>:@_hegemon_lock
|
20
|
+
# threadlock :state, :states, :state_obj, :state_objs, :lock=>:@_hegemon_lock
|
17
21
|
|
18
|
-
#***
|
19
|
-
# Declarative functions
|
20
|
-
#***
|
21
|
-
# Run these inside of your object's #initialize method
|
22
|
-
# to set the parameters of the state machine
|
23
|
-
# All user-provided action blocks will have the scope of the instance object
|
24
|
-
# in which the state machine parameters are initialized, and all parameters
|
25
|
-
# should be initialized in the same place (in #initialize, typically)
|
26
|
-
#***
|
27
22
|
|
28
|
-
##
|
29
|
-
# Bypass all transition requirements and actions to directly impose state +s+
|
30
|
-
# This should not be used in the public API except to set the initial state
|
31
|
-
def impose_state(s); @_hegemon_state = s; end
|
32
|
-
threadlock :impose_state, :lock=>:@_hegemon_lock
|
33
23
|
|
34
24
|
##
|
35
|
-
#
|
36
|
-
#
|
37
|
-
|
38
|
-
#
|
25
|
+
# :section: Declarative Methods
|
26
|
+
#
|
27
|
+
|
28
|
+
#
|
29
|
+
# Declare a state in the state machine.
|
30
|
+
# Returns the HegemonState object created.
|
31
|
+
#
|
32
|
+
# [+state+]
|
33
|
+
# The state name to use, as a symbol
|
34
|
+
# [+block+]
|
35
|
+
# The state's declarative block.
|
36
|
+
# All code within gets evaluated not in its original binding,
|
37
|
+
# but in the context of a new HegemonState instance object.
|
38
|
+
# For stable use, only call methods in this block that are
|
39
|
+
# listed in HegemonState@Declarative+Methods.
|
40
|
+
#
|
41
|
+
# The state and associated state machine data and methods will be
|
42
|
+
# associated with the object referred to by +self+ object in the context
|
43
|
+
# in which the declarative method is called.
|
44
|
+
#
|
45
|
+
# This means that in typical usage, the declarative methods listed
|
46
|
+
# in Hegemon@Declarative+Methods (including declare_state) should be
|
47
|
+
# called only from within an instance method, such as +initialize+.
|
48
|
+
#
|
49
|
+
# The following example creates a skeleton state machine in each
|
50
|
+
# +MyStateMachine+ instance object with two states: +:working+ and +:idle+.
|
51
|
+
#
|
52
|
+
# require 'hegemon'
|
53
|
+
#
|
54
|
+
# class MyStateMachine
|
55
|
+
# include Hegemon
|
56
|
+
#
|
57
|
+
# def initialize
|
58
|
+
# declare_state :working do
|
59
|
+
# # various HegemonState Declarative Methods
|
60
|
+
# end
|
61
|
+
# declare_state :idle do
|
62
|
+
# # various HegemonState Declarative Methods
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
#
|
39
67
|
def declare_state(state, &block)
|
40
68
|
@_hegemon_states ||= Hash.new
|
41
69
|
@_hegemon_states[state] = HegemonState.new(self, state, &block)
|
42
70
|
end
|
43
71
|
threadlock :declare_state, :lock=>:@_hegemon_lock
|
44
72
|
|
45
|
-
|
46
|
-
|
73
|
+
|
74
|
+
#
|
75
|
+
# Bypass all transition requirements and actions to
|
76
|
+
# directly impose state +state+ as the current state.
|
77
|
+
#
|
78
|
+
# This should *not* be used in the public API *except* to
|
79
|
+
# set the initial state of the state machine, because state changes
|
80
|
+
# imposed by impose_state do not obey any rules of the state machine.
|
81
|
+
#
|
82
|
+
# [+state+]
|
83
|
+
# The state to impose, as a symbol
|
84
|
+
#
|
85
|
+
# This method should be called in the same scope in which the state
|
86
|
+
# was declared with declare_state\.
|
87
|
+
#
|
88
|
+
# The following example creates a skeleton state machine in each
|
89
|
+
# +MyStateMachine+ instance object with two states: +:working+ and +:idle+
|
90
|
+
# and sets +:working+ as the initial state.
|
91
|
+
#
|
92
|
+
# require 'hegemon'
|
93
|
+
#
|
94
|
+
# class MyStateMachine
|
95
|
+
# include Hegemon
|
96
|
+
#
|
97
|
+
# def initialize
|
98
|
+
# impose_state :working
|
99
|
+
# declare_state :working do
|
100
|
+
# # various HegemonState Declarative Methods
|
101
|
+
# end
|
102
|
+
# declare_state :idle do
|
103
|
+
# # various HegemonState Declarative Methods
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
# end
|
107
|
+
def impose_state(s) # :args: state
|
108
|
+
@_hegemon_state = s
|
109
|
+
nil end
|
110
|
+
threadlock :impose_state, :lock=>:@_hegemon_lock
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
##
|
115
|
+
# :section: State Action Methods
|
116
|
+
#
|
117
|
+
|
118
|
+
#
|
119
|
+
# Request a transition from the current state to state +state+.
|
120
|
+
# Returns +true+ if the transition was performed, else returns +false+.
|
121
|
+
#
|
122
|
+
# [+state+]
|
123
|
+
# The state to which transition is desired, as a symbol
|
124
|
+
# [+flags+]
|
125
|
+
# All subsequent arguments are interpreted as flags,
|
126
|
+
# and the only meaningful flag is +:force+
|
127
|
+
# (See transition requirements below).
|
128
|
+
#
|
129
|
+
# In order for the transition to occur, the transition must
|
130
|
+
# have been defined (using HegemonState#transition_to), and the
|
131
|
+
# transition rules declared in the HegemonTransition declarative block
|
132
|
+
# have been suitably met by any one of the following situations:
|
133
|
+
# * *All* HegemonTransition#requirement blocks evaluate as +true+
|
134
|
+
# and the +:force+ flag was included in +flags+.
|
135
|
+
# * At least *one* HegemonTransition#sufficient block and *all*
|
136
|
+
# HegemonTransition#requirement blocks evaluate as +true+
|
137
|
+
# * *All* HegemonTransition#condition blocks and *all*
|
138
|
+
# HegemonTransition#requirement blocks evaluate as +true+
|
139
|
+
#
|
140
|
+
# Note that evaluation of the rule blocks stops when a match is found,
|
141
|
+
# so rule blocks with code that has "side effects" are discouraged.
|
142
|
+
#
|
143
|
+
def request_state(s, *flags) # :args: state, *flags
|
47
144
|
return false unless @_hegemon_states[@_hegemon_state].transitions[s]
|
48
145
|
@_hegemon_states[@_hegemon_state].transitions[s].try(*flags)
|
49
146
|
end
|
50
147
|
threadlock :request_state, :lock=>:@_hegemon_lock
|
51
148
|
|
52
|
-
#
|
53
|
-
#
|
149
|
+
#
|
150
|
+
# Check the list of possible transitions from the current state
|
151
|
+
# and perform the first transition that is found to be ready, if any.
|
152
|
+
# Returns +true+ if the transition was performed, else returns +false+.
|
153
|
+
#
|
154
|
+
# [+flags+]
|
155
|
+
# All subsequent arguments are interpreted as flags,
|
156
|
+
# and the only meaningful flag is +:only_auto+.
|
157
|
+
# Use of the +:only_auto+ flag indicates that all state
|
158
|
+
# transitions which have disabled automatic updating with
|
159
|
+
# HegemonTransition#auto_update should be ignored.
|
160
|
+
#
|
161
|
+
# In order for a transition to occur, the transition rules
|
162
|
+
# declared in the HegemonTransition declarative block have been
|
163
|
+
# suitably met by any one of the following situations:
|
164
|
+
# * *All* HegemonTransition#requirement blocks evaluate as +true+
|
165
|
+
# and the +:force+ flag was included in +flags+.
|
166
|
+
# * At least *one* HegemonTransition#sufficient block and *all*
|
167
|
+
# HegemonTransition#requirement blocks evaluate as +true+
|
168
|
+
# * *All* HegemonTransition#condition blocks and *all*
|
169
|
+
# HegemonTransition#requirement blocks evaluate as +true+
|
170
|
+
#
|
54
171
|
def update_state(*flags)
|
55
172
|
return false unless @_hegemon_states[@_hegemon_state]
|
56
173
|
trans = @_hegemon_states[@_hegemon_state].transitions
|
@@ -59,48 +176,94 @@ module Hegemon
|
|
59
176
|
false end
|
60
177
|
threadlock :update_state, :lock=>:@_hegemon_lock
|
61
178
|
|
62
|
-
|
179
|
+
#
|
180
|
+
# Sleep the current thread until the current state is equal to +state+
|
181
|
+
#
|
182
|
+
# [+state+]
|
183
|
+
# The symbol to compare against the current state against
|
184
|
+
#
|
185
|
+
def block_until_state(s); # :args: state
|
63
186
|
raise ArgumentError, "Cannot block until undefined state :#{s}" \
|
64
187
|
unless @_hegemon_states.keys.include? s
|
65
188
|
sleep 0 until @_hegemon_state==s
|
66
|
-
end
|
189
|
+
nil end
|
67
190
|
|
68
|
-
|
191
|
+
#
|
192
|
+
# Perform all HegemonState#task\s associated with the current state.
|
193
|
+
# Tasks are performed in the order they were declared in the
|
194
|
+
# HegemonState declarative block.
|
195
|
+
#
|
196
|
+
# [+iter_num+ = 0]
|
197
|
+
# Specify the iteration number to be passed to the task block.
|
198
|
+
# When called by the +hegemon_auto_thread+ (see start_hegemon_auto_thread),
|
199
|
+
# this number counts up from zero for each iteration of the
|
200
|
+
# +hegemon_auto_thread+ loop. If no value is specified, +0+ is used.
|
201
|
+
#
|
202
|
+
def do_state_tasks(iter_num = 0)
|
69
203
|
return nil unless @_hegemon_states[@_hegemon_state]
|
70
|
-
@_hegemon_states[@_hegemon_state].do_tasks(
|
204
|
+
@_hegemon_states[@_hegemon_state].do_tasks(iter_num)
|
71
205
|
nil end
|
72
206
|
threadlock :do_state_tasks, :lock=>:@_hegemon_lock
|
73
207
|
|
208
|
+
|
209
|
+
|
210
|
+
##
|
211
|
+
# :section: Thread Action Methods
|
212
|
+
#
|
213
|
+
|
74
214
|
def iter_hegemon_auto_loop(i=0)
|
75
215
|
do_state_tasks(i)
|
76
216
|
update_state(:only_auto)
|
77
217
|
end
|
218
|
+
private :iter_hegemon_auto_loop
|
78
219
|
threadlock :iter_hegemon_auto_loop, :lock=>:@_hegemon_lock
|
79
220
|
|
80
|
-
#
|
81
|
-
|
221
|
+
#
|
222
|
+
# Run the +hegemon_auto_thread+ if it is not already running.
|
223
|
+
# Returns the Thread object.
|
224
|
+
# The +hegemon_auto_thread+ continually calls do_state_tasks and update_state,
|
225
|
+
# counting up from +0+ the value passed to do_state_tasks, until the
|
226
|
+
# thread is stopped with end_hegemon_auto_thread\.
|
227
|
+
#
|
228
|
+
# [+throttle = 0.1+]
|
229
|
+
# The amount of time to sleep between iterations, 0.1 seconds by default.
|
230
|
+
#
|
231
|
+
def start_hegemon_auto_thread(throttle = 0.1)
|
82
232
|
if (not @_hegemon_auto_thread) \
|
83
233
|
or (not @_hegemon_auto_thread.status)
|
84
234
|
|
85
235
|
@_end_hegemon_auto_thread = false
|
236
|
+
@_hegemon_auto_thread_throttle ||= throttle
|
86
237
|
@_hegemon_auto_thread = Thread.new do
|
87
238
|
i = 0
|
88
239
|
until @_end_hegemon_auto_thread
|
89
240
|
iter_hegemon_auto_loop(i)
|
90
241
|
i += 1
|
242
|
+
sleep @_hegemon_auto_thread_throttle
|
91
243
|
end
|
92
244
|
end
|
93
245
|
end
|
246
|
+
@_hegemon_auto_thread
|
94
247
|
end
|
95
248
|
|
249
|
+
#
|
250
|
+
# Block until the +hegemon_auto_thread+ is finished.
|
251
|
+
#
|
96
252
|
def join_hegemon_auto_thread
|
97
253
|
@_hegemon_auto_thread.join if @_hegemon_auto_thread
|
98
254
|
end
|
99
255
|
|
256
|
+
#
|
257
|
+
# Raise a flag to stop the loop inside +hegemon_auto_thread+.
|
258
|
+
#
|
100
259
|
def end_hegemon_auto_thread
|
101
260
|
@_end_hegemon_auto_thread = true
|
102
261
|
end
|
103
262
|
threadlock :end_hegemon_auto_thread, :lock=>:@_hegemon_lock
|
263
|
+
|
264
|
+
#
|
265
|
+
# :section:
|
266
|
+
##
|
104
267
|
end
|
105
268
|
|
106
269
|
|