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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +80 -0
- data/LICENSE.txt +1 -1
- data/README.md +679 -624
- data/lib/finite_machine.rb +35 -45
- data/lib/finite_machine/async_call.rb +5 -21
- data/lib/finite_machine/callable.rb +4 -4
- data/lib/finite_machine/catchable.rb +24 -14
- data/lib/finite_machine/choice_merger.rb +20 -20
- data/lib/finite_machine/const.rb +16 -0
- data/lib/finite_machine/definition.rb +3 -3
- data/lib/finite_machine/dsl.rb +98 -151
- data/lib/finite_machine/env.rb +4 -2
- data/lib/finite_machine/event_definition.rb +7 -15
- data/lib/finite_machine/{events_chain.rb → events_map.rb} +40 -53
- data/lib/finite_machine/hook_event.rb +60 -61
- data/lib/finite_machine/hooks.rb +44 -36
- data/lib/finite_machine/listener.rb +2 -2
- data/lib/finite_machine/logger.rb +5 -4
- data/lib/finite_machine/{event_queue.rb → message_queue.rb} +76 -32
- data/lib/finite_machine/observer.rb +71 -34
- data/lib/finite_machine/safety.rb +16 -14
- data/lib/finite_machine/state_definition.rb +3 -5
- data/lib/finite_machine/state_machine.rb +93 -76
- data/lib/finite_machine/state_parser.rb +55 -83
- data/lib/finite_machine/subscribers.rb +2 -2
- data/lib/finite_machine/threadable.rb +3 -1
- data/lib/finite_machine/transition.rb +34 -34
- data/lib/finite_machine/transition_builder.rb +23 -32
- data/lib/finite_machine/transition_event.rb +12 -11
- data/lib/finite_machine/two_phase_lock.rb +8 -6
- data/lib/finite_machine/undefined_transition.rb +5 -6
- data/lib/finite_machine/version.rb +2 -2
- metadata +58 -142
- data/.gitignore +0 -18
- data/.rspec +0 -5
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/.travis.yml +0 -26
- data/Gemfile +0 -15
- data/Rakefile +0 -8
- data/assets/finite_machine_logo.png +0 -0
- data/examples/atm.rb +0 -45
- data/examples/bug_system.rb +0 -145
- data/finite_machine.gemspec +0 -23
- data/lib/finite_machine/async_proxy.rb +0 -30
- data/spec/integration/system_spec.rb +0 -95
- data/spec/spec_helper.rb +0 -33
- data/spec/unit/alias_target_spec.rb +0 -108
- data/spec/unit/async_events_spec.rb +0 -138
- data/spec/unit/callable/call_spec.rb +0 -113
- data/spec/unit/callbacks_spec.rb +0 -942
- data/spec/unit/can_spec.rb +0 -98
- data/spec/unit/choice_spec.rb +0 -331
- data/spec/unit/define_spec.rb +0 -55
- data/spec/unit/definition_spec.rb +0 -115
- data/spec/unit/event_names_spec.rb +0 -19
- data/spec/unit/event_queue_spec.rb +0 -52
- data/spec/unit/events_chain/add_spec.rb +0 -25
- data/spec/unit/events_chain/cancel_transitions_spec.rb +0 -22
- data/spec/unit/events_chain/choice_transition_spec.rb +0 -28
- data/spec/unit/events_chain/clear_spec.rb +0 -15
- data/spec/unit/events_chain/events_spec.rb +0 -18
- data/spec/unit/events_chain/inspect_spec.rb +0 -24
- data/spec/unit/events_chain/match_transition_spec.rb +0 -37
- data/spec/unit/events_chain/move_to_spec.rb +0 -48
- data/spec/unit/events_chain/states_for_spec.rb +0 -17
- data/spec/unit/events_spec.rb +0 -459
- data/spec/unit/handlers_spec.rb +0 -152
- data/spec/unit/hook_event/build_spec.rb +0 -15
- data/spec/unit/hook_event/eql_spec.rb +0 -36
- data/spec/unit/hook_event/infer_default_name_spec.rb +0 -13
- data/spec/unit/hook_event/initialize_spec.rb +0 -25
- data/spec/unit/hook_event/notify_spec.rb +0 -14
- data/spec/unit/hooks/call_spec.rb +0 -24
- data/spec/unit/hooks/clear_spec.rb +0 -16
- data/spec/unit/hooks/inspect_spec.rb +0 -17
- data/spec/unit/hooks/register_spec.rb +0 -22
- data/spec/unit/if_unless_spec.rb +0 -353
- data/spec/unit/initial_spec.rb +0 -222
- data/spec/unit/inspect_spec.rb +0 -17
- data/spec/unit/is_spec.rb +0 -55
- data/spec/unit/log_transitions_spec.rb +0 -30
- data/spec/unit/logger_spec.rb +0 -38
- data/spec/unit/respond_to_spec.rb +0 -38
- data/spec/unit/state_parser/inspect_spec.rb +0 -25
- data/spec/unit/state_parser/parse_spec.rb +0 -59
- data/spec/unit/states_spec.rb +0 -34
- data/spec/unit/subscribers_spec.rb +0 -42
- data/spec/unit/target_spec.rb +0 -225
- data/spec/unit/terminated_spec.rb +0 -95
- data/spec/unit/transition/check_conditions_spec.rb +0 -54
- data/spec/unit/transition/inspect_spec.rb +0 -25
- data/spec/unit/transition/matches_spec.rb +0 -23
- data/spec/unit/transition/states_spec.rb +0 -31
- data/spec/unit/transition/to_state_spec.rb +0 -27
- data/spec/unit/trigger_spec.rb +0 -22
- data/spec/unit/undefined_transition/eql_spec.rb +0 -17
- data/tasks/console.rake +0 -11
- data/tasks/coverage.rake +0 -11
- data/tasks/spec.rake +0 -29
data/.gitignore
DELETED
data/.rspec
DELETED
data/.ruby-gemset
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
finite_machine
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.0.0
|
data/.travis.yml
DELETED
@@ -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
Binary file
|
data/examples/atm.rb
DELETED
@@ -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}"
|
data/examples/bug_system.rb
DELETED
@@ -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}"
|
data/finite_machine.gemspec
DELETED
@@ -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
|
data/spec/spec_helper.rb
DELETED
@@ -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
|