finite_machine 0.13.0 → 0.14.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.
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
3
+ require "logger"
4
4
 
5
- require_relative 'finite_machine/const'
6
- require_relative 'finite_machine/logger'
7
- require_relative 'finite_machine/definition'
8
- require_relative 'finite_machine/state_machine'
9
- require_relative 'finite_machine/version'
5
+ require_relative "finite_machine/const"
6
+ require_relative "finite_machine/logger"
7
+ require_relative "finite_machine/definition"
8
+ require_relative "finite_machine/state_machine"
9
+ require_relative "finite_machine/version"
10
10
 
11
11
  module FiniteMachine
12
12
  # Default state name
@@ -33,7 +33,7 @@ module FiniteMachine
33
33
  if block_given?
34
34
  options[:with] = block
35
35
  else
36
- raise ArgumentError, 'Need to provide error handler.'
36
+ raise ArgumentError, "Need to provide error handler."
37
37
  end
38
38
  end
39
39
  evaluate_exceptions(exceptions, options)
@@ -71,7 +71,7 @@ module FiniteMachine
71
71
  #
72
72
  # @api private
73
73
  def extract_const(class_name)
74
- class_name.split('::').reduce(FiniteMachine) do |constant, part|
74
+ class_name.split("::").reduce(FiniteMachine) do |constant, part|
75
75
  constant.const_get(part)
76
76
  end
77
77
  end
@@ -85,9 +85,9 @@ module FiniteMachine
85
85
  target.method(handler)
86
86
  when Proc
87
87
  if handler.arity.zero?
88
- proc { instance_exec(&handler) }
88
+ -> { instance_exec(&handler) }
89
89
  else
90
- proc { |_exception| instance_exec(_exception, &handler) }
90
+ ->(exception) { instance_exec(exception, &handler) }
91
91
  end
92
92
  end
93
93
  end
@@ -101,16 +101,24 @@ module FiniteMachine
101
101
  # @api private
102
102
  def evaluate_exceptions(exceptions, options)
103
103
  exceptions.each do |exception|
104
- key = if exception.is_a?(Class) && exception <= Exception
105
- exception.name
106
- elsif exception.is_a?(String)
107
- exception
108
- else
109
- raise ArgumentError, "#{exception} isn't an Exception"
110
- end
111
-
104
+ key = extract_exception_name(exception)
112
105
  error_handlers << [key, options[:with]]
113
106
  end
114
107
  end
108
+
109
+ # Extract exception name
110
+ #
111
+ # @param [Class,Exception,String] exception
112
+ #
113
+ # @api private
114
+ def extract_exception_name(exception)
115
+ if exception.is_a?(Class) && exception <= Exception
116
+ exception.name
117
+ elsif exception.is_a?(String)
118
+ exception
119
+ else
120
+ raise ArgumentError, "#{exception} isn't an Exception"
121
+ end
122
+ end
115
123
  end # Catchable
116
124
  end # FiniteMachine
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'transition_builder'
3
+ require_relative "transition_builder"
4
4
 
5
5
  module FiniteMachine
6
6
  # A class responsible for merging choice options
@@ -39,6 +39,6 @@ module FiniteMachine
39
39
  @transitions.merge(conditions))
40
40
  transition_builder.call(@transitions[:from] => to)
41
41
  end
42
- alias_method :default, :choice
42
+ alias default choice
43
43
  end # ChoiceMerger
44
44
  end # FiniteMachine
@@ -49,7 +49,7 @@ module FiniteMachine
49
49
  def self.inherited(subclass)
50
50
  super
51
51
 
52
- self.deferreds.each { |d| subclass.add_deferred(d) }
52
+ deferreds.each { |d| subclass.add_deferred(d) }
53
53
  end
54
54
 
55
55
  # Delay lookup of DSL method
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'choice_merger'
4
- require_relative 'safety'
5
- require_relative 'transition_builder'
3
+ require_relative "choice_merger"
4
+ require_relative "safety"
5
+ require_relative "transition_builder"
6
6
 
