finite_machine 0.11.2 → 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.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +80 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +679 -624
  5. data/lib/finite_machine.rb +35 -45
  6. data/lib/finite_machine/async_call.rb +5 -21
  7. data/lib/finite_machine/callable.rb +4 -4
  8. data/lib/finite_machine/catchable.rb +24 -14
  9. data/lib/finite_machine/choice_merger.rb +20 -20
  10. data/lib/finite_machine/const.rb +16 -0
  11. data/lib/finite_machine/definition.rb +3 -3
  12. data/lib/finite_machine/dsl.rb +98 -151
  13. data/lib/finite_machine/env.rb +4 -2
  14. data/lib/finite_machine/event_definition.rb +7 -15
  15. data/lib/finite_machine/{events_chain.rb → events_map.rb} +40 -53
  16. data/lib/finite_machine/hook_event.rb +60 -61
  17. data/lib/finite_machine/hooks.rb +44 -36
  18. data/lib/finite_machine/listener.rb +2 -2
  19. data/lib/finite_machine/logger.rb +5 -4
  20. data/lib/finite_machine/{event_queue.rb → message_queue.rb} +76 -32
  21. data/lib/finite_machine/observer.rb +71 -34
  22. data/lib/finite_machine/safety.rb +16 -14
  23. data/lib/finite_machine/state_definition.rb +3 -5
  24. data/lib/finite_machine/state_machine.rb +93 -76
  25. data/lib/finite_machine/state_parser.rb +55 -83
  26. data/lib/finite_machine/subscribers.rb +2 -2
  27. data/lib/finite_machine/threadable.rb +3 -1
  28. data/lib/finite_machine/transition.rb +34 -34
  29. data/lib/finite_machine/transition_builder.rb +23 -32
  30. data/lib/finite_machine/transition_event.rb +12 -11
  31. data/lib/finite_machine/two_phase_lock.rb +8 -6
  32. data/lib/finite_machine/undefined_transition.rb +5 -6
  33. data/lib/finite_machine/version.rb +2 -2
  34. metadata +58 -142
  35. data/.gitignore +0 -18
  36. data/.rspec +0 -5
  37. data/.ruby-gemset +0 -1
  38. data/.ruby-version +0 -1
  39. data/.travis.yml +0 -26
  40. data/Gemfile +0 -15
  41. data/Rakefile +0 -8
  42. data/assets/finite_machine_logo.png +0 -0
  43. data/examples/atm.rb +0 -45
  44. data/examples/bug_system.rb +0 -145
  45. data/finite_machine.gemspec +0 -23
  46. data/lib/finite_machine/async_proxy.rb +0 -30
  47. data/spec/integration/system_spec.rb +0 -95
  48. data/spec/spec_helper.rb +0 -33
  49. data/spec/unit/alias_target_spec.rb +0 -108
  50. data/spec/unit/async_events_spec.rb +0 -138
  51. data/spec/unit/callable/call_spec.rb +0 -113
  52. data/spec/unit/callbacks_spec.rb +0 -942
  53. data/spec/unit/can_spec.rb +0 -98
  54. data/spec/unit/choice_spec.rb +0 -331
  55. data/spec/unit/define_spec.rb +0 -55
  56. data/spec/unit/definition_spec.rb +0 -115
  57. data/spec/unit/event_names_spec.rb +0 -19
  58. data/spec/unit/event_queue_spec.rb +0 -52
  59. data/spec/unit/events_chain/add_spec.rb +0 -25
  60. data/spec/unit/events_chain/cancel_transitions_spec.rb +0 -22
  61. data/spec/unit/events_chain/choice_transition_spec.rb +0 -28
  62. data/spec/unit/events_chain/clear_spec.rb +0 -15
  63. data/spec/unit/events_chain/events_spec.rb +0 -18
  64. data/spec/unit/events_chain/inspect_spec.rb +0 -24
  65. data/spec/unit/events_chain/match_transition_spec.rb +0 -37
  66. data/spec/unit/events_chain/move_to_spec.rb +0 -48
  67. data/spec/unit/events_chain/states_for_spec.rb +0 -17
  68. data/spec/unit/events_spec.rb +0 -459
  69. data/spec/unit/handlers_spec.rb +0 -152
  70. data/spec/unit/hook_event/build_spec.rb +0 -15
  71. data/spec/unit/hook_event/eql_spec.rb +0 -36
  72. data/spec/unit/hook_event/infer_default_name_spec.rb +0 -13
  73. data/spec/unit/hook_event/initialize_spec.rb +0 -25
  74. data/spec/unit/hook_event/notify_spec.rb +0 -14
  75. data/spec/unit/hooks/call_spec.rb +0 -24
  76. data/spec/unit/hooks/clear_spec.rb +0 -16
  77. data/spec/unit/hooks/inspect_spec.rb +0 -17
  78. data/spec/unit/hooks/register_spec.rb +0 -22
  79. data/spec/unit/if_unless_spec.rb +0 -353
  80. data/spec/unit/initial_spec.rb +0 -222
  81. data/spec/unit/inspect_spec.rb +0 -17
  82. data/spec/unit/is_spec.rb +0 -55
  83. data/spec/unit/log_transitions_spec.rb +0 -30
  84. data/spec/unit/logger_spec.rb +0 -38
  85. data/spec/unit/respond_to_spec.rb +0 -38
  86. data/spec/unit/state_parser/inspect_spec.rb +0 -25
  87. data/spec/unit/state_parser/parse_spec.rb +0 -59
  88. data/spec/unit/states_spec.rb +0 -34
  89. data/spec/unit/subscribers_spec.rb +0 -42
  90. data/spec/unit/target_spec.rb +0 -225
  91. data/spec/unit/terminated_spec.rb +0 -95
  92. data/spec/unit/transition/check_conditions_spec.rb +0 -54
  93. data/spec/unit/transition/inspect_spec.rb +0 -25
  94. data/spec/unit/transition/matches_spec.rb +0 -23
  95. data/spec/unit/transition/states_spec.rb +0 -31
  96. data/spec/unit/transition/to_state_spec.rb +0 -27
  97. data/spec/unit/trigger_spec.rb +0 -22
  98. data/spec/unit/undefined_transition/eql_spec.rb +0 -17
  99. data/tasks/console.rake +0 -11
  100. data/tasks/coverage.rake +0 -11
  101. data/tasks/spec.rake +0 -29
