apollo 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +57 -0
- data/{README.markdown → README.md} +59 -87
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/apollo.gemspec +5 -4
- data/lib/apollo.rb +55 -30
- data/lib/apollo/active_record_instance_methods.rb +7 -7
- data/lib/apollo/specification.rb +31 -1
- data/lib/apollo/state.rb +3 -3
- metadata +6 -5
data/CHANGELOG.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
Apollo Changelog
|
2
|
+
================
|
3
|
+
|
4
|
+
1.1
|
5
|
+
|
6
|
+
* Added state sets. (7498cf0)
|
7
|
+
* Unbranded methods. E.g. `Apollo::apollo` -> `Apollo::state_machine` (f8b42b8)
|
8
|
+
|
9
|
+
1.0
|
10
|
+
---
|
11
|
+
This is an initial release of the Apollo fork from [Workflow](http://github.com/geekq/workflow). The reason I decided to fork Workflow, and in particular change the name, is because I feel that Workflow is an excellent starting point for my needs; however, my desire for Apollo is somewhat different from the desires of the creators of Workflow. **In no way is my fork (and renaming) intended to be any kind of insult or intellectual rights infringement.** I chose Workflow for the basis of Apollo because I feel it is the **best** state machine gem available. I will most certainly maintain the original MIT-LICENSE as apart of Apollo so long as *any* portion of the code is derived from Workflow (which I suspect will always be the case).
|
12
|
+
|
13
|
+
* Rebranded modules from "workflow" to "apollo".
|
14
|
+
* Using [Jeweler](http://github.com/technicalpickles/jeweler).
|
15
|
+
* Removed unnecessary workflow.rb "initializer" file from root of project. (f2ac52a)
|
16
|
+
* Extracted Workflow submodules and classes into separated files. (6d4e90f)
|
17
|
+
* Changed default "column" name from `workflow_state` to `current_state`. (f562e71)
|
18
|
+
* Require reason for `halt` and allow arbitrary exception for `halt!`. (0f903d7)
|
19
|
+
|
20
|
+
Original Workflow Changelog
|
21
|
+
===========================
|
22
|
+
|
23
|
+
### New in the version 0.4.0
|
24
|
+
|
25
|
+
* completely rewritten the documentation to match my branch. Every
|
26
|
+
described feature is backed up by an automated test.
|
27
|
+
|
28
|
+
### New in the version 0.3.0
|
29
|
+
|
30
|
+
Intermixing of transition graph definition (states, transitions)
|
31
|
+
on the one side and implementation of the actions on the other side
|
32
|
+
for a bigger state machine can introduce clutter.
|
33
|
+
|
34
|
+
To reduce this clutter it is now possible to use state entry- and
|
35
|
+
exit- hooks defined through a naming convention. For example, if there
|
36
|
+
is a state :pending, then instead of using a
|
37
|
+
block:
|
38
|
+
|
39
|
+
state :pending do
|
40
|
+
on_entry do
|
41
|
+
# your implementation here
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
you can hook in by defining method
|
46
|
+
|
47
|
+
def on_pending_exit(new_state, event, *args)
|
48
|
+
# your implementation here
|
49
|
+
end
|
50
|
+
|
51
|
+
anywhere in your class. You can also use a simpler function signature
|
52
|
+
like `def on_pending_exit(*args)` if your are not interested in
|
53
|
+
arguments. Please note: `def on_pending_exit()` with an empty list
|
54
|
+
would not work.
|
55
|
+
|
56
|
+
If both a function with a name according to naming convention and the
|
57
|
+
on_entry/on_exit block are given, then only on_entry/on_exit block is used.
|
@@ -8,7 +8,38 @@ What is apollo?
|
|
8
8
|
> poetry, and the arts; and more. Apollo is the son of Zeus and Leto, and has a twin
|
9
9
|
> sister, the chaste huntress Artemis. [Wikipedia: Dionysus (2010/04/23)](http://en.wikipedia.org/wiki/Apollo)
|
10
10
|
|
11
|
-
Apollo is an fork of workflow.
|
11
|
+
Apollo is an fork of [Workflow](http://github.com/geekq/workflow).
|
12
|
+
|
13
|
+
Resources
|
14
|
+
---------
|
15
|
+
|
16
|
+
* [Github Project](http://github.com/tekwiz/apollo)
|
17
|
+
* [Rdocs on Rdoc.info](http://rdoc.info/projects/tekwiz/apollo)
|
18
|
+
* [Wiki on Github](http://wiki.github.com/tekwiz/apollo/)
|
19
|
+
* [Issues Tracker on Github](http://github.com/tekwiz/apollo/issues)
|
20
|
+
* [Metrics on Caliper](http://getcaliper.com/caliper/project?repo=http%3A%2F%2Frubygems.org%2Fgems%2Fapollo)
|
21
|
+
|
22
|
+
Features & Issues
|
23
|
+
-----------------
|
24
|
+
|
25
|
+
This is a brand new project, so if you find bugs or use cases that would helpful to satisfy, post an [Issue](http://github.com/tekwiz/apollo/issues) on Github.
|
26
|
+
|
27
|
+
This project is intended to be a **very** eclectic mix of helpful tools, so please feel free to send pull requests. That said, make **absolutely sure** your modifications are well tested. The hodge-podge nature of this project may make it prone to issues, so no code will be pulled-in that is not __fully_tested__.
|
28
|
+
|
29
|
+
Note on Patches/Pull Requests
|
30
|
+
-----------------------------
|
31
|
+
|
32
|
+
* Fork the project.
|
33
|
+
* Make your feature addition or bug fix.
|
34
|
+
* Add tests for it. This is important so I don't break it in a
|
35
|
+
future version unintentionally.
|
36
|
+
* Commit, do not mess with rakefile, version, or history.
|
37
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
38
|
+
* Send me a pull request. Bonus points for topic branches.
|
39
|
+
|
40
|
+
### Documentation Warning
|
41
|
+
|
42
|
+
Beware that the below documentation has NOT been validated for the changes from Workflow to Apollo.
|
12
43
|
|
13
44
|
What is workflow?
|
14
45
|
-----------------
|
@@ -332,106 +363,47 @@ The whole event sequence is as follows:
|
|
332
363
|
* PERSIST WORKFLOW STATE, i.e. transition
|
333
364
|
* on_entry
|
334
365
|
|
335
|
-
|
336
366
|
Documenting with diagrams
|
337
367
|
-------------------------
|
338
368
|
|
339
369
|
You can generate a graphical representation of your apollo for
|
340
370
|
documentation purposes. S. Apollo::create_apollo_diagram.
|
341
371
|
|
342
|
-
|
343
|
-
Earlier versions
|
344
|
-
----------------
|
345
|
-
|
346
|
-
The `apollo` library was originally written by Ryan Allen.
|
347
|
-
|
348
|
-
The version 0.3 was almost completely (including ActiveRecord
|
349
|
-
integration, API for accessing apollo specification,
|
350
|
-
method_missing free implementation) rewritten by Vladimir Dobriakov
|
351
|
-
keeping the original apollo DSL spirit.
|
352
|
-
|
353
|
-
|
354
|
-
Migration from the original Ryan's library
|
355
|
-
------------------------------------------
|
356
|
-
|
357
|
-
Credit: Michael (rockrep)
|
358
|
-
|
359
|
-
Accessing apollo specification
|
360
|
-
|
361
|
-
my_instance.apollo # old
|
362
|
-
MyClass.apollo_spec # new
|
363
|
-
|
364
|
-
Accessing states, events, meta, e.g.
|
365
|
-
|
366
|
-
my_instance.apollo.states(:some_state).events(:some_event).meta[:some_meta_tag] # old
|
367
|
-
MyClass.apollo_spec.states[:some_state].events[:some_event].meta[:some_meta_tag] # new
|
368
|
-
|
369
|
-
Causing state transitions
|
370
|
-
|
371
|
-
my_instance.apollo.my_event # old
|
372
|
-
my_instance.my_event! # new
|
373
|
-
|
374
|
-
when using both a block and a callback method for an event, the block executes prior to the callback
|
375
|
-
|
376
|
-
|
377
|
-
Changelog
|
372
|
+
Copyright
|
378
373
|
---------
|
379
374
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
375
|
+
Copyright 2010 Travis D. Warlick, Jr.
|
376
|
+
|
377
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
378
|
+
you may not use this file except in compliance with the License.
|
379
|
+
You may obtain a copy of the License at
|
380
|
+
|
381
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
382
|
+
|
383
|
+
Unless required by applicable law or agreed to in writing, software
|
384
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
385
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
386
|
+
See the License for the specific language governing permissions and
|
387
|
+
limitations under the License.
|
384
388
|
|
385
|
-
|
389
|
+
The original work from [Workflow](http://github.com/geekq/workflow)
|
386
390
|
|
387
|
-
|
388
|
-
on the one side and implementation of the actions on the other side
|
389
|
-
for a bigger state machine can introduce clutter.
|
390
|
-
|
391
|
-
To reduce this clutter it is now possible to use state entry- and
|
392
|
-
exit- hooks defined through a naming convention. For example, if there
|
393
|
-
is a state :pending, then instead of using a
|
394
|
-
block:
|
395
|
-
|
396
|
-
state :pending do
|
397
|
-
on_entry do
|
398
|
-
# your implementation here
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
you can hook in by defining method
|
403
|
-
|
404
|
-
def on_pending_exit(new_state, event, *args)
|
405
|
-
# your implementation here
|
406
|
-
end
|
391
|
+
Author: Vladimir Dobriakov, http://www.innoq.com/blog/vd, http://blog.geekq.net/
|
407
392
|
|
408
|
-
|
409
|
-
like `def on_pending_exit(*args)` if your are not interested in
|
410
|
-
arguments. Please note: `def on_pending_exit()` with an empty list
|
411
|
-
would not work.
|
393
|
+
Copyright (c) 2008-2009 Vodafone
|
412
394
|
|
413
|
-
|
414
|
-
on_entry/on_exit block are given, then only on_entry/on_exit block is used.
|
395
|
+
Copyright (c) 2007-2008 Ryan Allen, FlashDen Pty Ltd
|
415
396
|
|
397
|
+
Based on the work of Ryan Allen and Scott Barron
|
416
398
|
|
417
|
-
|
418
|
-
-------
|
399
|
+
Licensed under MIT license, see the MIT-LICENSE file.
|
419
400
|
|
420
|
-
|
421
|
-
|
422
|
-
http://github.com/geekq/apollo/issues
|
423
|
-
|
424
|
-
|
425
|
-
About
|
426
|
-
-----
|
427
|
-
|
428
|
-
Author: Vladimir Dobriakov, http://www.innoq.com/blog/vd, http://blog.geekq.net/
|
429
|
-
|
430
|
-
Copyright (c) 2008-2009 Vodafone
|
431
|
-
|
432
|
-
Copyright (c) 2007-2008 Ryan Allen, FlashDen Pty Ltd
|
433
|
-
|
434
|
-
Based on the work of Ryan Allen and Scott Barron
|
401
|
+
Earlier versions
|
402
|
+
----------------
|
435
403
|
|
436
|
-
|
404
|
+
The `workflow` library was originally written by Ryan Allen.
|
437
405
|
|
406
|
+
The version 0.3 was almost completely (including ActiveRecord
|
407
|
+
integration, API for accessing apollo specification,
|
408
|
+
method_missing free implementation) rewritten by Vladimir Dobriakov
|
409
|
+
keeping the original apollo DSL spirit.
|
data/Rakefile
CHANGED
@@ -41,8 +41,8 @@ Rake::RDocTask.new do |rdoc|
|
|
41
41
|
|
42
42
|
rdoc.rdoc_dir = 'rdoc'
|
43
43
|
rdoc.title = "Apollo #{version}"
|
44
|
-
rdoc.rdoc_files.include('README*', 'MIT-LICENSE', 'LICENSE', 'VERSION')
|
44
|
+
rdoc.rdoc_files.include('README*', 'MIT-LICENSE', 'LICENSE', 'VERSION', 'CHANGELOG.md')
|
45
45
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
46
|
end
|
47
47
|
|
48
|
-
task :clobber => [:clobber_rcov, :clobber_rdoc]
|
48
|
+
# task :clobber => [:clobber_rcov, :clobber_rdoc]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.1.0
|
data/apollo.gemspec
CHANGED
@@ -5,21 +5,22 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{apollo}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Travis D. Warlick, Jr."]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-24}
|
13
13
|
s.email = %q{warlickt@operissystems.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
16
|
-
"README.
|
16
|
+
"README.md"
|
17
17
|
]
|
18
18
|
s.files = [
|
19
19
|
".gitignore",
|
20
|
+
"CHANGELOG.md",
|
20
21
|
"LICENSE",
|
21
22
|
"MIT-LICENSE",
|
22
|
-
"README.
|
23
|
+
"README.md",
|
23
24
|
"Rakefile",
|
24
25
|
"VERSION",
|
25
26
|
"apollo.gemspec",
|
data/lib/apollo.rb
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
# Copyright 2010 Travis D. Warlick, Jr.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
#
|
15
|
+
# Original work from Workflow:
|
16
|
+
# Copyright (c) 2008-2009 Vodafone
|
17
|
+
# Copyright (c) 2007-2008 Ryan Allen, FlashDen Pty Ltd
|
1
18
|
module Apollo
|
2
19
|
autoload :Event, 'apollo/event'
|
3
20
|
autoload :State, 'apollo/state'
|
@@ -23,18 +40,18 @@ module Apollo
|
|
23
40
|
class ApolloDefinitionError < Exception; end
|
24
41
|
|
25
42
|
module ClassMethods
|
26
|
-
|
27
|
-
|
28
|
-
def apollo_column(column_name=nil)
|
43
|
+
def current_state_column(column_name=nil)
|
29
44
|
if column_name
|
30
|
-
@
|
45
|
+
@current_state_column_name = column_name.to_sym
|
31
46
|
else
|
32
|
-
@
|
47
|
+
@current_state_column_name ||= :current_state
|
33
48
|
end
|
34
|
-
@
|
49
|
+
@current_state_column_name
|
35
50
|
end
|
36
51
|
|
37
|
-
def
|
52
|
+
def state_machine(&specification)
|
53
|
+
return @apollo_spec unless block_given?
|
54
|
+
|
38
55
|
@apollo_spec = Specification.new(Hash.new, &specification)
|
39
56
|
@apollo_spec.states.values.each do |state|
|
40
57
|
state_name = state.name
|
@@ -53,12 +70,20 @@ module Apollo
|
|
53
70
|
end
|
54
71
|
end
|
55
72
|
end
|
73
|
+
|
74
|
+
@apollo_spec.state_sets.keys.each do |set_name|
|
75
|
+
module_eval do
|
76
|
+
define_method "#{set_name}?" do
|
77
|
+
current_state.sets.include?(set_name)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
56
81
|
end
|
57
82
|
end
|
58
83
|
|
59
84
|
module InstanceMethods
|
60
85
|
def current_state
|
61
|
-
loaded_state =
|
86
|
+
loaded_state = load_current_state
|
62
87
|
res = spec.states[loaded_state.to_sym] if loaded_state
|
63
88
|
res || spec.initial_state
|
64
89
|
end
|
@@ -76,7 +101,7 @@ module Apollo
|
|
76
101
|
raise NoTransitionAllowed.new(
|
77
102
|
"There is no event #{name.to_sym} defined for the #{current_state} state") \
|
78
103
|
if event.nil?
|
79
|
-
# This three member variables are a relict from the old
|
104
|
+
# This three member variables are a relict from the old workflow library
|
80
105
|
# TODO: refactor some day
|
81
106
|
@halted_because = nil
|
82
107
|
@halted = false
|
@@ -112,10 +137,10 @@ module Apollo
|
|
112
137
|
c = self.class
|
113
138
|
# using a simple loop instead of class_inheritable_accessor to avoid
|
114
139
|
# dependency on Rails' ActiveSupport
|
115
|
-
until c.
|
140
|
+
until c.state_machine || !(c.include? Apollo)
|
116
141
|
c = c.superclass
|
117
142
|
end
|
118
|
-
c.
|
143
|
+
c.state_machine
|
119
144
|
end
|
120
145
|
|
121
146
|
def halt(reason)
|
@@ -137,7 +162,7 @@ module Apollo
|
|
137
162
|
|
138
163
|
def transition(from, to, name, *args)
|
139
164
|
run_on_exit(from, to, name, *args)
|
140
|
-
|
165
|
+
persist_current_state to.to_s
|
141
166
|
run_on_entry(to, from, name, *args)
|
142
167
|
end
|
143
168
|
|
@@ -173,19 +198,19 @@ module Apollo
|
|
173
198
|
end
|
174
199
|
end
|
175
200
|
|
176
|
-
#
|
177
|
-
# can be overriden to handle the persistence of the
|
201
|
+
# load_current_state and persist_current_state
|
202
|
+
# can be overriden to handle the persistence of the current state.
|
178
203
|
#
|
179
204
|
# Default (non ActiveRecord) implementation stores the current state
|
180
205
|
# in a variable.
|
181
206
|
#
|
182
|
-
# Default ActiveRecord implementation uses a '
|
183
|
-
def
|
184
|
-
@
|
207
|
+
# Default ActiveRecord implementation uses a 'current_state' database column.
|
208
|
+
def load_current_state
|
209
|
+
@current_state if instance_variable_defined? :@current_state
|
185
210
|
end
|
186
211
|
|
187
|
-
def
|
188
|
-
@
|
212
|
+
def persist_current_state(new_value)
|
213
|
+
@current_state = new_value
|
189
214
|
end
|
190
215
|
end
|
191
216
|
|
@@ -200,21 +225,21 @@ module Apollo
|
|
200
225
|
end
|
201
226
|
end
|
202
227
|
|
203
|
-
# Generates a `dot` graph of the
|
228
|
+
# Generates a `dot` graph of the state machine.
|
204
229
|
# Prerequisite: the `dot` binary.
|
205
230
|
# You can use it in your own Rakefile like this:
|
206
231
|
#
|
207
232
|
# namespace :doc do
|
208
|
-
# desc "Generate a graph of the
|
209
|
-
# task :
|
210
|
-
# Apollo::
|
233
|
+
# desc "Generate a graph of the state machine."
|
234
|
+
# task :state_machine do
|
235
|
+
# Apollo::create_state_diagram(Order.new)
|
211
236
|
# end
|
212
237
|
# end
|
213
238
|
#
|
214
239
|
# You can influence the placement of nodes by specifying
|
215
240
|
# additional meta information in your states and transition descriptions.
|
216
241
|
# You can assign higher `doc_weight` value to the typical transitions
|
217
|
-
# in your
|
242
|
+
# in your state machine. All other states and transitions will be arranged
|
218
243
|
# around that main line. See also `weight` in the graphviz documentation.
|
219
244
|
# Example:
|
220
245
|
#
|
@@ -223,21 +248,21 @@ module Apollo
|
|
223
248
|
# end
|
224
249
|
#
|
225
250
|
#
|
226
|
-
# @param klass A class with the Apollo mixin, for which you wish the graphical
|
251
|
+
# @param klass A class with the Apollo mixin, for which you wish the graphical state machine representation
|
227
252
|
# @param [String] target_dir Directory, where to save the dot and the pdf files
|
228
253
|
# @param [String] graph_options You can change graph orientation, size etc. See graphviz documentation
|
229
|
-
def self.
|
230
|
-
|
231
|
-
fname = File.join(target_dir, "generated_#{
|
254
|
+
def self.create_state_diagram(klass, target_dir, graph_options='rankdir="LR", size="7,11.6", ratio="fill"')
|
255
|
+
state_machine_name = "#{klass.name.tableize}_state_machine"
|
256
|
+
fname = File.join(target_dir, "generated_#{state_machine_name}")
|
232
257
|
File.open("#{fname}.dot", 'w') do |file|
|
233
258
|
file.puts %Q|
|
234
|
-
digraph #{
|
259
|
+
digraph #{state_machine_name} {
|
235
260
|
graph [#{graph_options}];
|
236
261
|
node [shape=box];
|
237
262
|
edge [len=1];
|
238
263
|
|
|
239
264
|
|
240
|
-
klass.
|
265
|
+
klass.state_machine.states.each do |state_name, state|
|
241
266
|
file.puts %Q{ #{state.name} [label="#{state.name}"];}
|
242
267
|
state.events.each do |event_name, event|
|
243
268
|
meta_info = event.meta
|
@@ -1,24 +1,24 @@
|
|
1
1
|
module Apollo
|
2
2
|
module ActiveRecordInstanceMethods
|
3
|
-
def
|
4
|
-
read_attribute(self.class.
|
3
|
+
def load_current_state
|
4
|
+
read_attribute(self.class.current_state_column)
|
5
5
|
end
|
6
6
|
|
7
|
-
# On transition the new
|
7
|
+
# On transition the new current state is immediately saved in the
|
8
8
|
# database.
|
9
|
-
def
|
10
|
-
update_attribute self.class.
|
9
|
+
def persist_current_state(new_value)
|
10
|
+
update_attribute self.class.current_state_column, new_value
|
11
11
|
end
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
# Motivation: even if NULL is stored in the
|
15
|
+
# Motivation: even if NULL is stored in the current_state database column,
|
16
16
|
# the current_state is correctly recognized in the Ruby code. The problem
|
17
17
|
# arises when you want to SELECT records filtering by the value of initial
|
18
18
|
# state. That's why it is important to save the string with the name of the
|
19
19
|
# initial state in all the new records.
|
20
20
|
def write_initial_state
|
21
|
-
write_attribute self.class.
|
21
|
+
write_attribute self.class.current_state_column, current_state.to_s
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
data/lib/apollo/specification.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Apollo
|
2
2
|
class Specification
|
3
|
-
attr_accessor :states, :initial_state, :meta, :on_transition_proc
|
3
|
+
attr_accessor :states, :initial_state, :meta, :on_transition_proc, :state_sets
|
4
4
|
|
5
5
|
def initialize(meta = {}, &specification)
|
6
6
|
@states = Hash.new
|
7
|
+
@state_sets = Hash.new
|
7
8
|
@meta = meta
|
8
9
|
instance_eval(&specification)
|
9
10
|
end
|
@@ -11,6 +12,8 @@ module Apollo
|
|
11
12
|
private
|
12
13
|
|
13
14
|
def state(name, meta = {:meta => {}}, &events_and_etc)
|
15
|
+
validate_state_name(name)
|
16
|
+
|
14
17
|
# meta[:meta] to keep the API consistent..., gah
|
15
18
|
new_state = State.new(name, meta[:meta])
|
16
19
|
@initial_state = new_state if @states.empty?
|
@@ -18,6 +21,21 @@ module Apollo
|
|
18
21
|
@scoped_state = new_state
|
19
22
|
instance_eval(&events_and_etc) if events_and_etc
|
20
23
|
end
|
24
|
+
|
25
|
+
def state_set(name, *state_names)
|
26
|
+
validate_state_set_name(name)
|
27
|
+
|
28
|
+
set = Set.new
|
29
|
+
state_names.each do |state_name|
|
30
|
+
if state = @states[state_name]
|
31
|
+
set << state
|
32
|
+
state.sets << name
|
33
|
+
else
|
34
|
+
raise ApolloDefinitionError, "Unknown state: #{state}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@state_sets[name] = set
|
38
|
+
end
|
21
39
|
|
22
40
|
def event(name, args = {}, &action)
|
23
41
|
target = args[:to] || args[:to]
|
@@ -39,5 +57,17 @@ module Apollo
|
|
39
57
|
def on_transition(&proc)
|
40
58
|
@on_transition_proc = proc
|
41
59
|
end
|
60
|
+
|
61
|
+
def validate_state_name(name)
|
62
|
+
if @state_sets[name]
|
63
|
+
raise ApolloDefinitionError, "State name conflicts with state set name: #{name}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_state_set_name(name)
|
68
|
+
if @states[name]
|
69
|
+
raise ApolloDefinitionError, "State set name conflicts with state name: #{name}"
|
70
|
+
end
|
71
|
+
end
|
42
72
|
end
|
43
73
|
end
|
data/lib/apollo/state.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Apollo
|
2
2
|
class State
|
3
|
-
attr_accessor :name, :events, :meta, :on_entry, :on_exit
|
3
|
+
attr_accessor :name, :events, :meta, :on_entry, :on_exit, :sets
|
4
4
|
|
5
5
|
def initialize(name, meta = {})
|
6
|
-
@name, @events, @meta = name, Hash.new, meta
|
6
|
+
@name, @events, @meta, @sets = name, Hash.new, meta, Set.new
|
7
7
|
end
|
8
8
|
|
9
9
|
def to_s
|
@@ -14,4 +14,4 @@ module Apollo
|
|
14
14
|
name.to_sym
|
15
15
|
end
|
16
16
|
end
|
17
|
-
end
|
17
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 1.0.0
|
9
|
+
version: 1.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Travis D. Warlick, Jr.
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-24 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -26,12 +26,13 @@ extensions: []
|
|
26
26
|
|
27
27
|
extra_rdoc_files:
|
28
28
|
- LICENSE
|
29
|
-
- README.
|
29
|
+
- README.md
|
30
30
|
files:
|
31
31
|
- .gitignore
|
32
|
+
- CHANGELOG.md
|
32
33
|
- LICENSE
|
33
34
|
- MIT-LICENSE
|
34
|
-
- README.
|
35
|
+
- README.md
|
35
36
|
- Rakefile
|
36
37
|
- VERSION
|
37
38
|
- apollo.gemspec
|