micromachine 1.1.0 → 1.2.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 +4 -4
- data/.gems +1 -0
- data/LICENSE +1 -1
- data/README.md +8 -0
- data/examples/advanced.rb +23 -0
- data/examples/basic.rb +27 -0
- data/examples/callbacks.rb +31 -0
- data/lib/micromachine.rb +13 -4
- data/makefile +5 -0
- data/micromachine.gemspec +9 -6
- data/test/callbacks.rb +44 -0
- data/test/helper.rb +2 -0
- data/test/introspection.rb +27 -0
- data/test/transitions.rb +53 -0
- metadata +19 -9
- data/Rakefile +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 695548d56ffdf4666ad19b2fb55af4a647f2f364
|
4
|
+
data.tar.gz: 4331c9df0cd25f86ccdadbfe6070fcfbd31a2d21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b98dae4b90be60013ad87c90db67d6c232fcc5632d038d47e691c85efb6ac5f63296f06dd94725988c36adb1715470484b5c42d87ce54c4f5bebbc3755822015
|
7
|
+
data.tar.gz: b7ed4f8bf6f5a2d62589e4acb964f0f5fec4b4a773cda49cbcc367bfacb077656fa3ec4504919218a3a5df55c6ad24296503f26504609139b342f370c6ee33d0
|
data/.gems
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
cutest -v 1.2.2
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -62,6 +62,14 @@ machine.trigger?(:reset) #=> true
|
|
62
62
|
machine.state #=> :ignored
|
63
63
|
```
|
64
64
|
|
65
|
+
If you want to force an Exception when trying to trigger a event from a
|
66
|
+
non compatible state use the `trigger!` method:
|
67
|
+
|
68
|
+
``` ruby
|
69
|
+
machine.trigger?(:ignore) #=> false
|
70
|
+
machine.trigger!(:ignore) #=> MicroMachine::InvalidState raised
|
71
|
+
```
|
72
|
+
|
65
73
|
It can also have callbacks when entering some state:
|
66
74
|
|
67
75
|
``` ruby
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'micromachine'
|
2
|
+
|
3
|
+
# This example can be run with ruby -I lib/ example/advanced.rb
|
4
|
+
|
5
|
+
fsm = MicroMachine.new(:pending)
|
6
|
+
|
7
|
+
fsm.when(:confirm, :pending => :confirmed)
|
8
|
+
fsm.when(:ignore, :pending => :ignored)
|
9
|
+
fsm.when(:reset, :confirmed => :pending, :ignored => :pending)
|
10
|
+
|
11
|
+
puts "Should print Confirmed, Pending and Ignored:"
|
12
|
+
|
13
|
+
fsm.on(:any) do
|
14
|
+
puts fsm.state.capitalize
|
15
|
+
end
|
16
|
+
|
17
|
+
fsm.trigger(:confirm)
|
18
|
+
|
19
|
+
fsm.trigger(:ignore)
|
20
|
+
|
21
|
+
fsm.trigger(:reset)
|
22
|
+
|
23
|
+
fsm.trigger(:ignore)
|
data/examples/basic.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'micromachine'
|
2
|
+
|
3
|
+
# This example can be run with ruby -I lib/ example/basic.rb
|
4
|
+
|
5
|
+
fsm = MicroMachine.new(:pending)
|
6
|
+
|
7
|
+
fsm.when(:confirm, :pending => :confirmed)
|
8
|
+
fsm.when(:ignore, :pending => :ignored)
|
9
|
+
fsm.when(:reset, :confirmed => :pending, :ignored => :pending)
|
10
|
+
|
11
|
+
puts "Should print Confirmed, Reset and Ignored:"
|
12
|
+
|
13
|
+
if fsm.trigger(:confirm)
|
14
|
+
puts "Confirmed"
|
15
|
+
end
|
16
|
+
|
17
|
+
if fsm.trigger(:ignore)
|
18
|
+
puts "Ignored"
|
19
|
+
end
|
20
|
+
|
21
|
+
if fsm.trigger(:reset)
|
22
|
+
puts "Reset"
|
23
|
+
end
|
24
|
+
|
25
|
+
if fsm.trigger(:ignore)
|
26
|
+
puts "Ignored"
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'micromachine'
|
2
|
+
|
3
|
+
# This example can be run with ruby -I lib/ example/callbacks.rb
|
4
|
+
|
5
|
+
fsm = MicroMachine.new(:pending)
|
6
|
+
|
7
|
+
fsm.when(:confirm, :pending => :confirmed)
|
8
|
+
fsm.when(:ignore, :pending => :ignored)
|
9
|
+
fsm.when(:reset, :confirmed => :pending, :ignored => :pending)
|
10
|
+
|
11
|
+
puts "Should print Confirmed, Reset and Ignored:"
|
12
|
+
|
13
|
+
fsm.on(:confirmed) do
|
14
|
+
puts "Confirmed"
|
15
|
+
end
|
16
|
+
|
17
|
+
fsm.on(:ignored) do
|
18
|
+
puts "Ignored"
|
19
|
+
end
|
20
|
+
|
21
|
+
fsm.on(:pending) do
|
22
|
+
puts "Reset"
|
23
|
+
end
|
24
|
+
|
25
|
+
fsm.trigger(:confirm)
|
26
|
+
|
27
|
+
fsm.trigger(:ignore)
|
28
|
+
|
29
|
+
fsm.trigger(:reset)
|
30
|
+
|
31
|
+
fsm.trigger(:ignore)
|
data/lib/micromachine.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
class MicroMachine
|
2
2
|
InvalidEvent = Class.new(NoMethodError)
|
3
|
+
InvalidState = Class.new(ArgumentError)
|
3
4
|
|
4
5
|
attr :transitions_for
|
5
6
|
attr :state
|
6
7
|
|
7
|
-
def initialize
|
8
|
+
def initialize(initial_state)
|
8
9
|
@state = initial_state
|
9
10
|
@transitions_for = Hash.new
|
10
11
|
@callbacks = Hash.new { |hash, key| hash[key] = [] }
|
11
12
|
end
|
12
13
|
|
13
|
-
def on
|
14
|
+
def on(key, &block)
|
14
15
|
@callbacks[key] << block
|
15
16
|
end
|
16
17
|
|
@@ -18,17 +19,25 @@ class MicroMachine
|
|
18
19
|
transitions_for[event] = transitions
|
19
20
|
end
|
20
21
|
|
21
|
-
def trigger
|
22
|
+
def trigger(event)
|
22
23
|
if trigger?(event)
|
23
24
|
@state = transitions_for[event][@state]
|
24
25
|
callbacks = @callbacks[@state] + @callbacks[:any]
|
25
|
-
callbacks.each { |callback| callback.call }
|
26
|
+
callbacks.each { |callback| callback.call(event) }
|
26
27
|
true
|
27
28
|
else
|
28
29
|
false
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
33
|
+
def trigger!(event)
|
34
|
+
if trigger(event)
|
35
|
+
true
|
36
|
+
else
|
37
|
+
raise InvalidState.new("Event '#{event}' not valid from state '#{@state}'")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
32
41
|
def trigger?(event)
|
33
42
|
raise InvalidEvent unless transitions_for.has_key?(event)
|
34
43
|
transitions_for[event][state] ? true : false
|
data/makefile
ADDED
data/micromachine.gemspec
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
|
-
s.name =
|
3
|
-
s.version =
|
2
|
+
s.name = "micromachine"
|
3
|
+
s.version = "1.2.0"
|
4
4
|
s.summary = %{Minimal Finite State Machine.}
|
5
5
|
s.description = %Q{There are many finite state machine implementations for Ruby, and they all provide a nice DSL for declaring events, exceptions, callbacks, and all kinds of niceties in general.\n\nBut if all you want is a finite state machine, look no further: this has less than 50 lines of code and provides everything a finite state machine must have, and nothing more.}
|
6
|
-
s.author = "Michel Martens"
|
7
|
-
s.email = "michel@soveran.com"
|
6
|
+
s.author = ["Michel Martens"]
|
7
|
+
s.email = ["michel@soveran.com"]
|
8
8
|
s.homepage = "http://github.com/soveran/micromachine"
|
9
|
-
s.
|
10
|
-
|
9
|
+
s.license = "MIT"
|
10
|
+
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
|
13
|
+
s.add_development_dependency "cutest"
|
11
14
|
end
|
data/test/callbacks.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
setup do
|
4
|
+
machine = MicroMachine.new(:pending)
|
5
|
+
machine.when(:confirm, pending: :confirmed)
|
6
|
+
machine.when(:reset, confirmed: :pending)
|
7
|
+
|
8
|
+
machine.on(:pending) { @state = "Pending" }
|
9
|
+
machine.on(:confirmed) { @state = "Confirmed" }
|
10
|
+
machine.on(:any) { @current = @state }
|
11
|
+
|
12
|
+
machine
|
13
|
+
end
|
14
|
+
|
15
|
+
test "executes callbacks when entering a state" do |machine|
|
16
|
+
machine.trigger(:confirm)
|
17
|
+
assert_equal "Confirmed", @state
|
18
|
+
|
19
|
+
machine.trigger(:reset)
|
20
|
+
assert_equal "Pending", @state
|
21
|
+
end
|
22
|
+
|
23
|
+
test "executes the callback on any transition" do |machine|
|
24
|
+
machine.trigger(:confirm)
|
25
|
+
assert_equal "Confirmed", @current
|
26
|
+
|
27
|
+
machine.trigger(:reset)
|
28
|
+
assert_equal "Pending", @current
|
29
|
+
end
|
30
|
+
|
31
|
+
test "passing the event name to the callbacks" do
|
32
|
+
event_name = nil
|
33
|
+
|
34
|
+
machine = MicroMachine.new(:pending)
|
35
|
+
machine.when(:confirm, pending: :confirmed)
|
36
|
+
|
37
|
+
machine.on(:confirmed) do |event|
|
38
|
+
event_name = event
|
39
|
+
end
|
40
|
+
|
41
|
+
machine.trigger(:confirm)
|
42
|
+
|
43
|
+
assert_equal(:confirm, event_name)
|
44
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
setup do
|
4
|
+
machine = MicroMachine.new(:pending)
|
5
|
+
|
6
|
+
machine.when(:confirm, pending: :confirmed)
|
7
|
+
machine.when(:ignore, pending: :ignored)
|
8
|
+
machine.when(:reset, confirmed: :pending, ignored: :pending)
|
9
|
+
|
10
|
+
machine
|
11
|
+
end
|
12
|
+
|
13
|
+
test "returns an array with the defined events" do |machine|
|
14
|
+
assert_equal [:confirm, :ignore, :reset], machine.events
|
15
|
+
end
|
16
|
+
|
17
|
+
test "returns an array with the defined states" do |machine|
|
18
|
+
assert_equal [:pending, :confirmed, :ignored], machine.states
|
19
|
+
end
|
20
|
+
|
21
|
+
test "returns false if compared state is not equal to current" do |machine|
|
22
|
+
assert !(machine == :confirmed)
|
23
|
+
end
|
24
|
+
|
25
|
+
test "returns true if compared state is equal to current" do |machine|
|
26
|
+
assert machine == :pending
|
27
|
+
end
|
data/test/transitions.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
setup do
|
4
|
+
machine = MicroMachine.new(:pending)
|
5
|
+
|
6
|
+
machine.when(:confirm, pending: :confirmed)
|
7
|
+
machine.when(:ignore, pending: :ignored)
|
8
|
+
machine.when(:reset, confirmed: :pending, ignored: :pending)
|
9
|
+
|
10
|
+
machine
|
11
|
+
end
|
12
|
+
|
13
|
+
test "defines initial state" do |machine|
|
14
|
+
assert_equal :pending, machine.state
|
15
|
+
end
|
16
|
+
|
17
|
+
test "raises an error if an invalid event is triggered" do |machine|
|
18
|
+
assert_raise(MicroMachine::InvalidEvent) do
|
19
|
+
machine.trigger(:random_event)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
test "preserves the state if transition is not possible" do |machine|
|
24
|
+
assert !machine.trigger?(:reset)
|
25
|
+
assert !machine.trigger(:reset)
|
26
|
+
assert_equal :pending, machine.state
|
27
|
+
end
|
28
|
+
|
29
|
+
test "changes the state if transition is possible" do |machine|
|
30
|
+
assert machine.trigger?(:confirm)
|
31
|
+
assert machine.trigger(:confirm)
|
32
|
+
assert_equal :confirmed, machine.state
|
33
|
+
end
|
34
|
+
|
35
|
+
test "discerns multiple transitions" do |machine|
|
36
|
+
machine.trigger(:confirm)
|
37
|
+
assert_equal :confirmed, machine.state
|
38
|
+
|
39
|
+
machine.trigger(:reset)
|
40
|
+
assert_equal :pending, machine.state
|
41
|
+
|
42
|
+
machine.trigger(:ignore)
|
43
|
+
assert_equal :ignored, machine.state
|
44
|
+
|
45
|
+
machine.trigger(:reset)
|
46
|
+
assert_equal :pending, machine.state
|
47
|
+
end
|
48
|
+
|
49
|
+
test "raises an error if event is triggered from/to a non complatible state" do |machine|
|
50
|
+
assert_raise(MicroMachine::InvalidState) do
|
51
|
+
machine.trigger!(:reset)
|
52
|
+
end
|
53
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: micromachine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michel Martens
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: cutest
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - '>='
|
@@ -28,18 +28,28 @@ description: |-
|
|
28
28
|
There are many finite state machine implementations for Ruby, and they all provide a nice DSL for declaring events, exceptions, callbacks, and all kinds of niceties in general.
|
29
29
|
|
30
30
|
But if all you want is a finite state machine, look no further: this has less than 50 lines of code and provides everything a finite state machine must have, and nothing more.
|
31
|
-
email:
|
31
|
+
email:
|
32
|
+
- michel@soveran.com
|
32
33
|
executables: []
|
33
34
|
extensions: []
|
34
35
|
extra_rdoc_files: []
|
35
36
|
files:
|
36
|
-
-
|
37
|
-
- README.md
|
37
|
+
- .gems
|
38
38
|
- LICENSE
|
39
|
-
-
|
39
|
+
- README.md
|
40
|
+
- examples/advanced.rb
|
41
|
+
- examples/basic.rb
|
42
|
+
- examples/callbacks.rb
|
43
|
+
- lib/micromachine.rb
|
44
|
+
- makefile
|
40
45
|
- micromachine.gemspec
|
46
|
+
- test/callbacks.rb
|
47
|
+
- test/helper.rb
|
48
|
+
- test/introspection.rb
|
49
|
+
- test/transitions.rb
|
41
50
|
homepage: http://github.com/soveran/micromachine
|
42
|
-
licenses:
|
51
|
+
licenses:
|
52
|
+
- MIT
|
43
53
|
metadata: {}
|
44
54
|
post_install_message:
|
45
55
|
rdoc_options: []
|
@@ -57,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
67
|
version: '0'
|
58
68
|
requirements: []
|
59
69
|
rubyforge_project:
|
60
|
-
rubygems_version: 2.0.
|
70
|
+
rubygems_version: 2.0.14
|
61
71
|
signing_key:
|
62
72
|
specification_version: 4
|
63
73
|
summary: Minimal Finite State Machine.
|