7
7
  module FiniteMachine
8
8
  # A generic DSL for describing the state machine
@@ -38,6 +38,13 @@ module FiniteMachine
38
38
  end
39
39
  end
40
40
 
41
+ # Check if message can be handled by this DSL
42
+ #
43
+ # @api private
44
+ def respond_to_missing?(method_name, include_private = false)
45
+ @machine.respond_to?(method_name) || super
46
+ end
47
+
41
48
  # Configure state machine properties
42
49
  #
43
50
  # @api private
@@ -65,6 +72,29 @@ module FiniteMachine
65
72
  log_transitions(@attrs.fetch(:log_transitions, false))
66
73
  end
67
74
 
75
+ # Add aliases for the target object
76
+ #
77
+ # @example
78
+ # FiniteMachine.define do
79
+ # target_alias :engine
80
+ #
81
+ # on_transition do |event|
82
+ # engine.state = event.to
83
+ # end
84
+ # end
85
+ #
86
+ # @param [Array<Symbol>] aliases
87
+ # the names for target alias
88
+ #
89
+ # @api public
90
+ def alias_target(*aliases)
91
+ aliases.each do |alias_name|
92
+ next if env.aliases.include?(alias_name)
93
+
94
+ env.aliases << alias_name
95
+ end
96
+ end
97
+
68
98
  # Define initial state
69
99
  #
70
100
  # @param [Symbol] value
@@ -197,8 +227,8 @@ module FiniteMachine
197
227
  #
198
228
  # @api private
199
229
  def raise_missing_state
200
- fail MissingInitialStateError,
201
- 'Provide state to transition :to for the initial event'
230
+ raise MissingInitialStateError,
231
+ "Provide state to transition :to for the initial event"
202
232
  end
203
233
  end # DSL
204
234
  end # FiniteMachine
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'threadable'
3
+ require_relative "threadable"
4
4
 
5
5
  module FiniteMachine
6
6
  # Holds references to targets and aliases
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/map'
4
- require 'forwardable'
3
+ require "concurrent/map"
4
+ require "forwardable"
5
5
 
6
- require_relative 'threadable'
7
- require_relative 'undefined_transition'
6
+ require_relative "threadable"
7
+ require_relative "undefined_transition"
8
8
 
9
9
  module FiniteMachine
10
10
  # A class responsible for storing mappings between event namess and
@@ -182,8 +182,7 @@ module FiniteMachine
182
182
  # @api public
183
183
  def match_transition_with(name, from_state, *conditions)
184
184
  find(name).find do |trans|
185
- trans.matches?(from_state) &&
186
- trans.check_conditions(*conditions)
185
+ trans.matches?(from_state) && trans.check_conditions(*conditions)
187
186
  end
188
187
  end
189
188
 
@@ -29,7 +29,7 @@ module FiniteMachine
29
29
  #
30
30
  # @api public
31
31
  def self.event_name
32
- name.split('::').last.downcase.to_sym
32
+ name.split("::").last.downcase.to_sym
33
33
  end
34
34
 
35
35
  # String representation
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/map'
3
+ require "concurrent/map"
4
4
 
5
- require_relative 'hook_event'
5
+ require_relative "hook_event"
6
6
 
7
7
  module FiniteMachine
8
8
  # A class reponsible for registering callbacks
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'listener'
4
- require 'thread'
3
+ require_relative "listener"
4
+ require "thread"
5
5
 
6
6
  module FiniteMachine
7
7
  # Allows for storage of asynchronous messages such as events
@@ -31,6 +31,7 @@ module FiniteMachine
31
31
  # @api private
32
32
  def start
33
33
  return if running?
34
+
34
35
  @mutex.synchronize { spawn_thread }
35
36
  end
36
37
 
@@ -114,6 +115,7 @@ module FiniteMachine
114
115
  # @api public
115
116
  def join(timeout = nil)
116
117
  return unless @thread
118
+
117
119
  timeout.nil? ? @thread.join : @thread.join(timeout)
