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,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'options_validator'
4
+
5
+ module StateMachines
6
+ # Represents a set of requirements that must be met in order for a transition
7
+ # or callback to occur. Branches verify that the event, from state, and to
8
+ # state of the transition match, in addition to if/unless conditionals for
9
+ # an object's state.
10
+ class Branch
11
+ include EvalHelpers
12
+
13
+ # The condition that must be met on an object
14
+ attr_reader :if_condition
15
+
16
+ # The condition that must *not* be met on an object
17
+ attr_reader :unless_condition
18
+
19
+ # The requirement for verifying the event being matched
20
+ attr_reader :event_requirement
21
+
22
+ # One or more requirements for verifying the states being matched. All
23
+ # requirements contain a mapping of {:from => matcher, :to => matcher}.
24
+ attr_reader :state_requirements
25
+
26
+ # A list of all of the states known to this branch. This will pull states
27
+ # from the following options (in the same order):
28
+ # * +from+ / +except_from+
29
+ # * +to+ / +except_to+
30
+ attr_reader :known_states
31
+
32
+ # Creates a new branch
33
+ def initialize(options = {}) # :nodoc:
34
+ # Build conditionals
35
+ @if_condition = options.delete(:if)
36
+ @unless_condition = options.delete(:unless)
37
+ @if_state_condition = options.delete(:if_state)
38
+ @unless_state_condition = options.delete(:unless_state)
39
+ @if_all_states_condition = options.delete(:if_all_states)
40
+ @unless_all_states_condition = options.delete(:unless_all_states)
41
+ @if_any_state_condition = options.delete(:if_any_state)
42
+ @unless_any_state_condition = options.delete(:unless_any_state)
43
+
44
+ # Build event requirement
45
+ @event_requirement = build_matcher(options, :on, :except_on)
46
+
47
+ if (options.keys - %i[from to on except_from except_to except_on]).empty?
48
+ # Explicit from/to requirements specified
49
+ @state_requirements = [{ from: build_matcher(options, :from, :except_from), to: build_matcher(options, :to, :except_to) }]
50
+ else
51
+ # Separate out the event requirement
52
+ options.delete(:on)
53
+ options.delete(:except_on)
54
+
55
+ # Implicit from/to requirements specified
56
+ @state_requirements = options.collect do |from, to|
57
+ from = WhitelistMatcher.new(from) unless from.is_a?(Matcher)
58
+ to = WhitelistMatcher.new(to) unless to.is_a?(Matcher)
59
+ { from: from, to: to }
60
+ end
61
+ end
62
+
63
+ # Track known states. The order that requirements are iterated is based
64
+ # on the priority in which tracked states should be added.
65
+ @known_states = []
66
+ @state_requirements.each do |state_requirement|
67
+ %i[from to].each { |option| @known_states |= state_requirement[option].values }
68
+ end
69
+ end
70
+
71
+ # Determines whether the given object / query matches the requirements
72
+ # configured for this branch. In addition to matching the event, from state,
73
+ # and to state, this will also check whether the configured :if/:unless
74
+ # conditions pass on the given object.
75
+ #
76
+ # == Examples
77
+ #
78
+ # branch = StateMachines::Branch.new(:parked => :idling, :on => :ignite)
79
+ #
80
+ # # Successful
81
+ # branch.matches?(object, :on => :ignite) # => true
82
+ # branch.matches?(object, :from => nil) # => true
83
+ # branch.matches?(object, :from => :parked) # => true
84
+ # branch.matches?(object, :to => :idling) # => true
85
+ # branch.matches?(object, :from => :parked, :to => :idling) # => true
86
+ # branch.matches?(object, :on => :ignite, :from => :parked, :to => :idling) # => true
87
+ #
88
+ # # Unsuccessful
89
+ # branch.matches?(object, :on => :park) # => false
90
+ # branch.matches?(object, :from => :idling) # => false
91
+ # branch.matches?(object, :to => :first_gear) # => false
92
+ # branch.matches?(object, :from => :parked, :to => :first_gear) # => false
93
+ # branch.matches?(object, :on => :park, :from => :parked, :to => :idling) # => false
94
+ def matches?(object, query = {})
95
+ !match(object, query).nil?
96
+ end
97
+
98
+ # Alias for Minitest's assert_match
99
+ alias =~ matches?
100
+
101
+ # Attempts to match the given object / query against the set of requirements
102
+ # configured for this branch. In addition to matching the event, from state,
103
+ # and to state, this will also check whether the configured :if/:unless
104
+ # conditions pass on the given object.
105
+ #
106
+ # If a match is found, then the event/state requirements that the query
107
+ # passed successfully will be returned. Otherwise, nil is returned if there
108
+ # was no match.
109
+ #
110
+ # Query options:
111
+ # * <tt>:from</tt> - One or more states being transitioned from. If none
112
+ # are specified, then this will always match.
113
+ # * <tt>:to</tt> - One or more states being transitioned to. If none are
114
+ # specified, then this will always match.
115
+ # * <tt>:on</tt> - One or more events that fired the transition. If none
116
+ # are specified, then this will always match.
117
+ # * <tt>:guard</tt> - Whether to guard matches with the if/unless
118
+ # conditionals defined for this branch. Default is true.
119
+ #
120
+ # Event arguments are passed to guard conditions if they accept multiple parameters.
121
+ #
122
+ # == Examples
123
+ #
124
+ # branch = StateMachines::Branch.new(:parked => :idling, :on => :ignite)
125
+ #
126
+ # branch.match(object, :on => :ignite) # => {:to => ..., :from => ..., :on => ...}
127
+ # branch.match(object, :on => :park) # => nil
128
+ def match(object, query = {}, event_args = [])
129
+ StateMachines::OptionsValidator.assert_valid_keys!(query, :from, :to, :on, :guard)
130
+
131
+ return unless (match = match_query(query)) && matches_conditions?(object, query, event_args)
132
+
133
+ match
134
+ end
135
+
136
+ def draw(graph, event, valid_states, io = $stdout)
137
+ machine.renderer.draw_branch(self, graph, event, valid_states, io)
138
+ end
139
+
140
+ protected
141
+
142
+ # Builds a matcher strategy to use for the given options. If neither a
143
+ # whitelist nor a blacklist option is specified, then an AllMatcher is
144
+ # built.
145
+ def build_matcher(options, whitelist_option, blacklist_option)
146
+ StateMachines::OptionsValidator.assert_exclusive_keys!(options, whitelist_option, blacklist_option)
147
+
148
+ if options.include?(whitelist_option)
149
+ value = options[whitelist_option]
150
+ value.is_a?(Matcher) ? value : WhitelistMatcher.new(options[whitelist_option])
151
+ elsif options.include?(blacklist_option)
152
+ value = options[blacklist_option]
153
+ raise ArgumentError, ":#{blacklist_option} option cannot use matchers; use :#{whitelist_option} instead" if value.is_a?(Matcher)
154
+
155
+ BlacklistMatcher.new(value)
156
+ else
157
+ AllMatcher.instance
158
+ end
159
+ end
160
+
161
+ # Verifies that all configured requirements (event and state) match the
162
+ # given query. If a match is found, then a hash containing the
163
+ # event/state requirements that passed will be returned; otherwise, nil.
164
+ def match_query(query)
165
+ query ||= {}
166
+
167
+ if match_event(query) && (state_requirement = match_states(query))
168
+ state_requirement.merge(on: event_requirement)
169
+ end
170
+ end
171
+
172
+ # Verifies that the event requirement matches the given query
173
+ def match_event(query)
174
+ matches_requirement?(query, :on, event_requirement)
175
+ end
176
+
177
+ # Verifies that the state requirements match the given query. If a
178
+ # matching requirement is found, then it is returned.
179
+ def match_states(query)
180
+ state_requirements.detect do |state_requirement|
181
+ %i[from to].all? { |option| matches_requirement?(query, option, state_requirement[option]) }
182
+ end
183
+ end
184
+
185
+ # Verifies that an option in the given query matches the values required
186
+ # for that option
187
+ def matches_requirement?(query, option, requirement)
188
+ !query.include?(option) || requirement.matches?(query[option], query)
189
+ end
190
+
191
+ # Verifies that the conditionals for this branch evaluate to true for the
192
+ # given object. Event arguments are passed to guards that accept multiple parameters.
193
+ def matches_conditions?(object, query, event_args = [])
194
+ return true if query[:guard] == false
195
+
196
+ # Evaluate original if/unless conditions
197
+ if_passes = !if_condition || Array(if_condition).all? { |condition| evaluate_method_with_event_args(object, condition, event_args) }
198
+ unless_passes = !unless_condition || Array(unless_condition).none? { |condition| evaluate_method_with_event_args(object, condition, event_args) }
199
+
200
+ return false unless if_passes && unless_passes
201
+
202
+ # Consolidate all state guards
203
+ state_guards = {
204
+ if_state: @if_state_condition,
205
+ unless_state: @unless_state_condition,
206
+ if_all_states: @if_all_states_condition,
207
+ unless_all_states: @unless_all_states_condition,
208
+ if_any_state: @if_any_state_condition,
209
+ unless_any_state: @unless_any_state_condition
210
+ }.compact
211
+
212
+ return true if state_guards.empty?
213
+
214
+ validate_and_check_state_guards(object, state_guards)
215
+ end
216
+
217
+ private
218
+
219
+ def validate_and_check_state_guards(object, guards)
220
+ guards.all? do |guard_type, conditions|
221
+ case guard_type
222
+ when :if_state, :if_all_states
223
+ conditions.all? { |machine, state| check_state(object, machine, state) }
224
+ when :unless_state
225
+ conditions.none? { |machine, state| check_state(object, machine, state) }
226
+ when :if_any_state
227
+ conditions.any? { |machine, state| check_state(object, machine, state) }
228
+ when :unless_all_states
229
+ !conditions.all? { |machine, state| check_state(object, machine, state) }
230
+ when :unless_any_state
231
+ conditions.none? { |machine, state| check_state(object, machine, state) }
232
+ end
233
+ end
234
+ end
235
+
236
+ def check_state(object, machine_name, state_name)
237
+ machine = object.class.state_machines[machine_name]
238
+ raise ArgumentError, "State machine '#{machine_name}' is not defined for #{object.class.name}" unless machine
239
+
240
+ state = machine.states[state_name]
241
+ raise ArgumentError, "State '#{state_name}' is not defined in state machine '#{machine_name}'" unless state
242
+
243
+ state.matches?(object.send(machine_name))
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'state_machines/branch'
4
+ require 'state_machines/eval_helpers'
5
+
6
+ module StateMachines
7
+ # Callbacks represent hooks into objects that allow logic to be triggered
8
+ # before, after, or around a specific set of transitions.
9
+ class Callback
10
+ include EvalHelpers
11
+
12
+ class << self
13
+ # Determines whether to automatically bind the callback to the object
14
+ # being transitioned. This only applies to callbacks that are defined as
15
+ # lambda blocks (or Procs). Some integrations, such as DataMapper, handle
16
+ # callbacks by executing them bound to the object involved, while other
17
+ # integrations, such as ActiveRecord, pass the object as an argument to
18
+ # the callback. This can be configured on an application-wide basis by
19
+ # setting this configuration to +true+ or +false+. The default value
20
+ # is +false+.
21
+ #
22
+ # *Note* that the DataMapper and Sequel integrations automatically
23
+ # configure this value on a per-callback basis, so it does not have to
24
+ # be enabled application-wide.
25
+ #
26
+ # == Examples
27
+ #
28
+ # When not bound to the object:
29
+ #
30
+ # class Vehicle
31
+ # state_machine do
32
+ # before_transition do |vehicle|
33
+ # vehicle.set_alarm
34
+ # end
35
+ # end
36
+ #
37
+ # def set_alarm
38
+ # ...
39
+ # end
40
+ # end
41
+ #
42
+ # When bound to the object:
43
+ #
44
+ # StateMachines::Callback.bind_to_object = true
45
+ #
46
+ # class Vehicle
47
+ # state_machine do
48
+ # before_transition do
49
+ # self.set_alarm
50
+ # end
51
+ # end
52
+ #
53
+ # def set_alarm
54
+ # ...
55
+ # end
56
+ # end
57
+ attr_accessor :bind_to_object
58
+
59
+ # The application-wide terminator to use for callbacks when not
60
+ # explicitly defined. Terminators determine whether to cancel a
61
+ # callback chain based on the return value of the callback.
62
+ #
63
+ # See StateMachines::Callback#terminator for more information.
64
+ attr_accessor :terminator
65
+ end
66
+
67
+ # The type of callback chain this callback is for. This can be one of the
68
+ # following:
69
+ # * +before+
70
+ # * +after+
71
+ # * +around+
72
+ # * +failure+
73
+ attr_accessor :type
74
+
75
+ # An optional block for determining whether to cancel the callback chain
76
+ # based on the return value of the callback. By default, the callback
77
+ # chain never cancels based on the return value (i.e. there is no implicit
78
+ # terminator). Certain integrations, such as ActiveRecord and Sequel,
79
+ # change this default value.
80
+ #
81
+ # == Examples
82
+ #
83
+ # Canceling the callback chain without a terminator:
84
+ #
85
+ # class Vehicle
86
+ # state_machine do
87
+ # before_transition do |vehicle|
88
+ # throw :halt
89
+ # end
90
+ # end
91
+ # end
92
+ #
93
+ # Canceling the callback chain with a terminator value of +false+:
94
+ #
95
+ # class Vehicle
96
+ # state_machine do
97
+ # before_transition do |vehicle|
98
+ # false
99
+ # end
100
+ # end
101
+ # end
102
+ attr_reader :terminator
103
+
104
+ # The branch that determines whether or not this callback can be invoked
105
+ # based on the context of the transition. The event, from state, and
106
+ # to state must all match in order for the branch to pass.
107
+ #
108
+ # See StateMachines::Branch for more information.
109
+ attr_reader :branch
110
+
111
+ # Creates a new callback that can get called based on the configured
112
+ # options.
113
+ #
114
+ # In addition to the possible configuration options for branches, the
115
+ # following options can be configured:
116
+ # * <tt>:bind_to_object</tt> - Whether to bind the callback to the object involved.
117
+ # If set to false, the object will be passed as a parameter instead.
118
+ # Default is integration-specific or set to the application default.
119
+ # * <tt>:terminator</tt> - A block/proc that determines what callback
120
+ # results should cause the callback chain to halt (if not using the
121
+ # default <tt>throw :halt</tt> technique).
122
+ #
123
+ # More information about how those options affect the behavior of the
124
+ # callback can be found in their attribute definitions.
125
+ def initialize(type, *args, &block)
126
+ @type = type
127
+ raise ArgumentError, 'Type must be :before, :after, :around, or :failure' unless %i[before after around failure].include?(type)
128
+
129
+ options = args.last.is_a?(Hash) ? args.pop : {}
130
+ @methods = args
131
+ @methods.concat(Array(options.delete(:do)))
132
+ @methods << block if block_given?
133
+ raise ArgumentError, 'Method(s) for callback must be specified' unless @methods.any?
134
+
135
+ options = { bind_to_object: self.class.bind_to_object, terminator: self.class.terminator }.merge(options)
136
+
137
+ # Proxy lambda blocks so that they're bound to the object
138
+ bind_to_object = options.delete(:bind_to_object)
139
+ @methods.map! do |method|
140
+ bind_to_object && method.is_a?(Proc) ? bound_method(method) : method
141
+ end
142
+
143
+ @terminator = options.delete(:terminator)
144
+ @branch = Branch.new(options)
145
+ end
146
+
147
+ # Gets a list of the states known to this callback by looking at the
148
+ # branch's known states
149
+ def known_states
150
+ branch.known_states
151
+ end
152
+
153
+ # Runs the callback as long as the transition context matches the branch
154
+ # requirements configured for this callback. If a block is provided, it
155
+ # will be called when the last method has run.
156
+ #
157
+ # If a terminator has been configured and it matches the result from the
158
+ # evaluated method, then the callback chain should be halted.
159
+ def call(object, context = {}, *, &)
160
+ if @branch.matches?(object, context)
161
+ run_methods(object, context, 0, *, &)
162
+ true
163
+ else
164
+ false
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ # Runs all of the methods configured for this callback.
171
+ #
172
+ # When running +around+ callbacks, this will evaluate each method and
173
+ # yield when the last method has yielded. The callback will only halt if
174
+ # one of the methods does not yield.
175
+ #
176
+ # For all other types of callbacks, this will evaluate each method in
177
+ # order. The callback will only halt if the resulting value from the
178
+ # method passes the terminator.
179
+ def run_methods(object, context = {}, index = 0, *args, &block)
180
+ case type
181
+ when :around
182
+ current_method = @methods[index]
183
+ if current_method
184
+ yielded = false
185
+ evaluate_method(object, current_method, *args) do
186
+ yielded = true
187
+ run_methods(object, context, index + 1, *args, &block)
188
+ end
189
+
190
+ throw :halt unless yielded
191
+ elsif block_given?
192
+ yield
193
+ end
194
+ else
195
+ @methods.each do |method|
196
+ result = evaluate_method(object, method, *args)
197
+ throw :halt if @terminator&.call(result)
198
+ end
199
+ end
200
+ end
201
+
202
+ # Generates a method that can be bound to the object being transitioned
203
+ # when the callback is invoked
204
+ def bound_method(block)
205
+ type = self.type
206
+ arity = block.arity
207
+ arity += 1 if arity >= 0 # Make sure the object gets passed
208
+ arity += 1 if arity == 1 && type == :around # Make sure the block gets passed
209
+
210
+ method = ->(object, *args) { object.instance_exec(*args, &block) }
211
+
212
+ # Proxy arity to the original block
213
+ (
214
+ class << method
215
+ self
216
+ end).class_eval do
217
+ define_method(:arity) { arity }
218
+ end
219
+
220
+ method
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Load all of the core implementation required to use state_machine. This
4
+ # includes:
5
+ # * StateMachines::MacroMethods which adds the state_machine DSL to your class
6
+ # * A set of initializers for setting state_machine defaults based on the current
7
+ # running environment (such as within Rails)
8
+ require 'state_machines/error'
9
+
10
+ require 'state_machines/extensions'
11
+
12
+ require 'state_machines/integrations'
13
+ require 'state_machines/integrations/base'
14
+
15
+ require 'state_machines/eval_helpers'
16
+
17
+ require 'singleton'
18
+ require 'state_machines/matcher'
19
+ require 'state_machines/matcher_helpers'
20
+
21
+ require 'state_machines/transition'
22
+ require 'state_machines/transition_collection'
23
+
24
+ require 'state_machines/branch'
25
+
26
+ require 'state_machines/helper_module'
27
+ require 'state_machines/callback'
28
+ require 'state_machines/node_collection'
29
+
30
+ require 'state_machines/state_context'
31
+ require 'state_machines/state'
32
+ require 'state_machines/state_collection'
33
+
34
+ require 'state_machines/event'
35
+ require 'state_machines/event_collection'
36
+
37
+ require 'state_machines/path'
38
+ require 'state_machines/path_collection'
39
+
40
+ require 'state_machines/machine'
41
+ require 'state_machines/machine_collection'
42
+
43
+ require 'state_machines/macro_methods'
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Class.class_eval do
4
+ include StateMachines::MacroMethods
5
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Loads all of the extensions to be made to Ruby core classes
4
+ require 'state_machines/core_ext/class/state_machine'
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StateMachines
4
+ # An error occurred during a state machine invocation
5
+ class Error < StandardError
6
+ # The object that failed
7
+ attr_reader :object
8
+
9
+ def initialize(object, message = nil) # :nodoc:
10
+ @object = object
11
+
12
+ super(message)
13
+ end
14
+ end
15
+
16
+ # An invalid integration was specified
17
+ class IntegrationNotFound < Error
18
+ def initialize(name)
19
+ super(nil, "#{name.inspect} is an invalid integration. #{error_message}")
20
+ end
21
+
22
+ def valid_integrations
23
+ "Valid integrations are: #{valid_integrations_name}"
24
+ end
25
+
26
+ def valid_integrations_name
27
+ Integrations.list.collect(&:integration_name)
28
+ end
29
+
30
+ def no_integrations
31
+ 'No integrations registered'
32
+ end
33
+
34
+ def error_message
35
+ if Integrations.list.size.zero?
36
+ no_integrations
37
+ else
38
+ valid_integrations
39
+ end
40
+ end
41
+ end
42
+
43
+ # An invalid integration was registered
44
+ class IntegrationError < StandardError
45
+ end
46
+
47
+ # An invalid event was specified
48
+ class InvalidEvent < Error
49
+ # The event that was attempted to be run
50
+ attr_reader :event
51
+
52
+ def initialize(object, event_name) # :nodoc:
53
+ @event = event_name
54
+
55
+ super(object, "#{event.inspect} is an unknown state machine event")
56
+ end
57
+ end
58
+
59
+ # An invalid transition was attempted
60
+ class InvalidTransition < Error
61
+ # The machine attempting to be transitioned
62
+ attr_reader :machine
63
+
64
+ # The current state value for the machine
65
+ attr_reader :from
66
+
67
+ def initialize(object, machine, event) # :nodoc:
68
+ @machine = machine
69
+ @from_state = machine.states.match!(object)
70
+ @from = machine.read(object, :state)
71
+ @event = machine.events.fetch(event)
72
+ errors = machine.errors_for(object)
73
+
74
+ message = "Cannot transition #{machine.name} via :#{self.event} from #{from_name.inspect}"
75
+ message << " (Reason(s): #{errors})" unless errors.empty?
76
+ super(object, message)
77
+ end
78
+
79
+ # The event that triggered the failed transition
80
+ def event
81
+ @event.name
82
+ end
83
+
84
+ # The fully-qualified name of the event that triggered the failed transition
85
+ def qualified_event
86
+ @event.qualified_name
87
+ end
88
+
89
+ # The name for the current state
90
+ def from_name
91
+ @from_state.name
92
+ end
93
+
94
+ # The fully-qualified name for the current state
95
+ def qualified_from_name
96
+ @from_state.qualified_name
97
+ end
98
+ end
99
+
100
+ # A set of transition failed to run in parallel
101
+ class InvalidParallelTransition < Error
102
+ # The set of events that failed the transition(s)
103
+ attr_reader :events
104
+
105
+ def initialize(object, events) # :nodoc:
106
+ @events = events
107
+
108
+ super(object, "Cannot run events in parallel: #{events * ', '}")
109
+ end
110
+ end
111
+
112
+ # A method was called in an invalid state context
113
+ class InvalidContext < Error
114
+ end
115
+ end