finite_machine 0.11.3 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/.rspec DELETED
@@ -1,5 +0,0 @@
1
- --color
2
- --format progress
3
- --order random
4
- --warnings
5
- --require spec_helper
@@ -1,27 +0,0 @@
1
- ---
2
- language: ruby
3
- sudo: false
4
- cache: bundler
5
- bundler_args: --without yard benchmarks
6
- script: "bundle exec rake ci"
7
- rvm:
8
- - 1.9.3
9
- - 2.0
10
- - 2.1
11
- - 2.2
12
- - 2.3.0
13
- - ruby-head
14
- - rbx-2
15
- matrix:
16
- include:
17
- - rvm: jruby-19mode
18
- - rvm: jruby-20mode
19
- - rvm: jruby-21mode
20
- - rvm: jruby-head
21
- allow_failures:
22
- - rvm: ruby-head
23
- - rvm: jruby-head
24
- - rvm: rbx-2
25
- fast_finish: true
26
- branches:
27
- only: master
data/Gemfile DELETED
@@ -1,16 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :development do
6
- gem 'pry', '~> 0.10.1'
7
- gem 'rspec', '~> 3.4.0'
8
- gem 'rspec-benchmark', '~> 0.1.0'
9
- gem 'yard', '~> 0.8.7'
10
- end
11
-
12
- group :metrics do
13
- gem 'coveralls', '~> 0.8.1'
14
- gem 'simplecov', '~> 0.10.0'
15
- gem 'yardstick', '~> 0.9.9'
16
- end
@@ -1,55 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module FiniteMachine
4
- # An asynchronous messages proxy
5
- #
6
- # @api private
7
- class AsyncProxy
8
- include Threadable
9
-
10
- attr_threadsafe :context
11
-
12
- # The queue for asynchronoous events
13
- #
14
- # @return [EventQueue]
15
- #
16
- # @api private
17
- attr_threadsafe :event_queue
18
-
19
- # Initialize an AsynxProxy
20
- #
21
- # @param [Object] context
22
- # the context this proxy is associated with
23
- #
24
- # @api private
25
- def initialize(context)
26
- self.context = context
27
- self.event_queue = MessageQueue.new
28
-
29
- ObjectSpace.define_finalizer(self, self.class.cleanup(event_queue))
30
- end
31
-
32
- # Delegate asynchronous event to event queue
33
- #
34
- # @api private
35
- def method_missing(method_name, *args, &block)
36
- callable = Callable.new(method_name)
37
- async_call = AsyncCall.new(context, callable, *args, &block)
38
-
39
- event_queue.start unless event_queue.running?
40
- context.event_queue << async_call
41
- end
42
-
43
- # Clean up event queue
44
- #
45
- # @api private
46
- def self.cleanup(queue)
47
- proc do
48
- begin
49
- queue && queue.shutdown
50
- rescue MessageQueueDeadError
51
- end
52
- end
53
- end
54
- end # AsyncProxy
55
- end # FiniteMachine
@@ -1,107 +0,0 @@
1
- # encoding: utf-8
2
-
3
- RSpec.describe FiniteMachine, 'async events' do
4
-
5
- it 'runs events asynchronously' do
6
- called = []
7
- fsm = FiniteMachine.define do
8
- initial :green
9
-
10
- events {
11
- event :slow, :green => :yellow
12
- event :stop, :yellow => :red
13
- event :ready, :red => :yellow
14
- event :go, :yellow => :green
15
- }
16
-
17
- callbacks {
18
- on_enter :yellow do |event, a| called << "on_enter_yellow_#{a}" end
19
- on_enter :red do |event, a| called << "on_enter_red_#{a}" end
20
- }
21
- end
22
-
23
- expect(fsm.current).to eql(:green)
24
- fsm.async.slow(:foo)
25
- fsm.event_queue.join 0.01
26
- expect(fsm.current).to eql(:yellow)
27
- expect(called).to eql([
28
- 'on_enter_yellow_foo'
29
- ])
30
- fsm.async(:stop, :bar) # execute directly
31
- fsm.event_queue.join 0.01
32
- expect(fsm.current).to eql(:red)
33
- expect(called).to match_array([
34
- 'on_enter_yellow_foo',
35
- 'on_enter_red_bar'
36
- ])
37
- end
38
-
39
- it 'correctly passes parameters to conditionals' do
40
- called = []
41
- fsm = FiniteMachine.define do
42
- events {
43
- event :go, :none => :green,
44
- if: proc { |context, arg|
45
- called << "cond_none_green(#{context},#{arg})"; true
46
- }
47
-
48
- event :stop, from: :any do
49
- choice :red, if: proc { |context, arg|
50
- called << "cond_any_red(#{context},#{arg})"; true
51
- }
52
- end
53
- }
54
- end
55
- expect(fsm.current).to eql(:none)
56
- fsm.async.go(:foo)
57
- fsm.event_queue.join 0.02
58
- expect(fsm.current).to eql(:green)
59
- expect(called).to eql(["cond_none_green(#{fsm},foo)"])
60
-
61
- expect(fsm.current).to eql(:green)
62
- fsm.async.stop(:bar)
63
- fsm.event_queue.join 0.02
64
- expect(fsm.current).to eql(:red)
65
- expect(called).to match_array([
66
- "cond_none_green(#{fsm},foo)",
67
- "cond_any_red(#{fsm},bar)"
68
- ])
69
- end
70
-
71
- it "ensure queue per thread" do
72
- called = []
73
- fsmFoo = nil
74
- fsmBar = nil
75
- foo_thread = Thread.new {
76
- fsmFoo = FiniteMachine.define do
77
- initial :green
78
- events { event :slow, :green => :yellow }
79
-
80
- callbacks {
81
- on_enter :yellow do |event, a| called << "(foo)on_enter_yellow_#{a}" end
82
- }
83
- end
84
- fsmFoo.async.slow(:foo)
85
- }
86
- bar_thread = Thread.new {
87
- fsmBar = FiniteMachine.define do
88
- initial :green
89
- events { event :slow, :green => :yellow }
90
-
91
- callbacks {
92
- on_enter :yellow do |event, a| called << "(bar)on_enter_yellow_#{a}" end
93
- }
94
- end
95
- fsmBar.async.slow(:bar)
96
- }
97
- ThreadsWait.all_waits(foo_thread, bar_thread)
98
- fsmFoo.event_queue.join(0.01)
99
- fsmBar.event_queue.join(0.01)
100
- expect(called).to match_array([
101
- '(foo)on_enter_yellow_foo',
102
- '(bar)on_enter_yellow_bar'
103
- ])
104
- expect(fsmFoo.current).to eql(:yellow)
105
- expect(fsmBar.current).to eql(:yellow)
106
- end
107
- end
@@ -1,25 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::EventsChain, '.add' do
6
- it "adds transitions" do
7
- transition = double(:transition)
8
- events_chain = described_class.new
9
-
10
- events_chain.add(:validated, transition)
11
- expect(events_chain[:validated]).to eq([transition])
12
-
13
- events_chain.add(:validated, transition)
14
- expect(events_chain[:validated]).to eq([transition, transition])
15
- end
16
-
17
- it "allows to chain add operations" do
18
- events_chain = described_class.new
19
- transition = double(:transition)
20
-
21
- events_chain.add(:go, transition).add(:start, transition)
22
-
23
- expect(events_chain.size).to eq(2)
24
- end
25
- end
@@ -1,22 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::EventsChain, '.cancel_transitions' do
6
- it "sets cancel status for chosen transitions" do
7
- events_chain = described_class.new
8
- transition_a = spy(:transition_a, cancelled: false)
9
- transition_b = spy(:transition_b, cancelled: false)
10
- transition_c = spy(:transition_c, cancelled: false)
11
-
12
- events_chain.add(:start, transition_a)
13
- events_chain.add(:start, transition_b)
14
- events_chain.add(:finish, transition_c)
15
-
16
- events_chain.cancel_transitions(:start)
17
-
18
- expect(transition_a).to have_received(:cancelled=).with(true)
19
- expect(transition_b).to have_received(:cancelled=).with(true)
20
- expect(transition_c).not_to have_received(:cancelled=)
21
- end
22
- end
@@ -1,28 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::EventsChain, '.choice_transition?' do
6
-
7
- it "checks if transition has many branches" do
8
- transition_a = double(:transition_a, matches?: true)
9
- transition_b = double(:transition_b, matches?: true)
10
-
11
- events_chain = described_class.new
12
- events_chain.add(:go, transition_a)
13
- events_chain.add(:go, transition_b)
14
-
15
- expect(events_chain.choice_transition?(:go, :green)).to eq(true)
16
- end
17
-
18
- it "checks that transition has no branches" do
19
- transition_a = double(:transition_a, matches?: false)
20
- transition_b = double(:transition_b, matches?: true)
21
-
22
- events_chain = described_class.new
23
- events_chain.add(:go, transition_a)
24
- events_chain.add(:go, transition_b)
25
-
26
- expect(events_chain.choice_transition?(:go, :green)).to eq(false)
27
- end
28
- end
@@ -1,15 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::EventsChain, '#clear' do
6
- it "clears chain events" do
7
- event = double(:event)
8
- events_chain = described_class.new
9
- events_chain.add(:validated, event)
10
- expect(events_chain.empty?).to be(false)
11
-
12
- events_chain.clear
13
- expect(events_chain.empty?).to be(true)
14
- end
15
- end
@@ -1,18 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::EventsChain, '.events' do
6
- it "has no event names" do
7
- events_chain = described_class.new
8
- expect(events_chain.events).to eq([])
9
- end
10
-
11
- it "returns all event names" do
12
- events_chain = described_class.new
13
- transition = double(:transition)
14
- events_chain.add(:ready, transition)
15
- events_chain.add(:go, transition)
16
- expect(events_chain.events).to match_array([:ready, :go])
17
- end
18
- end
@@ -1,24 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::EventsChain, '#inspect' do
6
- it "inspects empty events chain" do
7
- events_chain = described_class.new
8
- expect(events_chain.inspect).to eq("<#FiniteMachine::EventsChain @chain={}>")
9
- end
10
-
11
- it "inspect events chain" do
12
- transition = double(:transition)
13
- events_chain = described_class.new
14
- events_chain.add(:validated, transition)
15
- expect(events_chain.inspect).to eq("<#FiniteMachine::EventsChain @chain=#{{validated: [transition]}}>")
16
- end
17
-
18
- it "prints events chain" do
19
- transition = double(:transition)
20
- events_chain = described_class.new
21
- events_chain.add(:validated, transition)
22
- expect(events_chain.to_s).to eq("#{{validated: [transition]}}")
23
- end
24
- end
@@ -1,17 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe FiniteMachine::EventsChain do
4
- it "finds current states for event name" do
5
- transition = spy(:transition, states: {:red => :yellow, :yellow => :green})
6
- events_chain = described_class.new
7
- events_chain.add(:start, transition)
8
-
9
- expect(events_chain.states_for(:start)).to eq([:red, :yellow])
10
- end
11
-
12
- it "fails to find any states for event name" do
13
- events_chain = described_class.new
14
-
15
- expect(events_chain.states_for(:start)).to eq([])
16
- end
17
- end
@@ -1,13 +0,0 @@
1
- # encoding: utf-8
2
-
3
- RSpec.describe FiniteMachine::HookEvent, '#infer_default_name' do
4
- it "infers default name for state" do
5
- hook_event = described_class::Enter
6
- expect(described_class.infer_default_name(hook_event)).to eq(:any)
7
- end
8
-
9
- it "infers default name for event" do
10
- hook_event = described_class::Before
11
- expect(described_class.infer_default_name(hook_event)).to eq(:any_event)
12
- end
13
- end
@@ -1,25 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe FiniteMachine::StateParser, "#inspect" do
6
- let(:object) { described_class }
7
-
8
- subject(:parser) { object.new(attrs) }
9
-
10
- describe '#inspect' do
11
- let(:attrs) { { green: :yellow } }
12
-
13
- it "inspects parser" do
14
- expect(parser.inspect).to eq("<#FiniteMachine::StateParser @attrs=green:yellow>")
15
- end
16
- end
17
-
18
- describe '#to_s' do
19
- let(:attrs) { { green: :yellow } }
20
-
21
- it "prints parser attributes" do
22
- expect(parser.to_s).to eq(attrs.to_s)
23
- end
24
- end
25
- end