finite_machine 0.11.3 → 0.12.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.
Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +564 -569
  4. data/Rakefile +5 -1
  5. data/benchmarks/memory_profile.rb +11 -0
  6. data/benchmarks/memory_usage.rb +16 -9
  7. data/finite_machine.gemspec +10 -3
  8. data/lib/finite_machine.rb +34 -46
  9. data/lib/finite_machine/async_call.rb +5 -21
  10. data/lib/finite_machine/callable.rb +4 -4
  11. data/lib/finite_machine/catchable.rb +4 -2
  12. data/lib/finite_machine/choice_merger.rb +19 -19
  13. data/lib/finite_machine/const.rb +16 -0
  14. data/lib/finite_machine/definition.rb +2 -2
  15. data/lib/finite_machine/dsl.rb +66 -149
  16. data/lib/finite_machine/env.rb +4 -2
  17. data/lib/finite_machine/event_definition.rb +7 -15
  18. data/lib/finite_machine/{events_chain.rb → events_map.rb} +39 -51
  19. data/lib/finite_machine/hook_event.rb +60 -61
  20. data/lib/finite_machine/hooks.rb +44 -36
  21. data/lib/finite_machine/listener.rb +2 -2
  22. data/lib/finite_machine/logger.rb +5 -4
  23. data/lib/finite_machine/message_queue.rb +39 -30
  24. data/lib/finite_machine/observer.rb +55 -37
  25. data/lib/finite_machine/safety.rb +12 -10
  26. data/lib/finite_machine/state_definition.rb +3 -5
  27. data/lib/finite_machine/state_machine.rb +83 -64
  28. data/lib/finite_machine/state_parser.rb +51 -79
  29. data/lib/finite_machine/subscribers.rb +1 -1
  30. data/lib/finite_machine/threadable.rb +3 -1
  31. data/lib/finite_machine/transition.rb +30 -31
  32. data/lib/finite_machine/transition_builder.rb +23 -32
  33. data/lib/finite_machine/transition_event.rb +12 -11
  34. data/lib/finite_machine/two_phase_lock.rb +3 -1
  35. data/lib/finite_machine/undefined_transition.rb +5 -6
  36. data/lib/finite_machine/version.rb +2 -2
  37. data/spec/integration/system_spec.rb +36 -38
  38. data/spec/performance/benchmark_spec.rb +13 -21
  39. data/spec/unit/alias_target_spec.rb +22 -41
  40. data/spec/unit/async_callbacks_spec.rb +8 -13
  41. data/spec/unit/auto_methods_spec.rb +44 -0
  42. data/spec/unit/callable/call_spec.rb +1 -3
  43. data/spec/unit/callbacks_spec.rb +372 -463
  44. data/spec/unit/can_spec.rb +13 -23
  45. data/spec/unit/cancel_callbacks_spec.rb +46 -0
  46. data/spec/unit/choice_spec.rb +105 -141
  47. data/spec/unit/define_spec.rb +31 -31
  48. data/spec/unit/definition_spec.rb +24 -41
  49. data/spec/unit/event_names_spec.rb +6 -10
  50. data/spec/unit/events_map/add_spec.rb +23 -0
  51. data/spec/unit/events_map/choice_transition_spec.rb +25 -0
  52. data/spec/unit/events_map/clear_spec.rb +13 -0
  53. data/spec/unit/events_map/events_spec.rb +16 -0
  54. data/spec/unit/events_map/inspect_spec.rb +22 -0
  55. data/spec/unit/{events_chain → events_map}/match_transition_spec.rb +12 -14
  56. data/spec/unit/{events_chain → events_map}/move_to_spec.rb +14 -17
  57. data/spec/unit/events_map/states_for_spec.rb +17 -0
  58. data/spec/unit/events_spec.rb +91 -160
  59. data/spec/unit/handlers_spec.rb +34 -66
  60. data/spec/unit/hook_event/any_state_or_event_spec.rb +13 -0
  61. data/spec/unit/hook_event/build_spec.rb +1 -3
  62. data/spec/unit/hook_event/eql_spec.rb +1 -3
  63. data/spec/unit/hook_event/initialize_spec.rb +2 -4
  64. data/spec/unit/hook_event/notify_spec.rb +2 -4
  65. data/spec/unit/hooks/clear_spec.rb +1 -1
  66. data/spec/unit/hooks/{call_spec.rb → find_spec.rb} +4 -9
  67. data/spec/unit/hooks/inspect_spec.rb +16 -8
  68. data/spec/unit/hooks/register_spec.rb +4 -9
  69. data/spec/unit/if_unless_spec.rb +76 -115
  70. data/spec/unit/initial_spec.rb +50 -82
  71. data/spec/unit/inspect_spec.rb +14 -9
  72. data/spec/unit/is_spec.rb +12 -18
  73. data/spec/unit/log_transitions_spec.rb +4 -10
  74. data/spec/unit/logger_spec.rb +1 -3
  75. data/spec/unit/{event_queue_spec.rb → message_queue_spec.rb} +15 -8
  76. data/spec/unit/new_spec.rb +50 -0
  77. data/spec/unit/respond_to_spec.rb +2 -6
  78. data/spec/unit/state_parser/parse_spec.rb +9 -12
  79. data/spec/unit/states_spec.rb +12 -18
  80. data/spec/unit/subscribers_spec.rb +1 -3
  81. data/spec/unit/target_spec.rb +60 -93
  82. data/spec/unit/terminated_spec.rb +15 -25
  83. data/spec/unit/transition/check_conditions_spec.rb +16 -15
  84. data/spec/unit/transition/inspect_spec.rb +6 -6
  85. data/spec/unit/transition/matches_spec.rb +5 -7
  86. data/spec/unit/transition/states_spec.rb +5 -7
  87. data/spec/unit/transition/to_state_spec.rb +5 -13
  88. data/spec/unit/trigger_spec.rb +5 -9
  89. data/spec/unit/undefined_transition/eql_spec.rb +1 -3
  90. metadata +86 -49
  91. data/.gitignore +0 -18
  92. data/.rspec +0 -5
  93. data/.travis.yml +0 -27
  94. data/Gemfile +0 -16
  95. data/assets/finite_machine_logo.png +0 -0
  96. data/lib/finite_machine/async_proxy.rb +0 -55
  97. data/spec/unit/async_events_spec.rb +0 -107
  98. data/spec/unit/events_chain/add_spec.rb +0 -25
  99. data/spec/unit/events_chain/cancel_transitions_spec.rb +0 -22
  100. data/spec/unit/events_chain/choice_transition_spec.rb +0 -28
  101. data/spec/unit/events_chain/clear_spec.rb +0 -15
  102. data/spec/unit/events_chain/events_spec.rb +0 -18
  103. data/spec/unit/events_chain/inspect_spec.rb +0 -24
  104. data/spec/unit/events_chain/states_for_spec.rb +0 -17
  105. data/spec/unit/hook_event/infer_default_name_spec.rb +0 -13
  106. data/spec/unit/state_parser/inspect_spec.rb +0 -25
