hegemon 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hegemon.rb +223 -1
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a3c4e4c6087e43a78b89a9b70561a2c53978eb66
4
- data.tar.gz: 2ecc3d78169f174681623f0835ad590a896e202e
3
+ metadata.gz: 16c25ed67f2ba46414da653d229bd42fc2305bb6
4
+ data.tar.gz: 07eb0d874631e68ea5bca5457186bfa9b8d766bf
5
5
  SHA512:
6
- metadata.gz: 2cbd7490ec74838d7ad5ac3c2808564490a4ec630813b3599d7a570efd6e3feb93d259db935a9ea6f94d85b3d6c9e15834ad2b8b650563fd8460c2eb8c12b1e8
7
- data.tar.gz: d748f7d8650510f8ac56a9d8612d66cfa478b9b5402cf2ca50925c479776b4aa9fd7d0d0859516be86eb83db18789920d7714c56293160d2e9eaa58aa21fb87b
6
+ metadata.gz: 2420e9542dfdcc16a5a7bba5b5c00e13c181628a79c4e637450c31c38da86d06cc1ae571fc204ec86e3ed363acdb588a849ef442c816471c1cf111379c6abd63
7
+ data.tar.gz: a2bcef08cee2efe18568c88ae54a012035b8afa4d3ebba9f815bfce887ab71075d9b0c4d3122fb98bd23cfd6b4f1842570827eb2be6559a8366fa771c2bd26bf
@@ -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.1
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-05 00:00:00.000000000 Z
11
+ date: 2013-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: threadlock