finite_machine 0.11.2 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
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