ultra-smart-sys 0.0.1

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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/state_machines-0.201.0/LICENSE.txt +23 -0
  3. data/state_machines-0.201.0/README.md +1024 -0
  4. data/state_machines-0.201.0/lib/state_machines/async_mode/async_event_extensions.rb +49 -0
  5. data/state_machines-0.201.0/lib/state_machines/async_mode/async_events.rb +282 -0
  6. data/state_machines-0.201.0/lib/state_machines/async_mode/async_machine.rb +60 -0
  7. data/state_machines-0.201.0/lib/state_machines/async_mode/async_transition_collection.rb +136 -0
  8. data/state_machines-0.201.0/lib/state_machines/async_mode/thread_safe_state.rb +47 -0
  9. data/state_machines-0.201.0/lib/state_machines/async_mode.rb +64 -0
  10. data/state_machines-0.201.0/lib/state_machines/branch.rb +246 -0
  11. data/state_machines-0.201.0/lib/state_machines/callback.rb +223 -0
  12. data/state_machines-0.201.0/lib/state_machines/core.rb +43 -0
  13. data/state_machines-0.201.0/lib/state_machines/core_ext/class/state_machine.rb +5 -0
  14. data/state_machines-0.201.0/lib/state_machines/core_ext.rb +4 -0
  15. data/state_machines-0.201.0/lib/state_machines/error.rb +115 -0
  16. data/state_machines-0.201.0/lib/state_machines/eval_helpers.rb +227 -0
  17. data/state_machines-0.201.0/lib/state_machines/event.rb +247 -0
  18. data/state_machines-0.201.0/lib/state_machines/event_collection.rb +149 -0
  19. data/state_machines-0.201.0/lib/state_machines/extensions.rb +150 -0
  20. data/state_machines-0.201.0/lib/state_machines/helper_module.rb +19 -0
  21. data/state_machines-0.201.0/lib/state_machines/integrations/base.rb +49 -0
  22. data/state_machines-0.201.0/lib/state_machines/integrations.rb +111 -0
  23. data/state_machines-0.201.0/lib/state_machines/machine/action_hooks.rb +53 -0
  24. data/state_machines-0.201.0/lib/state_machines/machine/async_extensions.rb +88 -0
  25. data/state_machines-0.201.0/lib/state_machines/machine/callbacks.rb +333 -0
  26. data/state_machines-0.201.0/lib/state_machines/machine/class_methods.rb +95 -0
  27. data/state_machines-0.201.0/lib/state_machines/machine/configuration.rb +128 -0
  28. data/state_machines-0.201.0/lib/state_machines/machine/event_methods.rb +436 -0
  29. data/state_machines-0.201.0/lib/state_machines/machine/helper_generators.rb +125 -0
  30. data/state_machines-0.201.0/lib/state_machines/machine/integration.rb +92 -0
  31. data/state_machines-0.201.0/lib/state_machines/machine/parsing.rb +77 -0
  32. data/state_machines-0.201.0/lib/state_machines/machine/rendering.rb +17 -0
  33. data/state_machines-0.201.0/lib/state_machines/machine/scoping.rb +44 -0
  34. data/state_machines-0.201.0/lib/state_machines/machine/state_methods.rb +398 -0
  35. data/state_machines-0.201.0/lib/state_machines/machine/utilities.rb +86 -0
  36. data/state_machines-0.201.0/lib/state_machines/machine/validation.rb +39 -0
  37. data/state_machines-0.201.0/lib/state_machines/machine.rb +615 -0
  38. data/state_machines-0.201.0/lib/state_machines/machine_collection.rb +105 -0
  39. data/state_machines-0.201.0/lib/state_machines/macro_methods.rb +522 -0
  40. data/state_machines-0.201.0/lib/state_machines/matcher.rb +124 -0
  41. data/state_machines-0.201.0/lib/state_machines/matcher_helpers.rb +56 -0
  42. data/state_machines-0.201.0/lib/state_machines/node_collection.rb +226 -0
  43. data/state_machines-0.201.0/lib/state_machines/options_validator.rb +72 -0
  44. data/state_machines-0.201.0/lib/state_machines/path.rb +123 -0
  45. data/state_machines-0.201.0/lib/state_machines/path_collection.rb +91 -0
  46. data/state_machines-0.201.0/lib/state_machines/state.rb +314 -0
  47. data/state_machines-0.201.0/lib/state_machines/state_collection.rb +113 -0
  48. data/state_machines-0.201.0/lib/state_machines/state_context.rb +134 -0
  49. data/state_machines-0.201.0/lib/state_machines/stdio_renderer.rb +74 -0
  50. data/state_machines-0.201.0/lib/state_machines/syntax_validator.rb +54 -0
  51. data/state_machines-0.201.0/lib/state_machines/test_helper.rb +775 -0
  52. data/state_machines-0.201.0/lib/state_machines/transition.rb +593 -0
  53. data/state_machines-0.201.0/lib/state_machines/transition_collection.rb +310 -0
  54. data/state_machines-0.201.0/lib/state_machines/version.rb +5 -0
  55. data/state_machines-0.201.0/lib/state_machines.rb +6 -0
  56. data/ultra-smart-sys.gemspec +12 -0
  57. metadata +96 -0
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ class Machine
5
+ module Callbacks
6
+ # Creates a callback that will be invoked *before* a transition is
7
+ # performed so long as the given requirements match the transition.
8
+ #
9
+ # == The callback
10
+ #
11
+ # Callbacks must be defined as either an argument, in the :do option, or
12
+ # as a block. For example,
13
+ #
14
+ # class Vehicle
15
+ # state_machine do
16
+ # before_transition :set_alarm
17
+ # before_transition :set_alarm, all => :parked
18
+ # before_transition all => :parked, :do => :set_alarm
19
+ # before_transition all => :parked do |vehicle, transition|
20
+ # vehicle.set_alarm
21
+ # end
22
+ # ...
23
+ # end
24
+ # end
25
+ #
26
+ # Notice that the first three callbacks are the same in terms of how the
27
+ # methods to invoke are defined. However, using the <tt>:do</tt> can
28
+ # provide for a more fluid DSL.
29
+ #
30
+ # In addition, multiple callbacks can be defined like so:
31
+ #
32
+ # class Vehicle
33
+ # state_machine do
34
+ # before_transition :set_alarm, :lock_doors, all => :parked
35
+ # before_transition all => :parked, :do => [:set_alarm, :lock_doors]
36
+ # before_transition :set_alarm do |vehicle, transition|
37
+ # vehicle.lock_doors
38
+ # end
39
+ # end
40
+ # end
41
+ #
42
+ # Notice that the different ways of configuring methods can be mixed.
43
+ #
44
+ # == State requirements
45
+ #
46
+ # Callbacks can require that the machine be transitioning from and to
47
+ # specific states. These requirements use a Hash syntax to map beginning
48
+ # states to ending states. For example,
49
+ #
50
+ # before_transition :parked => :idling, :idling => :first_gear, :do => :set_alarm
51
+ #
52
+ # In this case, the +set_alarm+ callback will only be called if the machine
53
+ # is transitioning from +parked+ to +idling+ or from +idling+ to +parked+.
54
+ #
55
+ # To help define state requirements, a set of helpers are available for
56
+ # slightly more complex matching:
57
+ # * <tt>all</tt> - Matches every state/event in the machine
58
+ # * <tt>all - [:parked, :idling, ...]</tt> - Matches every state/event except those specified
59
+ # * <tt>any</tt> - An alias for +all+ (matches every state/event in the machine)
60
+ # * <tt>same</tt> - Matches the same state being transitioned from
61
+ #
62
+ # See StateMachines::MatcherHelpers for more information.
63
+ #
64
+ # Examples:
65
+ #
66
+ # before_transition :parked => [:idling, :first_gear], :do => ... # Matches from parked to idling or first_gear
67
+ # before_transition all - [:parked, :idling] => :idling, :do => ... # Matches from every state except parked and idling to idling
68
+ # before_transition all => :parked, :do => ... # Matches all states to parked
69
+ # before_transition any => same, :do => ... # Matches every loopback
70
+ #
71
+ # == Event requirements
72
+ #
73
+ # In addition to state requirements, an event requirement can be defined so
74
+ # that the callback is only invoked on specific events using the +on+
75
+ # option. This can also use the same matcher helpers as the state
76
+ # requirements.
77
+ #
78
+ # Examples:
79
+ #
80
+ # before_transition :on => :ignite, :do => ... # Matches only on ignite
81
+ # before_transition :on => all - :ignite, :do => ... # Matches on every event except ignite
82
+ # before_transition :parked => :idling, :on => :ignite, :do => ... # Matches from parked to idling on ignite
83
+ #
84
+ # == Verbose Requirements
85
+ #
86
+ # Requirements can also be defined using verbose options rather than the
87
+ # implicit Hash syntax and helper methods described above.
88
+ #
89
+ # Configuration options:
90
+ # * <tt>:from</tt> - One or more states being transitioned from. If none
91
+ # are specified, then all states will match.
92
+ # * <tt>:to</tt> - One or more states being transitioned to. If none are
93
+ # specified, then all states will match.
94
+ # * <tt>:on</tt> - One or more events that fired the transition. If none
95
+ # are specified, then all events will match.
96
+ # * <tt>:except_from</tt> - One or more states *not* being transitioned from
97
+ # * <tt>:except_to</tt> - One more states *not* being transitioned to
98
+ # * <tt>:except_on</tt> - One or more events that *did not* fire the transition
99
+ #
100
+ # Examples:
101
+ #
102
+ # before_transition :from => :ignite, :to => :idling, :on => :park, :do => ...
103
+ # before_transition :except_from => :ignite, :except_to => :idling, :except_on => :park, :do => ...
104
+ #
105
+ # == Conditions
106
+ #
107
+ # In addition to the state/event requirements, a condition can also be
108
+ # defined to help determine whether the callback should be invoked.
109
+ #
110
+ # Configuration options:
111
+ # * <tt>:if</tt> - A method, proc or string to call to determine if the
112
+ # callback should occur (e.g. :if => :allow_callbacks, or
113
+ # :if => lambda {|user| user.signup_step > 2}). The method, proc or string
114
+ # should return or evaluate to a true or false value.
115
+ # * <tt>:unless</tt> - A method, proc or string to call to determine if the
116
+ # callback should not occur (e.g. :unless => :skip_callbacks, or
117
+ # :unless => lambda {|user| user.signup_step <= 2}). The method, proc or
118
+ # string should return or evaluate to a true or false value.
119
+ #
120
+ # Examples:
121
+ #
122
+ # before_transition :parked => :idling, :if => :moving?, :do => ...
123
+ # before_transition :on => :ignite, :unless => :seatbelt_on?, :do => ...
124
+ #
125
+ # == Accessing the transition
126
+ #
127
+ # In addition to passing the object being transitioned, the actual
128
+ # transition describing the context (e.g. event, from, to) can be accessed
129
+ # as well. This additional argument is only passed if the callback allows
130
+ # for it.
131
+ #
132
+ # For example,
133
+ #
134
+ # class Vehicle
135
+ # # Only specifies one parameter (the object being transitioned)
136
+ # before_transition all => :parked do |vehicle|
137
+ # vehicle.set_alarm
138
+ # end
139
+ #
140
+ # # Specifies 2 parameters (object being transitioned and actual transition)
141
+ # before_transition all => :parked do |vehicle, transition|
142
+ # vehicle.set_alarm(transition)
143
+ # end
144
+ # end
145
+ #
146
+ # *Note* that the object in the callback will only be passed in as an
147
+ # argument if callbacks are configured to *not* be bound to the object
148
+ # involved. This is the default and may change on a per-integration basis.
149
+ #
150
+ # See StateMachines::Transition for more information about the
151
+ # attributes available on the transition.
152
+ #
153
+ # == Usage with delegates
154
+ #
155
+ # As noted above, state_machine uses the callback method's argument list
156
+ # arity to determine whether to include the transition in the method call.
157
+ # If you're using delegates, such as those defined in ActiveSupport or
158
+ # Forwardable, the actual arity of the delegated method gets masked. This
159
+ # means that callbacks which reference delegates will always get passed the
160
+ # transition as an argument. For example:
161
+ #
162
+ # class Vehicle
163
+ # extend Forwardable
164
+ # delegate :refresh => :dashboard
165
+ #
166
+ # state_machine do
167
+ # before_transition :refresh
168
+ # ...
169
+ # end
170
+ #
171
+ # def dashboard
172
+ # @dashboard ||= Dashboard.new
173
+ # end
174
+ # end
175
+ #
176
+ # class Dashboard
177
+ # def refresh(transition)
178
+ # # ...
179
+ # end
180
+ # end
181
+ #
182
+ # In the above example, <tt>Dashboard#refresh</tt> *must* defined a
183
+ # +transition+ argument. Otherwise, an +ArgumentError+ exception will get
184
+ # raised. The only way around this is to avoid the use of delegates and
185
+ # manually define the delegate method so that the correct arity is used.
186
+ #
187
+ # == Examples
188
+ #
189
+ # Below is an example of a class with one state machine and various types
190
+ # of +before+ transitions defined for it:
191
+ #
192
+ # class Vehicle
193
+ # state_machine do
194
+ # # Before all transitions
195
+ # before_transition :update_dashboard
196
+ #
197
+ # # Before specific transition:
198
+ # before_transition [:first_gear, :idling] => :parked, :on => :park, :do => :take_off_seatbelt
199
+ #
200
+ # # With conditional callback:
201
+ # before_transition all => :parked, :do => :take_off_seatbelt, :if => :seatbelt_on?
202
+ #
203
+ # # Using helpers:
204
+ # before_transition all - :stalled => same, :on => any - :crash, :do => :update_dashboard
205
+ # ...
206
+ # end
207
+ # end
208
+ #
209
+ # As can be seen, any number of transitions can be created using various
210
+ # combinations of configuration options.
211
+ def before_transition(*args, **options, &)
212
+ add_transition_callback(:before, args, options, &)
213
+ end
214
+
215
+ # Creates a callback that will be invoked *after* a transition is
216
+ # performed so long as the given requirements match the transition.
217
+ #
218
+ # See +before_transition+ for a description of the possible configurations
219
+ # for defining callbacks.
220
+ def after_transition(*args, **options, &)
221
+ add_transition_callback(:after, args, options, &)
222
+ end
223
+
224
+ # Creates a callback that will be invoked *around* a transition so long as
225
+ # the given requirements match the transition.
226
+ #
227
+ # == The callback
228
+ #
229
+ # Around callbacks wrap transitions, executing code both before and after.
230
+ # These callbacks are defined in the exact same manner as before / after
231
+ # callbacks with the exception that the transition must be yielded to in
232
+ # order to finish running it.
233
+ #
234
+ # If defining +around+ callbacks using blocks, you must yield within the
235
+ # transition by directly calling the block (since yielding is not allowed
236
+ # within blocks).
237
+ #
238
+ # For example,
239
+ #
240
+ # class Vehicle
241
+ # state_machine do
242
+ # around_transition do |block|
243
+ # Benchmark.measure { block.call }
244
+ # end
245
+ #
246
+ # around_transition do |vehicle, block|
247
+ # logger.info "vehicle was #{state}..."
248
+ # block.call
249
+ # logger.info "...and is now #{state}"
250
+ # end
251
+ #
252
+ # around_transition do |vehicle, transition, block|
253
+ # logger.info "before #{transition.event}: #{vehicle.state}"
254
+ # block.call
255
+ # logger.info "after #{transition.event}: #{vehicle.state}"
256
+ # end
257
+ # end
258
+ # end
259
+ #
260
+ # Notice that referencing the block is similar to doing so within an
261
+ # actual method definition in that it is always the last argument.
262
+ #
263
+ # On the other hand, if you're defining +around+ callbacks using method
264
+ # references, you can yield like normal:
265
+ #
266
+ # class Vehicle
267
+ # state_machine do
268
+ # around_transition :benchmark
269
+ # ...
270
+ # end
271
+ #
272
+ # def benchmark
273
+ # Benchmark.measure { yield }
274
+ # end
275
+ # end
276
+ #
277
+ # See +before_transition+ for a description of the possible configurations
278
+ # for defining callbacks.
279
+ def around_transition(*args, **options, &)
280
+ add_transition_callback(:around, args, options, &)
281
+ end
282
+
283
+ # Creates a callback that will be invoked *after* a transition failures to
284
+ # be performed so long as the given requirements match the transition.
285
+ #
286
+ # See +before_transition+ for a description of the possible configurations
287
+ # for defining callbacks. *Note* however that you cannot define the state
288
+ # requirements in these callbacks. You may only define event requirements.
289
+ #
290
+ # = The callback
291
+ #
292
+ # Failure callbacks get invoked whenever an event fails to execute. This
293
+ # can happen when no transition is available, a +before+ callback halts
294
+ # execution, or the action associated with this machine fails to succeed.
295
+ # In any of these cases, any failure callback that matches the attempted
296
+ # transition will be run.
297
+ #
298
+ # For example,
299
+ #
300
+ # class Vehicle
301
+ # state_machine do
302
+ # after_failure do |vehicle, transition|
303
+ # logger.error "vehicle #{vehicle} failed to transition on #{transition.event}"
304
+ # end
305
+ #
306
+ # after_failure :on => :ignite, :do => :log_ignition_failure
307
+ #
308
+ # ...
309
+ # end
310
+ # end
311
+ def after_failure(*args, **options, &)
312
+ # Extract legacy positional arguments and merge with keyword options
313
+ parsed_options = parse_callback_arguments(args, options)
314
+ StateMachines::OptionsValidator.assert_valid_keys!(parsed_options, :on, :do, :if, :unless)
315
+
316
+ add_callback(:failure, parsed_options, &)
317
+ end
318
+
319
+ private
320
+
321
+ def add_transition_callback(type, args, options, &)
322
+ # Extract legacy positional arguments and merge with keyword options
323
+ parsed_options = parse_callback_arguments(args, options)
324
+
325
+ # Only validate callback-specific options, not state transition requirements
326
+ callback_options = parsed_options.slice(:do, :if, :unless, :bind_to_object, :terminator)
327
+ StateMachines::OptionsValidator.assert_valid_keys!(callback_options, :do, :if, :unless, :bind_to_object, :terminator)
328
+
329
+ add_callback(type, parsed_options, &)
330
+ end
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ class Machine
5
+ module ClassMethods
6
+ # Attempts to find or create a state machine for the given class. For
7
+ # example,
8
+ #
9
+ # StateMachines::Machine.find_or_create(Vehicle)
10
+ # StateMachines::Machine.find_or_create(Vehicle, :initial => :parked)
11
+ # StateMachines::Machine.find_or_create(Vehicle, :status)
12
+ # StateMachines::Machine.find_or_create(Vehicle, :status, :initial => :parked)
13
+ #
14
+ # If a machine of the given name already exists in one of the class's
15
+ # superclasses, then a copy of that machine will be created and stored
16
+ # in the new owner class (the original will remain unchanged).
17
+ def find_or_create(owner_class, *args, &)
18
+ options = args.last.is_a?(Hash) ? args.pop : {}
19
+ name = args.first || :state
20
+
21
+ # Find an existing machine
22
+ machine = (owner_class.respond_to?(:state_machines) &&
23
+ ((args.first && owner_class.state_machines[name]) || (!args.first &&
24
+ owner_class.state_machines.values.first))) || nil
25
+
26
+ if machine
27
+ # Only create a new copy if changes are being made to the machine in
28
+ # a subclass
29
+ if machine.owner_class != owner_class && (options.any? || block_given?)
30
+ machine = machine.clone
31
+ machine.initial_state = options[:initial] if options.include?(:initial)
32
+ machine.owner_class = owner_class
33
+ # Configure async mode if requested in options
34
+ machine.configure_async_mode!(options[:async]) if options.include?(:async)
35
+ end
36
+
37
+ # Evaluate DSL
38
+ machine.instance_eval(&) if block_given?
39
+ else
40
+ # No existing machine: create a new one
41
+ machine = new(owner_class, name, options, &)
42
+ end
43
+
44
+ machine
45
+ end
46
+
47
+ def draw(*)
48
+ raise NotImplementedError
49
+ end
50
+
51
+ # Default messages to use for validation errors in ORM integrations
52
+ # Thread-safe access via atomic operations on simple values
53
+ attr_accessor :ignore_method_conflicts
54
+
55
+ def default_messages
56
+ @default_messages ||= {
57
+ invalid: 'is invalid',
58
+ invalid_event: 'cannot transition when %s',
59
+ invalid_transition: 'cannot transition via "%1$s"'
60
+ }.freeze
61
+ end
62
+
63
+ def default_messages=(messages)
64
+ # Atomic replacement with frozen object
65
+ @default_messages = deep_freeze_hash(messages)
66
+ end
67
+
68
+ def replace_messages(message_hash)
69
+ # Atomic replacement: read current messages, merge with new ones, replace atomically
70
+ current_messages = @default_messages || {}
71
+ merged_messages = current_messages.merge(message_hash)
72
+ @default_messages = deep_freeze_hash(merged_messages)
73
+ end
74
+
75
+ attr_writer :renderer
76
+
77
+ def renderer
78
+ return @renderer if @renderer
79
+
80
+ STDIORenderer
81
+ end
82
+
83
+ private
84
+
85
+ # Deep freezes a hash and all its string values for thread safety
86
+ def deep_freeze_hash(hash)
87
+ hash.each_with_object({}) do |(key, value), frozen_hash|
88
+ frozen_key = key.respond_to?(:freeze) ? key.freeze : key
89
+ frozen_value = value.respond_to?(:freeze) ? value.freeze : value
90
+ frozen_hash[frozen_key] = frozen_value
91
+ end.freeze
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ class Machine
5
+ module Configuration
6
+ # Initializes a new state machine with the given configuration.
7
+ def initialize(owner_class, *args, &)
8
+ options = args.last.is_a?(Hash) ? args.pop : {}
9
+
10
+ # Find an integration that matches this machine's owner class
11
+ @integration = if options.include?(:integration)
12
+ options[:integration] && StateMachines::Integrations.find_by_name(options[:integration])
13
+ else
14
+ StateMachines::Integrations.match(owner_class)
15
+ end
16
+
17
+ # Validate options including integration-specific options
18
+ valid_keys = [:attribute, :initial, :initialize, :action, :plural, :namespace, :integration, :messages, :use_transactions, :async]
19
+ valid_keys += @integration.integration_options if @integration
20
+ StateMachines::OptionsValidator.assert_valid_keys!(options, valid_keys)
21
+
22
+ if @integration
23
+ extend @integration
24
+ options = (@integration.defaults || {}).merge(options)
25
+ end
26
+
27
+ # Add machine-wide defaults
28
+ options = { use_transactions: true, initialize: true }.merge(options)
29
+
30
+ # Set machine configuration
31
+ @name = args.first || :state
32
+ @attribute = options[:attribute] || @name
33
+ @events = EventCollection.new(self)
34
+ @states = StateCollection.new(self)
35
+ @callbacks = { before: [], after: [], failure: [] }
36
+ @namespace = options[:namespace]
37
+ @messages = options[:messages] || {}
38
+ @action = options[:action]
39
+ @use_transactions = options[:use_transactions]
40
+ @initialize_state = options[:initialize]
41
+ @action_hook_defined = false
42
+ @async_requested = options[:async]
43
+
44
+ self.owner_class = owner_class
45
+
46
+ # Merge with sibling machine configurations
47
+ add_sibling_machine_configs
48
+
49
+ # Define class integration
50
+ define_helpers
51
+ define_scopes(options[:plural])
52
+ after_initialize
53
+
54
+ # Evaluate DSL
55
+ instance_eval(&) if block_given?
56
+
57
+ # Configure async mode if requested, after owner_class is set and DSL is evaluated
58
+ configure_async_mode!(true) if @async_requested
59
+
60
+ self.initial_state = options[:initial] unless sibling_machines.any?
61
+ end
62
+
63
+ # Creates a copy of this machine in addition to copies of each associated
64
+ # event/states/callback, so that the modifications to those collections do
65
+ # not affect the original machine.
66
+ def initialize_copy(orig) # :nodoc:
67
+ super
68
+
69
+ @events = @events.dup
70
+ @events.machine = self
71
+ @states = @states.dup
72
+ @states.machine = self
73
+ @callbacks = { before: @callbacks[:before].dup, after: @callbacks[:after].dup, failure: @callbacks[:failure].dup }
74
+ @async_requested = orig.instance_variable_get(:@async_requested)
75
+ @async_mode_enabled = orig.instance_variable_get(:@async_mode_enabled)
76
+ end
77
+
78
+ # Sets the class which is the owner of this state machine. Any methods
79
+ # generated by states, events, or other parts of the machine will be defined
80
+ # on the given owner class.
81
+ def owner_class=(klass)
82
+ @owner_class = klass
83
+
84
+ # Create modules for extending the class with state/event-specific methods
85
+ @helper_modules = helper_modules = { instance: HelperModule.new(self, :instance), class: HelperModule.new(self, :class) }
86
+ owner_class.class_eval do
87
+ extend helper_modules[:class]
88
+ include helper_modules[:instance]
89
+ end
90
+
91
+ # Add class-/instance-level methods to the owner class for state initialization
92
+ unless owner_class < StateMachines::InstanceMethods
93
+ owner_class.class_eval do
94
+ extend StateMachines::ClassMethods
95
+ include StateMachines::InstanceMethods
96
+ end
97
+
98
+ define_state_initializer if @initialize_state
99
+ end
100
+
101
+ # Record this machine as matched to the name in the current owner class.
102
+ # This will override any machines mapped to the same name in any superclasses.
103
+ owner_class.state_machines[name] = self
104
+ end
105
+
106
+ # Sets the initial state of the machine. This can be either the static name
107
+ # of a state or a lambda block which determines the initial state at
108
+ # creation time.
109
+ def initial_state=(new_initial_state)
110
+ @initial_state = new_initial_state
111
+ add_states([@initial_state]) unless dynamic_initial_state?
112
+
113
+ # Update all states to reflect the new initial state
114
+ states.each { |state| state.initial = (state.name == @initial_state) }
115
+
116
+ # Warn if the owner class and the machine have conflicting defaults for
117
+ # the machine's attribute. May be deferred by integrations (e.g.
118
+ # ActiveRecord) to avoid touching the DB at class load time.
119
+ schedule_conflicting_attribute_default_check
120
+ end
121
+
122
+ # Gets the attribute name for the given machine scope.
123
+ def attribute(name = :state)
124
+ name == :state ? @attribute : :"#{self.name}_#{name}"
125
+ end
126
+ end
127
+ end
128
+ end