@@ -1,7 +1,9 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'hook_event'
2
4
 
3
5
  module FiniteMachine
4
- # Module for responsible for safety checks against known methods
6
+ # Module responsible for safety checks against known methods
5
7
  module Safety
6
8
  EVENT_CONFLICT_MESSAGE = \
7
9
  "You tried to define an event named \"%{name}\", however this would " \
@@ -33,7 +35,7 @@ module FiniteMachine
33
35
  # @api public
34
36
  def detect_event_conflict!(event_name, method_name = event_name)
35
37
  if method_already_implemented?(method_name)
36
- fail FiniteMachine::AlreadyDefinedError, EVENT_CONFLICT_MESSAGE % {
38
+ raise FiniteMachine::AlreadyDefinedError, EVENT_CONFLICT_MESSAGE % {
37
39
  name: event_name,
38
40
  type: :instance,
39
41
  method: method_name,
@@ -55,12 +57,12 @@ module FiniteMachine
55
57
  def ensure_valid_callback_name!(event_type, name)
56
58
  message = if wrong_event_name?(name, event_type)
57
59
  EVENT_CALLBACK_CONFLICT_MESSAGE % {
58
- type: "on_#{event_type.to_s}",
60
+ type: "on_#{event_type}",
59
61
  name: name
60
62
  }
61
63
  elsif wrong_state_name?(name, event_type)
62
64
  STATE_CALLBACK_CONFLICT_MESSAGE % {
63
- type: "on_#{event_type.to_s}",
65
+ type: "on_#{event_type}",
64
66
  name: name
65
67
  }
66
68
  elsif !callback_names.include?(name)
@@ -71,7 +73,7 @@ module FiniteMachine
71
73
  else
72
74
  nil
73
75
  end
74
- message && fail_invalid_callback_error(message)
76
+ message && raise_invalid_callback_error(message)
75
77
  end
76
78
 
77
79
  private
@@ -87,7 +89,7 @@ module FiniteMachine
87
89
  # @api private
88
90
  def wrong_event_name?(name, event_type)
89
91
  machine.states.include?(name) &&
90
- !machine.event_names.include?(name) &&
92
+ !machine.events.include?(name) &&
91
93
  event_type < HookEvent::Anyaction
92
94
  end
93
95
 
@@ -101,14 +103,14 @@ module FiniteMachine
101
103
  #
102
104
  # @api private
103
105
  def wrong_state_name?(name, event_type)
104
- machine.event_names.include?(name) &&
106
+ machine.events.include?(name) &&
105
107
  !machine.states.include?(name) &&
106
108
  event_type < HookEvent::Anystate
107
109
  end
108
110
 
109
- def fail_invalid_callback_error(message)
111
+ def raise_invalid_callback_error(message)
110
112
  exception = InvalidCallbackNameError
111
- machine.catch_error(exception) || fail(exception, message)
113
+ machine.catch_error(exception) || raise(exception, message)
112
114
  end
113
115
 
114
116
  # Check if method is already implemented inside StateMachine
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module FiniteMachine
4
4
  # A class responsible for defining state query methods on state machine
@@ -8,15 +8,13 @@ module FiniteMachine
8
8
  #
9
9
  # @api private
10
10
  class StateDefinition
11
- include Threadable
12
-
13
11
  # Initialize a StateDefinition
14
12
  #
15
13
  # @param [StateMachine] machine
16
14
  #
17
15
  # @api public
18
16
  def initialize(machine)
19
- self.machine = machine
17
+ @machine = machine
20
18
  end
21
19
 
22
20
  # Define query methods for states
@@ -34,7 +32,7 @@ module FiniteMachine
34
32
  private
35
33
 
36
34
  # The current state machine
37
- attr_threadsafe :machine
35
+ attr_reader :machine
38
36
 
39
37
  # Define helper state mehods for the transition states
40
38
  #
@@ -1,4 +1,15 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ require_relative 'catchable'
6
+ require_relative 'dsl'
7
+ require_relative 'env'
8
+ require_relative 'events_map'
9
+ require_relative 'hook_event'
10
+ require_relative 'observer'
11
+ require_relative 'threadable'
12
+ require_relative 'subscribers'
2
13
 
3
14
  module FiniteMachine
4
15
  # Base class for state machine
@@ -7,6 +18,13 @@ module FiniteMachine
7
18
  include Catchable
8
19
  extend Forwardable
9
20
 
21
+ # Current state
22
+ #
23
+ # @return [Symbol]
24
+ #
25
+ # @api private
26
+ attr_threadsafe :state
27
+
10
28
  # Initial state, defaults to :none
11
29
  attr_threadsafe :initial_state
12
30
 
@@ -20,21 +38,14 @@ module FiniteMachine
20
38
  attr_threadsafe :env
21
39
 
22
40
  # The state machine event definitions
23
- attr_threadsafe :events_chain
24
-
25
- # Errors DSL
26
- #
27
- # @return [ErrorsDSL]
28
- #
29
- # @api private
30
- attr_threadsafe :errors_dsl
41
+ attr_threadsafe :events_map
31
42
 
32
- # Events DSL
43
+ # Machine dsl
33
44
  #
34
- # @return [EventsDSL]
45
+ # @return [DSL]
35
46
  #
36
47
  # @api private
37
- attr_threadsafe :events_dsl
48
+ attr_threadsafe :dsl
38
49
 
39
50
  # The state machine observer
40
51
  #
@@ -43,13 +54,6 @@ module FiniteMachine
43
54
  # @api private
44
55
  attr_threadsafe :observer
45
56
 
46
- # Current state
47
- #
48
- # @return [Symbol]
49
- #
50
- # @api private
51
- attr_threadsafe :state
52
-
53
57
  # The state machine subscribers
54
58
  #
55
59
  # @return [Subscribers]
@@ -60,64 +64,76 @@ module FiniteMachine
60
64
  # Allow or not logging of transitions
61
65
  attr_threadsafe :log_transitions
62
66
 
63
- def_delegators :@dsl, :initial, :terminal, :target, :trigger_init,
64
- :alias_target
65
-
66
- def_delegator :events_dsl, :event
67
-
68
- def_delegator :@async_proxy, :event_queue
67
+ def_delegators :dsl, :initial, :terminal, :event, :trigger_init
69
68
 
70
69
  # Initialize state machine
71
70
  #
71
+ # @example
72
+ # fsm = FiniteMachine::StateMachine.new(target_alias: :car) do
73
+ # initial :red
74
+ #
75
+ # event :go, :red => :green
76
+ #
77
+ # on_transition do |event|
78
+ # car.state = event.to
79
+ # end
80
+ # end
81
+ #
82
+ # @param [Hash] options
83
+ # the options to create state machine with
84
+ # @option options [String] :alias_target
85
+ # the alias for target object
86
+ #
72
87
  # @api private
73
- def initialize(*args, &block)
74
- attributes = args.last.is_a?(Hash) ? args.pop : {}
75
-
88
+ def initialize(*args, **options, &block)
76
89
  @initial_state = DEFAULT_STATE
77
- @async_proxy = AsyncProxy.new(self)
90
+ @auto_methods = options.fetch(:auto_methods, true)
78
91
  @subscribers = Subscribers.new
79
92
  @observer = Observer.new(self)
80
- @events_chain = EventsChain.new
93
+ @events_map = EventsMap.new
81
94
  @env = Env.new(self, [])
82
- @events_dsl = EventsDSL.new(self)
83
- @errors_dsl = ErrorsDSL.new(self)
84
- @dsl = DSL.new(self, attributes)
95
+ @dsl = DSL.new(self, options)
85
96
 
86
- @dsl.call(&block) if block_given?
97
+ env.target = args.pop unless args.empty?
98
+ env.aliases << options[:alias_target] if options[:alias_target]
99
+ dsl.call(&block) if block_given?
87
100
  trigger_init
88
101
  end
89
102
 
90
- # Subscribe observer for event notifications
103
+ # Check if event methods should be auto generated
91
104
  #
92
- # @example
93
- # machine.subscribe(Observer.new(machine))
105
+ # @return [Boolean]
94
106
  #
95
107
  # @api public
96
- def subscribe(*observers)
97
- sync_exclusive { subscribers.subscribe(*observers) }
108
+ def auto_methods?
109
+ @auto_methods
98
110
  end
99
111
 
100
- # Help to mark the event as synchronous
112
+ # Attach state machine to an object
113
+ #
114
+ # This allows state machine to initiate events in the context
115
+ # of a particular object
101
116
  #
102
117
  # @example
103
- # fsm.sync.go
118
+ # FiniteMachine.define(target: object) do
119
+ # ...
120
+ # end
104
121
  #
105
- # @return [self]
122
+ # @return [Object|FiniteMachine::StateMachine]
106
123
  #
107
124
  # @api public
108
- alias_method :sync, :method_missing
125
+ def target
126
+ env.target
127
+ end
109
128
 
110
- # Explicitly invoke event on proxy or delegate to proxy
129
+ # Subscribe observer for event notifications
111
130
  #
112
- # @return [AsyncProxy]
131
+ # @example
132
+ # machine.subscribe(Observer.new(machine))
113
133
  #
114
134
  # @api public
115
- def async(method_name = nil, *args, &block)
116
- if method_name
117
- @async_proxy.method_missing(method_name, *args, &block)
118
- else
119
- @async_proxy
120
- end
135
+ def subscribe(*observers)
136
+ sync_exclusive { subscribers.subscribe(*observers) }
121
137
  end
122
138
 
123
139
  # Get current state
@@ -126,7 +142,7 @@ module FiniteMachine
126
142
  #
127
143
  # @api public
128
144
  def current
129
- state
145
+ sync_shared { state }
130
146
  end
131
147
 
132
148
  # Check if current state matches provided state
@@ -156,19 +172,19 @@ module FiniteMachine
156
172
  #
157
173
  # @api public
158
174
  def states
159
- sync_shared { events_chain.states }
175
+ sync_shared { events_map.states }
160
176
  end
161
177
 
162
178
  # Retireve all event names
163
179
  #
164
180
  # @example
165
- # fsm.event_names # => [:init, :start, :stop]
181
+ # fsm.events # => [:init, :start, :stop]
166
182
  #
167
183
  # @return [Array[Symbol]]
168
184
  #
169
185
  # @api public
170
- def event_names
171
- sync_shared { events_chain.events }
186
+ def events
187
+ events_map.events
172
188
  end
173
189
 
174
190
  # Checks if event can be triggered
@@ -186,7 +202,7 @@ module FiniteMachine
186
202
  # @api public
187
203
  def can?(*args)
188
204
  event_name = args.shift
189
- events_chain.can_perform?(event_name, current, *args)
205
+ events_map.can_perform?(event_name, current, *args)
190
206
  end
191
207
 
192
208
  # Checks if event cannot be triggered
@@ -232,7 +248,7 @@ module FiniteMachine
232
248
  #
233
249
  # @api private
234
250
  def valid_state?(event_name)
235
- current_states = events_chain.states_for(event_name)
251
+ current_states = events_map.states_for(event_name)
236
252
  current_states.any? { |state| state == current || state == ANY_STATE }
237
253
  end
238
254
 
@@ -284,9 +300,9 @@ module FiniteMachine
284
300
  #
285
301
  # @api public
286
302
  def trigger!(event_name, *data, &block)
287
- sync_exclusive do
288
- from = current # Save away current state
303
+ from = current # Save away current state
289
304
 
305
+ sync_exclusive do
290
306
  notify HookEvent::Before, event_name, from, *data
291
307
 
292
308
  status = try_trigger(event_name) do
@@ -307,6 +323,9 @@ module FiniteMachine
307
323
 
308
324
  status
309
325
  end
326
+ rescue Exception => err
327
+ self.state = from # rollback transition
328
+ raise err
310
329
  end
311
330
 
312
331
  # Trigger transition event without raising any errors
@@ -319,7 +338,7 @@ module FiniteMachine
319
338
  # @api public
320
339
  def trigger(event_name, *data, &block)
321
340
  trigger!(event_name, *data, &block)
322
- rescue InvalidStateError, TransitionError
341
+ rescue InvalidStateError, TransitionError, CallbackError
323
342
  false
324
343
  end
325
344
 
@@ -330,7 +349,7 @@ module FiniteMachine
330
349
  # @api private
331
350
  def transition!(event_name, *data, &block)
332
351
  from_state = current
333
- to_state = events_chain.move_to(event_name, from_state, *data)
352
+ to_state = events_map.move_to(event_name, from_state, *data)
334
353
 
335
354
  block.call(from_state, to_state) if block
336
355
 
@@ -371,8 +390,8 @@ module FiniteMachine
371
390
  def inspect
372
391
  sync_shared do
373
392
  "<##{self.class}:0x#{object_id.to_s(16)} @states=#{states}, " \
374
- "@events=#{event_names}, " \
375
- "@transitions=#{events_chain.state_transitions}>"
393
+ "@events=#{events}, " \
394
+ "@transitions=#{events_map.state_transitions}>"
376
395
  end
377
396
  end
378
397
 
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module FiniteMachine
4
4
  # A class responsible for converting transition arguments to states
@@ -7,114 +7,98 @@ module FiniteMachine
7
7
  #
8
8
  # @api private
9
9
  class StateParser
10
- include Threadable
11
-
12
- attr_threadsafe :attrs
13
-
14
10
  BLACKLIST = [:name, :if, :unless, :silent].freeze
15
11
 
16
- # Initialize a StateParser
12
+ # Extract states from user defined attributes
17
13
  #
18
14
  # @example
19
- # StateParpser.new({from: [:green, :blue], to: :red})
20
- #
21
- # @param [Hash] attrs
22
- #
23
- # @api public
24
- def initialize(attrs)
25
- @attrs = ensure_only_states!(attrs)
26
- freeze
27
- end
28
-
29
- # Extract states from attributes
15
+ # StateParser.parse({from: [:green, :blue], to: :red})
16
+ # # => {green: :red, green: :blue}
30
17
  #
31
18
  # @param [Proc] block
32
19
  #
33
- # @example
34
- # StateParpser.new(attr).parase_states
35
- #
36
20
  # @yield [Hash[Symbol]] the resolved states
37
21
  #
38
22
  # @return [Hash[Symbol]] the resolved states
39
23
  #
40
24
  # @api public
41
- def parse(&block)
42
- states = extract_states
25
+ def self.parse(attributes, &block)
26
+ attrs = ensure_only_states!(attributes)
27
+ states = extract_states(attrs)
43
28
  block ? states.each(&block) : states
44
29
  end
45
30
 
46
- # Check if attributes contain :from or :to key
47
- #
48
- # @example
49
- # parser = StateParser.new({from: :green, to: :red})
50
- # parser.contains_from_to_keys? # => true
51
- #
52
- # @example
53
- # parser = StateParser.new({:green => :red})
54
- # parser.contains_from_to_keys? # => false
31
+ # Extract only states from attributes
55
32
  #
56
- # @return [Boolean]
33
+ # @return [Hash[Symbol]]
57
34
  #
58
- # @api public
59
- def contains_from_to_keys?
60
- [:from, :to].any? { |key| attrs.keys.include?(key) }
35
+ # @api private
36
+ def self.ensure_only_states!(attrs)
37
+ attributes = attrs.dup
38
+ BLACKLIST.each { |key| attributes.delete(key) }
39
+ raise_not_enough_transitions unless attributes.any?
40
+ attributes
61
41
  end
42
+ private_class_method :ensure_only_states!
62
43
 
63
- # Return parser attributes
44
+ # Perform extraction of states from user supplied definitions
64
45
  #
65
- # @return [String]
46
+ # @return [Hash[Symbol]] the resolved states
66
47
  #
67
- # @api public
68
- def to_s
69
- attrs.to_s
48
+ # @api private
49
+ def self.extract_states(attrs)
50
+ if contains_from_to_keys?(attrs)
51
+ convert_from_to_attributes_to_states_hash(attrs)
52
+ else
53
+ convert_attributes_to_states_hash(attrs)
54
+ end
70
55
  end
56
+ private_class_method :extract_states
71
57
 
72
- # Return string representation
58
+ # Check if attributes contain :from or :to key
73
59
  #
74
- # @return [String]
60
+ # @example
61
+ # StateParser.contains_from_to_keys?({from: :green, to: :red})
62
+ # # => true
75
63
  #
76
- # @api public
77
- def inspect
78
- attributes = @attrs.map { |k, v| "#{k}:#{v}" }.join(', ')
79
- "<##{self.class} @attrs=#{attributes}>"
80
- end
81
-
82
- private
83
-
84
- # Extract only states from attributes
64
+ # @example
65
+ # StateParser.contains_from_to_keys?({:green => :red})
66
+ # # => false
85
67
  #
86
- # @return [Hash[Symbol]]
68
+ # @return [Boolean]
87
69
  #
88
- # @api private
89
- def ensure_only_states!(attrs)
90
- attributes = attrs.dup
91
- BLACKLIST.each { |key| attributes.delete(key) }
92
- raise_not_enough_transitions unless attributes.any?
93
- attributes
70
+ # @api public
71
+ def self.contains_from_to_keys?(attrs)
72
+ [:from, :to].any? { |key| attrs.keys.include?(key) }
94
73
  end
74
+ private_class_method :contains_from_to_keys?
95
75
 
96
76
  # Convert attrbiutes with :from, :to keys to states hash
97
77
  #
98
78
  # @return [Hash[Symbol]]
99
79
  #
100
80
  # @api private
101
- def convert_from_to_attributes_to_states_hash
81
+ def self.convert_from_to_attributes_to_states_hash(attrs)
102
82
  Array(attrs[:from] || ANY_STATE).reduce({}) do |hash, state|
103
83
  hash[state] = attrs[:to] || state
104
84
  hash
105
85
  end
106
86
  end
87
+ private_class_method :convert_from_to_attributes_to_states_hash
107
88
 
108
89
  # Convert collapsed attributes to states hash
109
90
  #
110
91
  # @example
111
- # parser = StateParser.new([:green, :red] => :yellow)
112
- # parser.parse # => {green: :yellow, red: :yellow}
92
+ # StateParser.convert_attributes_to_states_hash([:green, :red] => :yellow)
93
+ # # => {green: :yellow, red: :yellow}
94
+ #
95
+ # @param [Hash] attrs
96
+ # the attributes to convert to a simple hash
113
97
  #
114
98
  # @return [Hash[Symbol]]
115
99
  #
116
100
  # @api private
117
- def convert_attributes_to_states_hash
101
+ def self.convert_attributes_to_states_hash(attrs)
118
102
  attrs.reduce({}) do |hash, (k, v)|
119
103
  if k.respond_to?(:to_ary)
120
104
  k.each { |el| hash[el] = v }
@@ -124,31 +108,19 @@ module FiniteMachine
124
108
  hash
125
109
  end
126
110
  end
127
-
128
- # Perform extraction of states from user supplied definitions
129
- #
130
- # @return [Hash[Symbol]] the resolved states
131
- #
132
- # @api private
133
- def extract_states
134
- if contains_from_to_keys?
135
- convert_from_to_attributes_to_states_hash
136
- else
137
- convert_attributes_to_states_hash
138
- end
139
- end
111
+ private_class_method :convert_attributes_to_states_hash
140
112
 
141
113
  # Raise error when not enough transitions are provided
142
114
  #
143
115
  # @raise [NotEnoughTransitionsError]
144
- # if the event has not enough transition arguments
116
+ # if the event has no transitions
145
117
  #
146
118
  # @return [nil]
147
119
  #
148
120
  # @api private
149
- def raise_not_enough_transitions
150
- fail NotEnoughTransitionsError, "please provide state transitions for" \
151
- " '#{attrs.inspect}'"
121
+ def self.raise_not_enough_transitions
122
+ raise NotEnoughTransitionsError, 'please provide state transitions'
152
123
  end
124
+ private_class_method :raise_not_enough_transitions
153
125
  end # StateParser
154
126
  end # FiniteMachine