apollo 1.0.0 → 1.1.0
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/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
|