118
120
  end
119
121
 
@@ -126,7 +128,7 @@ module FiniteMachine
126
128
  #
127
129
  # @api public
128
130
  def shutdown
129
- fail EventQueueDeadError, 'event queue already dead' if @dead
131
+ raise EventQueueDeadError, "event queue already dead" if @dead
130
132
 
131
133
  queue = []
132
134
  @mutex.synchronize do
@@ -184,6 +186,7 @@ module FiniteMachine
184
186
  end
185
187
  event = @queue.pop
186
188
  break unless event
189
+
187
190
  notify_listeners(event)
188
191
  event.dispatch
189
192
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'async_call'
4
- require_relative 'callable'
5
- require_relative 'hook_event'
6
- require_relative 'hooks'
7
- require_relative 'message_queue'
8
- require_relative 'safety'
9
- require_relative 'transition_event'
3
+ require_relative "async_call"
4
+ require_relative "callable"
5
+ require_relative "hook_event"
6
+ require_relative "hooks"
7
+ require_relative "message_queue"
8
+ require_relative "safety"
9
+ require_relative "transition_event"
10
10
 
11
11
  module FiniteMachine
12
12
  # A class responsible for observing state changes
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'hook_event'
3
+ require_relative "hook_event"
4
4
 
5
5
  module FiniteMachine
6
6
  # Module responsible for safety checks against known methods
@@ -39,7 +39,7 @@ module FiniteMachine
39
39
  name: event_name,
40
40
  type: :instance,
41
41
  method: method_name,
42
- source: 'FiniteMachine'
42
+ source: "FiniteMachine"
43
43
  }
44
44
  end
45
45
  end
@@ -89,8 +89,8 @@ module FiniteMachine
89
89
  # @api private
90
90
  def wrong_event_name?(name, event_type)
91
91
  machine.states.include?(name) &&
92
- !machine.events.include?(name) &&
93
- event_type < HookEvent::Anyaction
92
+ !machine.events.include?(name) &&
93
+ event_type < HookEvent::Anyaction
94
94
  end
95
95
 
96
96
  # Check if state name exists
@@ -104,8 +104,8 @@ module FiniteMachine
104
104
  # @api private
105
105
  def wrong_state_name?(name, event_type)
106
106
  machine.events.include?(name) &&
107
- !machine.states.include?(name) &&
108
- event_type < HookEvent::Anystate
107
+ !machine.states.include?(name) &&
108
+ event_type < HookEvent::Anystate
109
109
  end
110
110
 
111
111
  def raise_invalid_callback_error(message)
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
3
+ require "forwardable"
4
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'
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"
13
13
 
14
14
  module FiniteMachine
15
15
  # Base class for state machine
@@ -64,7 +64,8 @@ module FiniteMachine
64
64
  # Allow or not logging of transitions
65
65
  attr_threadsafe :log_transitions
66
66
 
67
- def_delegators :dsl, :initial, :terminal, :event, :trigger_init
67
+ def_delegators :dsl, :initial, :terminal, :event, :trigger_init,
68
+ :alias_target
68
69
 
69
70
  # Initialize state machine
70
71
  #
@@ -194,7 +195,7 @@ module FiniteMachine
194
195
  # fsm.can?(:go) # => true
195
196
  #
196
197
  # @example
197
- # fsm.can?(:go, 'Piotr') # checks condition with parameter 'Piotr'
198
+ # fsm.can?(:go, "Piotr") # checks condition with parameter "Piotr"
198
199
  #
199
200
  # @param [String] event
200
201
  #
@@ -202,7 +203,7 @@ module FiniteMachine
202
203
  #
203
204
  # @api public
204
205
  def can?(*args)
205
- event_name = args.shift
206
+ event_name = args.shift
206
207
  events_map.can_perform?(event_name, current, *args)
207
208
  end
208
209
 
@@ -284,7 +285,7 @@ module FiniteMachine
284
285
  else
285
286
  exception = InvalidStateError
