davidlee-state-fu 0.3.1 → 0.10.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/README.textile +124 -34
- data/Rakefile +36 -30
- data/lib/no_stdout.rb +1 -1
- data/lib/state-fu.rb +9 -8
- data/lib/state_fu/active_support_lite/array/access.rb +12 -5
- data/lib/state_fu/active_support_lite/array/conversions.rb +10 -4
- data/lib/state_fu/active_support_lite/array/extract_options.rb +5 -4
- data/lib/state_fu/active_support_lite/array/grouping.rb +7 -4
- data/lib/state_fu/active_support_lite/array/random_access.rb +4 -3
- data/lib/state_fu/active_support_lite/array/wrapper.rb +4 -3
- data/lib/state_fu/active_support_lite/array.rb +3 -1
- data/lib/state_fu/active_support_lite/blank.rb +18 -9
- data/lib/state_fu/active_support_lite/cattr_reader.rb +4 -1
- data/lib/state_fu/active_support_lite/keys.rb +8 -3
- data/lib/state_fu/active_support_lite/misc.rb +6 -4
- data/lib/state_fu/active_support_lite/module/delegation.rb +130 -0
- data/lib/state_fu/active_support_lite/module.rb +1 -0
- data/lib/state_fu/active_support_lite/object.rb +5 -2
- data/lib/state_fu/active_support_lite/string.rb +6 -1
- data/lib/state_fu/active_support_lite/symbol.rb +2 -1
- data/lib/state_fu/applicable.rb +41 -0
- data/lib/state_fu/{helper.rb → arrays.rb} +45 -121
- data/lib/state_fu/binding.rb +136 -159
- data/lib/state_fu/core_ext.rb +78 -10
- data/lib/state_fu/event.rb +112 -48
- data/lib/state_fu/exceptions.rb +80 -34
- data/lib/state_fu/executioner.rb +149 -0
- data/lib/state_fu/has_options.rb +16 -0
- data/lib/state_fu/hooks.rb +21 -16
- data/lib/state_fu/interface.rb +80 -83
- data/lib/state_fu/lathe.rb +361 -148
- data/lib/state_fu/logger.rb +122 -45
- data/lib/state_fu/machine.rb +60 -32
- data/lib/state_fu/method_factory.rb +180 -72
- data/lib/state_fu/methodical.rb +17 -0
- data/lib/state_fu/persistence/active_record.rb +6 -1
- data/lib/state_fu/persistence/attribute.rb +1 -0
- data/lib/state_fu/persistence/base.rb +8 -6
- data/lib/state_fu/persistence.rb +94 -23
- data/lib/state_fu/sprocket.rb +26 -11
- data/lib/state_fu/state.rb +8 -27
- data/lib/state_fu/transition.rb +207 -98
- data/lib/state_fu/transition_query.rb +214 -0
- data/lib/state_fu.rb +1 -0
- data/lib/tasks/spec_last.rake +46 -0
- data/lib/tasks/state_fu.rake +57 -0
- data/lib/vizier.rb +61 -61
- data/spec/custom_formatter.rb +49 -0
- data/spec/features/binding_and_transition_helper_mixin_spec.rb +2 -2
- data/spec/features/method_missing_only_once_spec.rb +28 -0
- data/spec/features/not_requirements_spec.rb +83 -46
- data/spec/features/plotter_spec.rb +97 -0
- data/spec/features/shared_log_spec.rb +7 -0
- data/spec/features/singleton_machine_spec.rb +39 -0
- data/spec/features/state_and_array_options_accessor_spec.rb +1 -1
- data/spec/features/{transition_boolean_comparison.rb → transition_boolean_comparison_spec.rb} +29 -18
- data/spec/helper.rb +6 -117
- data/spec/integration/active_record_persistence_spec.rb +18 -4
- data/spec/integration/binding_extension_spec.rb +1 -1
- data/spec/integration/class_accessor_spec.rb +49 -59
- data/spec/integration/event_definition_spec.rb +20 -20
- data/spec/integration/example_01_document_spec.rb +13 -8
- data/spec/integration/example_02_string_spec.rb +3 -2
- data/spec/integration/instance_accessor_spec.rb +16 -19
- data/spec/integration/lathe_extension_spec.rb +2 -2
- data/spec/integration/machine_duplication_spec.rb +59 -37
- data/spec/integration/relaxdb_persistence_spec.rb +6 -3
- data/spec/integration/requirement_reflection_spec.rb +66 -57
- data/spec/integration/state_definition_spec.rb +72 -66
- data/spec/integration/transition_spec.rb +169 -173
- data/spec/spec.opts +5 -3
- data/spec/spec_helper.rb +132 -0
- data/spec/state_fu_spec.rb +870 -0
- data/spec/units/binding_spec.rb +33 -22
- data/spec/units/event_spec.rb +3 -22
- data/spec/units/exceptions_spec.rb +7 -0
- data/spec/units/lathe_spec.rb +7 -7
- data/spec/units/machine_spec.rb +67 -75
- data/spec/units/method_factory_spec.rb +55 -48
- data/spec/units/sprocket_spec.rb +5 -7
- data/spec/units/state_spec.rb +33 -24
- metadata +31 -19
- data/lib/state_fu/active_support_lite/inheritable_attributes.rb +0 -1
- data/lib/state_fu/fu_space.rb +0 -51
- data/lib/state_fu/mock_transition.rb +0 -38
- data/spec/BDD/plotter_spec.rb +0 -115
- data/spec/integration/dynamic_requirement_spec.rb +0 -160
- data/spec/integration/ex_machine_for_accounts_spec.rb +0 -79
- data/spec/integration/sanity_spec.rb +0 -31
- data/spec/units/fu_space_spec.rb +0 -95
data/lib/state_fu/binding.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module StateFu
|
|
2
2
|
class Binding
|
|
3
|
-
include ContextualEval
|
|
4
3
|
|
|
5
|
-
attr_reader :object, :machine, :method_name, :persister, :transitions, :options
|
|
4
|
+
attr_reader :object, :machine, :method_name, :field_name, :persister, :transitions, :options, :target
|
|
5
|
+
|
|
6
6
|
|
|
7
7
|
# the constructor should not be called manually; a binding is
|
|
8
8
|
# returned when an instance of a class with a StateFu::Machine
|
|
@@ -18,39 +18,31 @@ module StateFu
|
|
|
18
18
|
@method_name = method_name
|
|
19
19
|
@transitions = []
|
|
20
20
|
@options = options.symbolize_keys!
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@
|
|
28
|
-
Logger.debug( "Persister (#{@persister.class}) added: #{method_name} as field #{field_name}" )
|
|
29
|
-
|
|
30
|
-
# define event methods on self( binding ) and @object
|
|
31
|
-
StateFu::MethodFactory.new( self ).install!
|
|
32
|
-
machine.helpers.inject_into( self )
|
|
33
|
-
# StateFu::Persistence.prepare_field( @object.class, field_name )
|
|
21
|
+
@target = singleton? ? object : object.class
|
|
22
|
+
@field_name = options[:field_name] || @target.state_fu_field_names[method_name]
|
|
23
|
+
@persister = Persistence.for( self )
|
|
24
|
+
|
|
25
|
+
# define event methods on this binding and its @object
|
|
26
|
+
MethodFactory.new( self ).install!
|
|
27
|
+
@machine.helpers.inject_into( self )
|
|
34
28
|
end
|
|
29
|
+
|
|
35
30
|
alias_method :o, :object
|
|
36
31
|
alias_method :obj, :object
|
|
37
32
|
alias_method :model, :object
|
|
38
33
|
alias_method :instance, :object
|
|
39
34
|
|
|
40
|
-
alias_method :machine, :machine
|
|
41
35
|
alias_method :workflow, :machine
|
|
42
36
|
alias_method :state_machine, :machine
|
|
43
37
|
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
end
|
|
38
|
+
#
|
|
39
|
+
# current state
|
|
40
|
+
#
|
|
48
41
|
|
|
49
|
-
# the
|
|
42
|
+
# the current State
|
|
50
43
|
def current_state
|
|
51
44
|
persister.current_state
|
|
52
45
|
end
|
|
53
|
-
alias_method :at, :current_state
|
|
54
46
|
alias_method :now, :current_state
|
|
55
47
|
alias_method :state, :current_state
|
|
56
48
|
|
|
@@ -66,54 +58,48 @@ module StateFu
|
|
|
66
58
|
alias_method :state_name, :current_state_name
|
|
67
59
|
alias_method :to_sym, :current_state_name
|
|
68
60
|
|
|
69
|
-
#
|
|
61
|
+
#
|
|
62
|
+
# events
|
|
63
|
+
#
|
|
64
|
+
|
|
65
|
+
# returns a list of Events which can fire from the current_state
|
|
70
66
|
def events
|
|
71
|
-
machine.events.select
|
|
67
|
+
machine.events.select do |e|
|
|
68
|
+
e.can_transition_from? current_state
|
|
69
|
+
end.extend EventArray
|
|
72
70
|
end
|
|
73
71
|
alias_method :events_from_current_state, :events
|
|
74
72
|
|
|
75
|
-
# the subset of events() whose requirements for firing are met
|
|
76
|
-
# (with the arguments supplied, if any)
|
|
77
|
-
def valid_events( *args )
|
|
78
|
-
return nil unless current_state
|
|
79
|
-
return [] unless current_state.exitable_by?( self, *args )
|
|
80
|
-
events.select {|e| e.fireable_by?( self, *args ) }.extend EventArray
|
|
81
|
-
end
|
|
82
|
-
|
|
83
73
|
# the subset of events() whose requirements for firing are NOT met
|
|
84
74
|
# (with the arguments supplied, if any)
|
|
85
75
|
def invalid_events( *args )
|
|
86
76
|
( events - valid_events( *args ) ).extend StateArray
|
|
87
77
|
end
|
|
88
78
|
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
# all states which can be reached from the current_state.
|
|
80
|
+
# Does not check transition requirements, etc.
|
|
81
|
+
def next_states
|
|
82
|
+
events.map(&:targets).compact.flatten.uniq.extend StateArray
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# transition validation
|
|
87
|
+
#
|
|
88
|
+
|
|
89
|
+
def transitions(opts={}) # .with(*args)
|
|
90
|
+
TransitionQuery.new(self, opts)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# transition requirements
|
|
96
|
-
def valid_next_states( *args )
|
|
97
|
-
vt = valid_transitions( *args )
|
|
98
|
-
vt && vt.values.flatten.uniq.extend( StateArray )
|
|
93
|
+
def valid_transitions(*args)
|
|
94
|
+
transitions.valid.with(*args)
|
|
99
95
|
end
|
|
100
96
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
events.map(&:targets).compact.flatten.uniq.extend StateArray
|
|
97
|
+
def valid_next_states(*args)
|
|
98
|
+
transitions.with(*args).targets
|
|
104
99
|
end
|
|
105
100
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def valid_transitions( *args )
|
|
109
|
-
h = {}
|
|
110
|
-
return nil unless ve = valid_events( *args )
|
|
111
|
-
ve.each do |e|
|
|
112
|
-
h[e] = e.targets.select do |s|
|
|
113
|
-
s.enterable_by?( self, *args )
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
h
|
|
101
|
+
def valid_events(*args)
|
|
102
|
+
transitions.with(*args).events
|
|
117
103
|
end
|
|
118
104
|
|
|
119
105
|
# initializes a new Transition to the given destination, with the
|
|
@@ -122,8 +108,7 @@ module StateFu
|
|
|
122
108
|
# If a block is given, it yields the Transition or is executed in
|
|
123
109
|
# its evaluation context, depending on the arity of the block.
|
|
124
110
|
def transition( event_or_array, *args, &block )
|
|
125
|
-
|
|
126
|
-
StateFu::Transition.new( self, event, target, *args, &block )
|
|
111
|
+
return transitions.with(*args, &block).find(event_or_array)
|
|
127
112
|
end
|
|
128
113
|
alias_method :fire, :transition
|
|
129
114
|
alias_method :fire_event, :transition
|
|
@@ -131,130 +116,66 @@ module StateFu
|
|
|
131
116
|
alias_method :trigger_event, :transition
|
|
132
117
|
alias_method :begin_transition, :transition
|
|
133
118
|
|
|
134
|
-
# return a MockTransition to nowhere and passes it the given
|
|
135
|
-
# *args. Useful for evaluating requirements in spec / test code.
|
|
136
|
-
def blank_mock_transition( *args, &block )
|
|
137
|
-
StateFu::MockTransition.new( self, nil, nil, *args, &block )
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# return a MockTransition; otherwise the same as #transition
|
|
141
|
-
def mock_transition( event_or_array, *args, &block )
|
|
142
|
-
event, target = nil
|
|
143
|
-
event, target = parse_destination( event_or_array )
|
|
144
|
-
StateFu::MockTransition.new( self, event, target, *args, &block )
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# sanitizes / extracts destination from *args for other methods.
|
|
148
|
-
#
|
|
149
|
-
# takes a single, simple (one target only) event,
|
|
150
|
-
# or an array of [event, target],
|
|
151
|
-
# or one of the above with symbols in place of the objects themselves.
|
|
152
|
-
def parse_destination( event_or_array )
|
|
153
|
-
case event_or_array
|
|
154
|
-
when StateFu::Event, Symbol
|
|
155
|
-
event = event_or_array
|
|
156
|
-
target = nil
|
|
157
|
-
when Array
|
|
158
|
-
event, target = *event_or_array
|
|
159
|
-
end
|
|
160
|
-
x = event_or_array.is_a?( Array ) ? event_or_array.map(&:class) : event_or_array
|
|
161
|
-
raise ArgumentError.new( x.inspect ) unless
|
|
162
|
-
[StateFu::Event, Symbol ].include?( event.class ) &&
|
|
163
|
-
[StateFu::State, Symbol, NilClass].include?( target.class )
|
|
164
|
-
[event, target]
|
|
165
|
-
end
|
|
166
|
-
|
|
167
119
|
# check that the event and target are valid (all requirements are
|
|
168
120
|
# met) with the given (optional) arguments
|
|
169
121
|
def fireable?( event_or_array, *args )
|
|
170
|
-
event, target = parse_destination( event_or_array )
|
|
171
122
|
begin
|
|
172
|
-
t = transition(
|
|
123
|
+
return nil unless t = transition( event_or_array, *args )
|
|
173
124
|
!! t.requirements_met?
|
|
174
125
|
rescue InvalidTransition => e
|
|
175
126
|
nil
|
|
176
127
|
end
|
|
177
128
|
end
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
alias_method :can_fire_event?, :fireable?
|
|
182
|
-
alias_method :trigger?, :fireable?
|
|
183
|
-
alias_method :triggerable?, :fireable?
|
|
184
|
-
alias_method :can_trigger?, :fireable?
|
|
185
|
-
alias_method :can_trigger_event?, :fireable?
|
|
186
|
-
alias_method :event_triggerable?, :fireable?
|
|
187
|
-
alias_method :transition?, :fireable?
|
|
188
|
-
alias_method :can_transition?, :fireable?
|
|
189
|
-
alias_method :transitionable?, :fireable?
|
|
190
|
-
|
|
191
|
-
# construct an event transition and fire it
|
|
129
|
+
|
|
130
|
+
# construct an event transition and fire it, returning the transition.
|
|
131
|
+
# (which is == true if the transition completed successfully.)
|
|
192
132
|
def fire!( event_or_array, *args, &block)
|
|
193
|
-
|
|
194
|
-
t = transition(
|
|
133
|
+
# TODO rather than die, try to find the next valid transition and fire that
|
|
134
|
+
t = transition(event_or_array, *args, &block )
|
|
195
135
|
t.fire!
|
|
196
|
-
t
|
|
197
136
|
end
|
|
198
|
-
alias_method :event!, :fire!
|
|
199
137
|
alias_method :trigger!, :fire!
|
|
200
138
|
alias_method :transition!, :fire!
|
|
201
139
|
|
|
202
|
-
#
|
|
203
|
-
# and
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def evaluate_requirement_with_args( name, *args )
|
|
208
|
-
t = blank_mock_transition( *args )
|
|
209
|
-
evaluate_named_proc_or_method( name, t )
|
|
210
|
-
end
|
|
211
|
-
# alias_method :evaluate_requirement, :evaluate_requirement_with_args
|
|
212
|
-
|
|
213
|
-
alias_method :evaluate_requirement_with_transition, :evaluate_named_proc_or_method
|
|
214
|
-
|
|
215
|
-
# if there is exactly one legal transition which can be fired with
|
|
140
|
+
#
|
|
141
|
+
# next_transition and friends: when there's exactly one valid move
|
|
142
|
+
#
|
|
143
|
+
|
|
144
|
+
# if there is exactly one legal & valid transition which can be fired with
|
|
216
145
|
# the given (optional) arguments, return it.
|
|
217
146
|
def next_transition( *args, &block )
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
targ = nt[1][0]
|
|
225
|
-
return transition( [ evt, targ], *args, &block )
|
|
226
|
-
end
|
|
147
|
+
transitions.with(*args, &block).next
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# as above but ignoring any transitions whose origin and target are the same
|
|
151
|
+
def next_transition_excluding_cycles( *args, &block )
|
|
152
|
+
transitions.not_cyclic.with(*args, &block).next
|
|
227
153
|
end
|
|
228
154
|
|
|
229
155
|
# if there is exactly one state reachable via a transition which
|
|
230
156
|
# is valid with the given optional arguments, return it.
|
|
231
|
-
def next_state(
|
|
232
|
-
|
|
233
|
-
nt && nt.target
|
|
157
|
+
def next_state(*args, &block)
|
|
158
|
+
transitions.with(*args, &block).next_state
|
|
234
159
|
end
|
|
235
160
|
|
|
236
161
|
# if there is exactly one event which is valid with the given
|
|
237
162
|
# optional arguments, return it
|
|
238
163
|
def next_event( *args )
|
|
239
|
-
|
|
240
|
-
nt && nt.event
|
|
164
|
+
transitions.with(*args, &block).next_event
|
|
241
165
|
end
|
|
242
|
-
|
|
166
|
+
|
|
243
167
|
# if there is a next_transition, create, fire & return it
|
|
244
168
|
# otherwise raise an InvalidTransition
|
|
245
169
|
def next!( *args, &block )
|
|
246
170
|
if t = next_transition( *args, &block )
|
|
247
171
|
t.fire!
|
|
248
|
-
t
|
|
249
172
|
else
|
|
250
|
-
|
|
251
|
-
n = vts && vts.length
|
|
252
|
-
raise InvalidTransition.
|
|
253
|
-
new( self, current_state, vts, "there are #{n} candidate transitions, need exactly 1")
|
|
173
|
+
raise TransitionNotFound.new( self, valid_transitions(*args), "Exactly 1 valid transition required.")
|
|
254
174
|
end
|
|
255
175
|
end
|
|
256
|
-
alias_method :
|
|
176
|
+
alias_method :next_transition!, :next!
|
|
257
177
|
alias_method :next_event!, :next!
|
|
178
|
+
alias_method :next_state!, :next!
|
|
258
179
|
|
|
259
180
|
# if there is a next_transition, return true / false depending on
|
|
260
181
|
# whether its requirements are met
|
|
@@ -264,37 +185,45 @@ module StateFu
|
|
|
264
185
|
t.requirements_met?
|
|
265
186
|
end
|
|
266
187
|
end
|
|
267
|
-
alias_method :next_state?, :next?
|
|
268
|
-
alias_method :next_event?, :next?
|
|
188
|
+
# alias_method :next_state?, :next?
|
|
189
|
+
# alias_method :next_event?, :next?
|
|
190
|
+
|
|
191
|
+
# Cyclic transitions (origin == target)
|
|
269
192
|
|
|
270
193
|
# if there is one possible cyclical event, return a transition there
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if
|
|
274
|
-
|
|
194
|
+
# otherwise, maybe we got an event name as an argument?
|
|
195
|
+
def cycle(event_or_array=nil, *args, &block)
|
|
196
|
+
if event_or_array.nil?
|
|
197
|
+
transitions.cyclic.with(*args, &block).singular ||
|
|
198
|
+
transitions.cyclic.with(*args, &block).valid.singular
|
|
199
|
+
else
|
|
200
|
+
transitions.cyclic.with(*args, &block).find(event_or_array)
|
|
275
201
|
end
|
|
276
202
|
end
|
|
277
203
|
|
|
278
|
-
# if there is a cycle() transition, fire and return it
|
|
204
|
+
# if there is a single possible cycle() transition, fire and return it
|
|
279
205
|
# otherwise raise an InvalidTransition
|
|
280
|
-
def cycle!( *args, &block )
|
|
281
|
-
if t = cycle( *args, &block )
|
|
206
|
+
def cycle!(event_or_array=nil, *args, &block )
|
|
207
|
+
if t = cycle(event_or_array, *args, &block )
|
|
282
208
|
t.fire!
|
|
283
209
|
t
|
|
284
210
|
else
|
|
285
|
-
|
|
286
|
-
raise InvalidTransition.new( self, current_state, current_state, err_msg )
|
|
211
|
+
raise TransitionNotFound.new( self, transitions.cyclic.with(*args,&block), "Cannot cycle! unless there is exactly one cyclic event")
|
|
287
212
|
end
|
|
288
213
|
end
|
|
289
214
|
|
|
290
215
|
# if there is one possible cyclical event, evaluate its
|
|
291
216
|
# requirements (true/false), else nil
|
|
292
|
-
def cycle?( *args )
|
|
293
|
-
if t = cycle( *args )
|
|
217
|
+
def cycle?(event_or_array=nil, *args )
|
|
218
|
+
if t = cycle(event_or_array, *args )
|
|
294
219
|
t.requirements_met?
|
|
295
220
|
end
|
|
296
221
|
end
|
|
297
222
|
|
|
223
|
+
#
|
|
224
|
+
# misc
|
|
225
|
+
#
|
|
226
|
+
|
|
298
227
|
# change the current state of the binding without any
|
|
299
228
|
# requirements or other sanity checks, or any hooks firing.
|
|
300
229
|
# Useful for test / spec scenarios, and abusing the framework.
|
|
@@ -308,12 +237,12 @@ module StateFu
|
|
|
308
237
|
attrs = [[:current_state, state_name.inspect],
|
|
309
238
|
[:object_type , @object.class],
|
|
310
239
|
[:method_name , method_name.inspect],
|
|
311
|
-
[:field_name ,
|
|
240
|
+
[:field_name , field_name.inspect],
|
|
312
241
|
[:machine , machine.inspect]].
|
|
313
242
|
map {|x| x.join('=') }.join( " " ) + ' =>|'
|
|
314
243
|
end
|
|
315
244
|
|
|
316
|
-
# let's be == the current_state_name as a symbol.
|
|
245
|
+
# let's be == (and hence ===) the current_state_name as a symbol.
|
|
317
246
|
# a nice little convenience.
|
|
318
247
|
def == other
|
|
319
248
|
if other.respond_to?( :to_sym ) && current_state
|
|
@@ -323,5 +252,53 @@ module StateFu
|
|
|
323
252
|
end
|
|
324
253
|
end
|
|
325
254
|
|
|
255
|
+
# TODO better name
|
|
256
|
+
# is this a binding unique to a specific instance (not bound to a class)?
|
|
257
|
+
def singleton?
|
|
258
|
+
options[:singleton]
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# SPECME DOCME OR KILLME
|
|
262
|
+
def reload()
|
|
263
|
+
if persister.is_a?( Persistence::ActiveRecord )
|
|
264
|
+
object.reload
|
|
265
|
+
end
|
|
266
|
+
persister.reload
|
|
267
|
+
self
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# This method is called from methods defined by MethodFactory.
|
|
271
|
+
# You don't want to call it directly.
|
|
272
|
+
def _event_method(action, event, *args)
|
|
273
|
+
target_or_options = args.shift
|
|
274
|
+
options = {}
|
|
275
|
+
case target_or_options
|
|
276
|
+
when Hash
|
|
277
|
+
options = target_or_options.symbolize_keys!
|
|
278
|
+
target = target_or_options.delete[:to]
|
|
279
|
+
when Symbol, String
|
|
280
|
+
target = target_or_options.to_sym
|
|
281
|
+
when nil
|
|
282
|
+
target = nil
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
case action
|
|
286
|
+
when :get_transition
|
|
287
|
+
transition [event, target], *args, &lambda {|t| t.options = options}
|
|
288
|
+
when :query_transition
|
|
289
|
+
fireable? [event, target], *args, &lambda {|t| t.options = options}
|
|
290
|
+
when :fire_transition
|
|
291
|
+
fire! [event, target], *args, &lambda {|t| t.options = options}
|
|
292
|
+
else
|
|
293
|
+
raise ArgumentError.new(action)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
#
|
|
298
|
+
# transition constructor
|
|
299
|
+
#
|
|
300
|
+
def new_transition(event, target, *args, &block)
|
|
301
|
+
Transition.new( self, event, target, *args, &block )
|
|
302
|
+
end
|
|
326
303
|
end
|
|
327
304
|
end
|
data/lib/state_fu/core_ext.rb
CHANGED
|
@@ -1,23 +1,91 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
|
-
# ruby1.9 style symbol comparability for ruby1.8
|
|
3
|
-
class Symbol # :nodoc:
|
|
4
|
-
unless instance_methods.include?(:'<=>')
|
|
5
|
-
def <=> other
|
|
6
|
-
self.to_s <=> other.to_s
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
2
|
|
|
11
3
|
# if ActiveSupport is absent, install a very small subset of it for
|
|
12
4
|
# some convenience methods
|
|
13
|
-
unless Object.const_defined?('ActiveSupport')
|
|
5
|
+
unless Object.const_defined?('ActiveSupport') #:nodoc
|
|
14
6
|
Dir[File.join(File.dirname( __FILE__), 'active_support_lite','**' )].sort.each do |lib|
|
|
15
7
|
next unless File.file?( lib )
|
|
16
8
|
require lib
|
|
17
9
|
end
|
|
18
10
|
|
|
19
|
-
class Hash #:nodoc
|
|
11
|
+
class Hash #:nodoc
|
|
20
12
|
include ActiveSupport::CoreExtensions::Hash::Keys
|
|
21
13
|
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# ruby1.9 style symbol comparability for ruby1.8
|
|
17
|
+
if RUBY_VERSION < "1.9"
|
|
18
|
+
class Symbol #:nodoc
|
|
19
|
+
unless instance_methods.include?(:'<=>')
|
|
20
|
+
def <=> other
|
|
21
|
+
self.to_s <=> other.to_s
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module ArrayToHash
|
|
28
|
+
def to_h
|
|
29
|
+
if RUBY_VERSION >= '1.8.7'
|
|
30
|
+
Hash[self]
|
|
31
|
+
else
|
|
32
|
+
inject({}) { |h, a| h[a.first] = a.last; h }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Array
|
|
38
|
+
include ArrayToHash unless instance_methods.include?(:to_h)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class Object
|
|
42
|
+
|
|
43
|
+
def self.__define_method( method_name, &block )
|
|
44
|
+
self.class.class_eval do
|
|
45
|
+
define_method method_name, &block
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def __define_singleton_method( method_name, &block )
|
|
50
|
+
(class << self; self; end).class_eval do
|
|
51
|
+
define_method method_name, &block
|
|
52
|
+
end
|
|
53
|
+
end
|
|
22
54
|
|
|
55
|
+
|
|
56
|
+
def with_methods_on(other)
|
|
57
|
+
(class << self; self; end).class_eval do
|
|
58
|
+
# we need some accounting to ensure that everything behaves itself when
|
|
59
|
+
# .with_methods_on is called more than once.
|
|
60
|
+
@_with_methods_on ||= []
|
|
61
|
+
if !@_with_methods_on.include?("method_missing_before_#{other.__id__}")
|
|
62
|
+
alias_method "method_missing_before_#{other.__id__}", :method_missing
|
|
63
|
+
end
|
|
64
|
+
@_with_methods_on << "method_missing_before_#{other.__id__}"
|
|
65
|
+
|
|
66
|
+
define_method :method_missing do |method_name, *args|
|
|
67
|
+
if _other.respond_to?(method_name, true)
|
|
68
|
+
_other.__send__( method_name, *args )
|
|
69
|
+
else
|
|
70
|
+
send "method_missing_before_#{other.__id__}", method_name, *args
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
result = yield
|
|
76
|
+
|
|
77
|
+
(class << self; self; end).class_eval do
|
|
78
|
+
# heal the damage
|
|
79
|
+
if @_with_methods_on.pop != "method_missing_before_#{other.__id__}"
|
|
80
|
+
raise "there is no god"
|
|
81
|
+
end
|
|
82
|
+
if !@_with_methods_on.include?("method_missing_before_#{other.__id__}")
|
|
83
|
+
alias_method :method_missing, "method_missing_before_#{other.__id__}"
|
|
84
|
+
undef_method "method_missing_before_#{other.__id__}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
result
|
|
89
|
+
end # with_methods_on
|
|
23
90
|
end
|
|
91
|
+
|