data/.gitignore DELETED
@@ -1,18 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
18
- *.sw[a-z]
data/.rspec DELETED
@@ -1,5 +0,0 @@
1
- --color
2
- --format progress
3
- --order random
4
- --warnings
5
- --require spec_helper
@@ -1 +0,0 @@
1
- finite_machine
@@ -1 +0,0 @@
1
- 2.0.0
@@ -1,26 +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
- - ruby-head
13
- - rbx-2
14
- matrix:
15
- include:
16
- - rvm: jruby-19mode
17
- - rvm: jruby-20mode
18
- - rvm: jruby-21mode
19
- - rvm: jruby-head
20
- allow_failures:
21
- - rvm: ruby-head
22
- - rvm: jruby-head
23
- - rvm: rbx-2
24
- fast_finish: true
25
- branches:
26
- only: master
data/Gemfile DELETED
@@ -1,15 +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 'yard', '~> 0.8.7'
9
- end
10
-
11
- group :metrics do
12
- gem 'coveralls', '~> 0.8.1'
13
- gem 'simplecov', '~> 0.10.0'
14
- gem 'yardstick', '~> 0.9.9'
15
- end
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "bundler/gem_tasks"
4
-
5
- FileList['tasks/**/*.rake'].each(&method(:import))
6
-
7
- desc 'Run all specs'
8
- task ci: %w[ spec ]
@@ -1,45 +0,0 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
- require 'finite_machine'
4
-
5
- class Account
6
- attr_accessor :number
7
-
8
- def verify(account_number, pin)
9
- return account_number == 123456 && pin == 666
10
- end
11
- end
12
-
13
- account = Account.new
14
-
15
- atm = FiniteMachine.define do
16
- initial :unauthorized
17
-
18
- target account
19
-
20
- events {
21
- event :authorize, :unauthorized => :authorized, if: -> (account, account_number, pin) {
22
- account.verify(account_number, pin)
23
- }
24
- event :deauthorize, :authorized => :unauthorized
25
- }
26
-
27
- callbacks {
28
- on_exit :unauthorized do |event, account_number, pin|
29
- # if verify(account_number, pin)
30
- self.number = account_number
31
- # else
32
- # puts "Invalid Account and/or PIN"
33
- # FiniteMachine::CANCELLED
34
- # end
35
- end
36
- }
37
- end
38
-
39
- atm.authorize(111222, 666)
40
- puts "authorized: #{atm.authorized?}"
41
- puts "Number: #{account.number}"
42
-
43
- atm.authorize(123456, 666)
44
- puts "authorized: #{atm.authorized?}"
45
- puts "Number: #{account.number}"
@@ -1,145 +0,0 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
- require 'finite_machine'
4
-
5
- class User
6
- attr_accessor :name
7
-
8
- def initialize(name)
9
- @name = name
10
- end
11
- end
12
-
13
- class Manager < User
14
- attr_accessor :developers
15
-
16
- def initialize(name)
17
- super
18
- @developers = []
19
- end
20
-
21
- def manages(developer)
22
- @developers << developer
23
- end
24
-
25
- def assign(bug)
26
- developer = @developers.first
27
- bug.assign
28
- developer.bug = bug
29
- end
30
- end
31
-
32
- class Tester < User
33
- def report(bug)
34
- bug.report
35
- end
36
-
37
- def reopen(bug)
38
- bug.reopen
39
- end
40
- end
41
-
42
- class Developer < User
43
- attr_accessor :bug
44
-
45
- def work_on
46
- bug.start
47
- end
48
-
49
- def resolve
50
- bug.close
51
- end
52
- end
53
-
54
- class BugSystem
55
- attr_accessor :managers
56
-
57
- def initialize(managers = [])
58
- @managers = managers
59
- end
60
-
61
- def notify_manager(bug)
62
- manager = @managers.first
63
- manager.assign(bug)
64
- end
65
- end
66
-
67
- class Bug
68
- attr_accessor :name
69
- attr_accessor :priority
70
- # fake belongs_to relationship
71
- attr_accessor :bug_system
72
-
73
- def initialize(name, priority)
74
- @name = name
75
- @priority = priority
76
- end
77
-
78
- def report
79
- status.report
80
- end
81
-
82
- def assign
83
- status.assign
84
- end
85
-
86
- def start
87
- status.start
88
- end
89
-
90
- def close
91
- status.close
92
- end
93
-
94
- def reopen
95
- status.reopen
96
- end
97
-
98
- def status
99
- context = self
100
- @status ||= FiniteMachine.define do
101
- target context
102
-
103
- events {
104
- event :report, :none => :new
105
- event :assign, :new => :assigned
106
- event :start, :assigned => :in_progress
107
- event :close, [:in_progress, :reopened] => :resolved
108
- event :reopen, :resolved => :reopened
109
- }
110
-
111
- callbacks {
112
- on_enter :new do |event|
113
- bug_system.notify_manager(self)
114
- end
115
- }
116
- end
117
- end
118
- end
119
-
120
- tester = Tester.new("John")
121
- manager = Manager.new("David")
122
- developer = Developer.new("Piotr")
123
- manager.manages(developer)
124
-
125
- bug_system = BugSystem.new([manager])
126
- bug = Bug.new(:trojan, :high)
127
- bug.bug_system = bug_system
128
-
129
- puts "A BUG's LIFE"
130
- puts "#1 #{bug.status.current}"
131
-
132
- tester.report(bug)
133
- puts "#2 #{bug.status.current}"
134
-
135
- developer.work_on
136
- puts "#3 #{bug.status.current}"
137
-
138
- developer.resolve
139
- puts "#4 #{bug.status.current}"
140
-
141
- tester.reopen(bug)
142
- puts "#5 #{bug.status.current}"
143
-
144
- developer.resolve
145
- puts "#6 #{bug.status.current}"
@@ -1,23 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'finite_machine/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "finite_machine"
8
- spec.version = FiniteMachine::VERSION
9
- spec.authors = ["Piotr Murach"]
10
- spec.email = [""]
11
- spec.description = %q{A minimal finite state machine with a straightforward syntax. You can quickly model states, add callbacks and use object-oriented techniques to integrate with ORMs.}
12
- spec.summary = %q{A minimal finite state machine with a straightforward syntax.}
13
- spec.homepage = "http://peter-murach.github.io/finite_machine/"
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_development_dependency "bundler"
22
- spec.add_development_dependency "rake"
23
- end
@@ -1,30 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module FiniteMachine
4
- # An asynchronous messages proxy
5
- class AsyncProxy
6
- include Threadable
7
-
8
- attr_threadsafe :context
9
-
10
- # Initialize an AsynxProxy
11
- #
12
- # @param [Object] context
13
- # the context this proxy is associated with
14
- #
15
- # @api private
16
- def initialize(context)
17
- self.context = context
18
- end
19
-
20
- # Delegate asynchronous event to event queue
21
- #
22
- # @api private
23
- def method_missing(method_name, *args, &block)
24
- callable = Callable.new(method_name)
25
- async_call = AsyncCall.new(context, callable, *args, &block)
26
-
27
- context.event_queue << async_call
28
- end
29
- end # AsyncProxy
30
- end # FiniteMachine
@@ -1,95 +0,0 @@
1
- # encoding: utf-8
2
-
3
- RSpec.describe FiniteMachine, 'system' do
4
-
5
- it "doesn't share state between machine callbacks" do
6
- callbacks = []
7
- stub_const("FSM_A", Class.new(FiniteMachine::Definition) do
8
- events {
9
- event :init, :none => :green
10
- event :green, :any => :green
11
- }
12
- callbacks {
13
- on_before do |event|
14
- callbacks << "fsmA on_before(#{event.to})"
15
- end
16
- on_enter_green do |event|
17
- target.fire
18
- callbacks << "fsmA on_enter_green"
19
- end
20
- once_on_enter_green do |event|
21
- callbacks << "fsmA once_on_enter_green"
22
- end
23
- }
24
- end)
25
-
26
- stub_const("FSM_B", Class.new(FiniteMachine::Definition) do
27
- events {
28
- event :init, :none => :stopped
29
- event :start, :stopped => :started
30
- }
31
- callbacks {
32
- on_before do |event|
33
- callbacks << "fsmB on_before(#{event.to})"
34
- end
35
- on_enter_started do |event|
36
- callbacks << "fsmB on_enter_started"
37
- end
38
- }
39
- end)
40
-
41
- class Backend
42
- def initialize
43
- @fsmB = FSM_B.new
44
- @fsmB.init
45
- @signal = Mutex.new
46
- end
47
-
48
- def operate
49
- @signal.unlock if @signal.locked?
50
- @worker = Thread.new do
51
- while !@signal.locked? do
52
- sleep 0.01
53
- end
54
- Thread.current.abort_on_exception = true
55
- @fsmB.start
56
- end
57
- end
58
-
59
- def stopit
60
- @signal.lock
61
- @worker.join
62
- end
63
- end
64
-
65
- class Fire
66
- def initialize
67
- @fsmA = FSM_A.new
68
- @fsmA.target(self)
69
-
70
- @backend = Backend.new
71
- @backend.operate
72
- end
73
-
74
- def fire
75
- @backend.stopit
76
- end
77
-
78
- def operate
79
- @fsmA.green
80
- end
81
- end
82
-
83
- fire = Fire.new
84
- fire.operate
85
-
86
- expect(callbacks).to match_array([
87
- 'fsmA on_before(green)',
88
- 'fsmA on_enter_green',
89
- 'fsmA once_on_enter_green',
90
- 'fsmB on_before(stopped)',
91
- 'fsmB on_before(started)',
92
- 'fsmB on_enter_started'
93
- ])
94
- end
95
- end
@@ -1,33 +0,0 @@
1
- # encoding: utf-8
2
-
3
- if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS'])
4
- require 'simplecov'
5
- require 'coveralls'
6
-
7
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
- SimpleCov::Formatter::HTMLFormatter,
9
- Coveralls::SimpleCov::Formatter
10
- ]
11
-
12
- SimpleCov.start do
13
- command_name 'spec'
14
- add_filter 'spec'
15
- end
16
- end
17
-
18
- require 'finite_machine'
19
- require 'thwait'
20
-
21
- RSpec.configure do |config|
22
- config.run_all_when_everything_filtered = true
23
- config.filter_run :focus
24
- config.raise_errors_for_deprecations!
25
- config.mock_with :rspec do |mocks|
26
- mocks.verify_partial_doubles = true
27
- end
28
- config.disable_monkey_patching!
29
- if config.files_to_run.one?
30
- config.default_formatter = 'doc'
31
- end
32
- config.order = :random
33
- end