286
287
  catch_error(exception) ||
287
- fail(exception, "inappropriate current state '#{current}'")
288
+ raise(exception, "inappropriate current state '#{current}'")
288
289
 
289
290
  false
290
291
  end
@@ -390,8 +391,10 @@ module FiniteMachine
390
391
  # @api public
391
392
  def inspect
392
393
  sync_shared do
393
- "<##{self.class}:0x#{object_id.to_s(16)} @states=#{states}, " \
394
- "@events=#{events}, " \
394
+ "<##{self.class}:0x#{object_id.to_s(16)} " \
395
+ "@current=#{current.inspect} " \
396
+ "@states=#{states} " \
397
+ "@events=#{events} " \
395
398
  "@transitions=#{events_map.state_transitions}>"
396
399
  end
397
400
  end
@@ -407,7 +410,7 @@ module FiniteMachine
407
410
  #
408
411
  # @api private
409
412
  def raise_transition_error(error)
410
- fail TransitionError, Logger.format_error(error)
413
+ raise TransitionError, Logger.format_error(error)
411
414
  end
412
415
 
413
416
  # Forward the message to observer or self
@@ -7,7 +7,9 @@ module FiniteMachine
7
7
  #
8
8
  # @api private
9
9
  class StateParser
10
- BLACKLIST = [:name, :if, :unless, :silent].freeze
10
+ NON_STATE_KEYS = %i[name if unless silent].freeze
11
+
12
+ STATE_KEYS = %i[from to].freeze
11
13
 
12
14
  # Extract states from user defined attributes
13
15
  #
@@ -35,7 +37,7 @@ module FiniteMachine
35
37
  # @api private
36
38
  def self.ensure_only_states!(attrs)
37
39
  attributes = attrs.dup
38
- BLACKLIST.each { |key| attributes.delete(key) }
40
+ NON_STATE_KEYS.each { |key| attributes.delete(key) }
39
41
  raise_not_enough_transitions unless attributes.any?
40
42
  attributes
41
43
  end
@@ -69,7 +71,7 @@ module FiniteMachine
69
71
  #
70
72
  # @api public
71
73
  def self.contains_from_to_keys?(attrs)
72
- [:from, :to].any? { |key| attrs.keys.include?(key) }
74
+ STATE_KEYS.any? { |key| attrs.keys.include?(key) }
73
75
  end
74
76
  private_class_method :contains_from_to_keys?
75
77
 
@@ -79,9 +81,8 @@ module FiniteMachine
79
81
  #
80
82
  # @api private
81
83
  def self.convert_from_to_attributes_to_states_hash(attrs)
82
- Array(attrs[:from] || ANY_STATE).reduce({}) do |hash, state|
84
+ Array(attrs[:from] || ANY_STATE).each_with_object({}) do |state, hash|
83
85
  hash[state] = attrs[:to] || state
84
- hash
85
86
  end
86
87
  end
87
88
  private_class_method :convert_from_to_attributes_to_states_hash
@@ -99,13 +100,12 @@ module FiniteMachine
99
100
  #
100
101
  # @api private
101
102
  def self.convert_attributes_to_states_hash(attrs)
102
- attrs.reduce({}) do |hash, (k, v)|
103
+ attrs.each_with_object({}) do |(k, v), hash|
103
104
  if k.respond_to?(:to_ary)
104
105
  k.each { |el| hash[el] = v }
105
106
  else
106
107
  hash[k] = v
107
108
  end
108
- hash
109
109
  end
110
110
  end
111
111
  private_class_method :convert_attributes_to_states_hash
@@ -119,7 +119,7 @@ module FiniteMachine
119
119
  #
120
120
  # @api private
121
121
  def self.raise_not_enough_transitions
122
- raise NotEnoughTransitionsError, 'please provide state transitions'
122
+ raise NotEnoughTransitionsError, "please provide state transitions"
123
123
  end
124
124
  private_class_method :raise_not_enough_transitions
125
125
  end # StateParser