hegemon 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/lib/hegemon.rb +223 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16c25ed67f2ba46414da653d229bd42fc2305bb6
|
4
|
+
data.tar.gz: 07eb0d874631e68ea5bca5457186bfa9b8d766bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2420e9542dfdcc16a5a7bba5b5c00e13c181628a79c4e637450c31c38da86d06cc1ae571fc204ec86e3ed363acdb588a849ef442c816471c1cf111379c6abd63
|
7
|
+
data.tar.gz: a2bcef08cee2efe18568c88ae54a012035b8afa4d3ebba9f815bfce887ab71075d9b0c4d3122fb98bd23cfd6b4f1842570827eb2be6559a8366fa771c2bd26bf
|
data/lib/hegemon.rb
CHANGED
@@ -1 +1,223 @@
|
|
1
|
-
require 'threadlock'
|
1
|
+
require 'threadlock'
|
2
|
+
|
3
|
+
Thread.abort_on_exception = true
|
4
|
+
def puts(*args); $stdout.puts(*args); end
|
5
|
+
|
6
|
+
module Hegemon
|
7
|
+
|
8
|
+
#***
|
9
|
+
# Accessor functions
|
10
|
+
#***
|
11
|
+
|
12
|
+
def state; @_hegemon_state; end
|
13
|
+
def states; @_hegemon_states.keys; end
|
14
|
+
def state_obj; @_hegemon_states[@_hegemon_state]; end
|
15
|
+
def state_objs; @_hegemon_states.clone; end
|
16
|
+
|
17
|
+
threadlock :state, :states, :state_obj, :state_objs, :lock=>:@_hegemon_lock
|
18
|
+
|
19
|
+
#***
|
20
|
+
# Declarative functions
|
21
|
+
#***
|
22
|
+
# Run these inside of your object's #initialize method
|
23
|
+
# to set the parameters of the state machine
|
24
|
+
# All user-provided action blocks will have the scope of the instance object
|
25
|
+
# in which the state machine parameters are initialized, and all parameters
|
26
|
+
# should be initialized in the same place (in #initialize, typically)
|
27
|
+
#***
|
28
|
+
|
29
|
+
##
|
30
|
+
# Bypass all transition requirements and actions to directly impose state +s+
|
31
|
+
# This should not be used in the public API except to set the initial state
|
32
|
+
def impose_state(s); @_hegemon_state = s; end
|
33
|
+
threadlock :impose_state, :lock=>:@_hegemon_lock
|
34
|
+
|
35
|
+
##
|
36
|
+
# Declare a state in the state machine
|
37
|
+
# [+state+] The state name to use, as a symbol
|
38
|
+
# [+&block+] The state's declarative block
|
39
|
+
# (refer to Declarative Functions of HegemonState)
|
40
|
+
def declare_state(state, &block)
|
41
|
+
@_hegemon_states ||= Hash.new
|
42
|
+
@_hegemon_states[state] = HegemonState.new(self, state, &block)
|
43
|
+
end
|
44
|
+
threadlock :declare_state, :lock=>:@_hegemon_lock
|
45
|
+
|
46
|
+
# Attempt a transition from the current state to state +s+
|
47
|
+
def request_state(s, *flags)
|
48
|
+
return false unless @_hegemon_states[@_hegemon_state].transitions[s]
|
49
|
+
@_hegemon_states[@_hegemon_state].transitions[s].try(*flags)
|
50
|
+
end
|
51
|
+
threadlock :request_state, :lock=>:@_hegemon_lock
|
52
|
+
|
53
|
+
# Check for relevant state updates and do.
|
54
|
+
# Using :only_auto flag will ignore all transitions with auto_update false
|
55
|
+
def update_state(*flags)
|
56
|
+
return false unless @_hegemon_states[@_hegemon_state]
|
57
|
+
trans = @_hegemon_states[@_hegemon_state].transitions
|
58
|
+
trans = trans.select{|k,t| t.auto_update} if (flags.include? :only_auto)
|
59
|
+
trans.each {|k,t| return true if t.try}
|
60
|
+
false end
|
61
|
+
threadlock :update_state, :lock=>:@_hegemon_lock
|
62
|
+
|
63
|
+
def block_until_state(s);
|
64
|
+
raise ArgumentError, "Cannot block until undefined state :#{s}" \
|
65
|
+
unless @_hegemon_states.keys.include? s
|
66
|
+
sleep 0 until @_hegemon_state==s
|
67
|
+
end
|
68
|
+
|
69
|
+
def do_state_tasks(i=0)
|
70
|
+
return nil unless @_hegemon_states[@_hegemon_state]
|
71
|
+
@_hegemon_states[@_hegemon_state].do_tasks(i)
|
72
|
+
nil end
|
73
|
+
threadlock :do_state_tasks, :lock=>:@_hegemon_lock
|
74
|
+
|
75
|
+
def iter_hegemon_auto_loop(i=0)
|
76
|
+
do_state_tasks(i)
|
77
|
+
update_state(:only_auto)
|
78
|
+
end
|
79
|
+
threadlock :iter_hegemon_auto_loop, :lock=>:@_hegemon_lock
|
80
|
+
|
81
|
+
# Run the automatic hegemon thread
|
82
|
+
def start_hegemon_auto_thread
|
83
|
+
if (not @_hegemon_auto_thread) \
|
84
|
+
or (not @_hegemon_auto_thread.status)
|
85
|
+
|
86
|
+
@_end_hegemon_auto_thread = false
|
87
|
+
@_hegemon_auto_thread = Thread.new do
|
88
|
+
i = 0
|
89
|
+
until @_end_hegemon_auto_thread
|
90
|
+
iter_hegemon_auto_loop(i)
|
91
|
+
i += 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def join_hegemon_auto_thread
|
98
|
+
@_hegemon_auto_thread.join if @_hegemon_auto_thread
|
99
|
+
end
|
100
|
+
|
101
|
+
def end_hegemon_auto_thread
|
102
|
+
@_end_hegemon_auto_thread = true
|
103
|
+
end
|
104
|
+
threadlock :end_hegemon_auto_thread, :lock=>:@_hegemon_lock
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
class HegemonState
|
109
|
+
|
110
|
+
attr_reader :state
|
111
|
+
|
112
|
+
def initialize(object, state, &block)
|
113
|
+
|
114
|
+
raise ScriptError, "HegemonState must be initialized with a block"\
|
115
|
+
unless block.is_a? Proc
|
116
|
+
|
117
|
+
@object = object
|
118
|
+
@state = state
|
119
|
+
|
120
|
+
@tasks = []
|
121
|
+
@transitions = Hash.new
|
122
|
+
|
123
|
+
instance_eval(&block)
|
124
|
+
end
|
125
|
+
|
126
|
+
def task(&block); @tasks << block if block; end
|
127
|
+
|
128
|
+
def transition_to(state, &block)
|
129
|
+
@transitions[state] = HegemonTransition.new(@object, @state, state, &block)
|
130
|
+
end
|
131
|
+
|
132
|
+
def do_tasks(i=0)
|
133
|
+
@tasks.each {|proc| @object.instance_exec(i,&proc) }
|
134
|
+
end
|
135
|
+
|
136
|
+
def transitions; @transitions; end
|
137
|
+
|
138
|
+
threadlock self.instance_methods-Object.instance_methods
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
class HegemonTransition
|
144
|
+
|
145
|
+
attr_reader :src_state, :dest_state
|
146
|
+
|
147
|
+
def initialize(object, src_state, dest_state, &block)
|
148
|
+
|
149
|
+
raise ScriptError, "HegemonTransition must be initialized with a block"\
|
150
|
+
unless block.is_a? Proc
|
151
|
+
|
152
|
+
@object = object
|
153
|
+
@src_state = src_state
|
154
|
+
@dest_state = dest_state
|
155
|
+
|
156
|
+
@conditions = []
|
157
|
+
@sufficients = []
|
158
|
+
@requirements = []
|
159
|
+
@befores = []
|
160
|
+
@afters = []
|
161
|
+
|
162
|
+
@progress = nil
|
163
|
+
@auto_update = true
|
164
|
+
|
165
|
+
instance_eval(&block)
|
166
|
+
end
|
167
|
+
|
168
|
+
def condition (&block); @conditions << block if block; end
|
169
|
+
def sufficient (&block); @sufficients << block if block; end
|
170
|
+
def requirement(&block); @requirements << block if block; end
|
171
|
+
def before (&block); @befores << block if block; end
|
172
|
+
def after (&block); @afters << block if block; end
|
173
|
+
|
174
|
+
# Get or set the @auto_update value
|
175
|
+
def auto_update(val=:just_ask)
|
176
|
+
(val==:just_ask) ?
|
177
|
+
(@auto_update) :
|
178
|
+
(@auto_update = (true and val))
|
179
|
+
end
|
180
|
+
|
181
|
+
def ready?(*flags)
|
182
|
+
return false unless @object.state==@src_state
|
183
|
+
return false if @progress
|
184
|
+
|
185
|
+
result = (procs_and @requirements)
|
186
|
+
return result if (flags.include? :force)
|
187
|
+
|
188
|
+
return result && ((procs_or @sufficients) or (procs_and @conditions))
|
189
|
+
end
|
190
|
+
|
191
|
+
def try(*flags)
|
192
|
+
(ready?(*flags)) ?
|
193
|
+
(perform; true) :
|
194
|
+
(false)
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def perform
|
200
|
+
@progress = :pre
|
201
|
+
procs_run(@befores)
|
202
|
+
@progress = :impose
|
203
|
+
@object.impose_state(@dest_state)
|
204
|
+
@progress = :post
|
205
|
+
procs_run(@afters)
|
206
|
+
@progress = nil
|
207
|
+
nil end
|
208
|
+
|
209
|
+
def procs_run(list)
|
210
|
+
list.each {|proc| @object.instance_eval(&proc) }
|
211
|
+
nil end
|
212
|
+
|
213
|
+
def procs_and(list)
|
214
|
+
list.each {|proc| return false if not @object.instance_eval(&proc)}
|
215
|
+
true end
|
216
|
+
|
217
|
+
def procs_or(list)
|
218
|
+
list.each {|proc| return true if @object.instance_eval(&proc)}
|
219
|
+
false end
|
220
|
+
|
221
|
+
threadlock self.instance_methods-Object.instance_methods
|
222
|
+
|
223
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hegemon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe McIlvain
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: threadlock
|