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