hifsm 0.1.0 → 0.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/README.md +14 -3
- data/lib/hifsm/callbacks.rb +9 -5
- data/lib/hifsm/event.rb +8 -6
- data/lib/hifsm/fsm.rb +14 -14
- data/lib/hifsm/machine.rb +2 -2
- data/lib/hifsm/state.rb +12 -7
- data/lib/hifsm/version.rb +1 -1
- data/test/monster.rb +5 -2
- data/test/test_any_state_event.rb +2 -2
- data/test/test_basic_fsm.rb +2 -2
- data/test/test_event_guard.rb +10 -7
- data/test/test_hierarchical.rb +58 -0
- data/test/test_ifless_factorial.rb +41 -0
- data/test/test_many_states.rb +34 -0
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 25b5e3332cdc03d7cdc7efee6fa52b83a2a85881
|
|
4
|
+
data.tar.gz: 52f1ffd9779265883292b018ed76ee480032cbf5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ecec06c7780e4ab19a6c98fa6191d5a3aeea238ba5c790d0b9a3a02a87b68838ec36c166bbdec15f8d75f9d125d0197f6b79d1833f2e1bcb73f96b110df702e2
|
|
7
|
+
data.tar.gz: 4e113ea01e29154d6cf2b62a08243a0b7a4054a9c254f59dffc468874f94b843e94c7586de327d0743dfda2c2f98c0e6f775c6168a968011ec3ef62f9d3d20c7
|
data/README.md
CHANGED
|
@@ -39,7 +39,7 @@ Here is how to use it to model a monster in a Quake-like game. It covers most Hi
|
|
|
39
39
|
require 'hifsm'
|
|
40
40
|
|
|
41
41
|
class Monster
|
|
42
|
-
@@fsm = Hifsm::FSM.
|
|
42
|
+
@@fsm = Hifsm::FSM.new do
|
|
43
43
|
state :idle, :initial => true
|
|
44
44
|
state :attacking do
|
|
45
45
|
state :acquiring_target, :initial => true do
|
|
@@ -97,7 +97,7 @@ class Monster
|
|
|
97
97
|
def initialize
|
|
98
98
|
@debug = false
|
|
99
99
|
@home = 'home'
|
|
100
|
-
@state = @@fsm.
|
|
100
|
+
@state = @@fsm.instantiate(self) # or @@fsm.instantiate(self, 'attacking.pursuing')
|
|
101
101
|
@tick = 1
|
|
102
102
|
@low_hp = false
|
|
103
103
|
end
|
|
@@ -155,6 +155,9 @@ ogre.act! # -> ~~> player2
|
|
|
155
155
|
ogre.enemy_dead # -> Woohoo!
|
|
156
156
|
ogre.act! # -> Acting @coming_back
|
|
157
157
|
# -> step step home
|
|
158
|
+
ogre.low_hp = true
|
|
159
|
+
ogre.sight 'player3'
|
|
160
|
+
ogre.act! # -> Acting @runaway
|
|
158
161
|
|
|
159
162
|
```
|
|
160
163
|
|
|
@@ -174,10 +177,18 @@ On event:
|
|
|
174
177
|
* to_state.after_enter
|
|
175
178
|
* event.after
|
|
176
179
|
|
|
177
|
-
If `before...`
|
|
180
|
+
If any of `before...` callbacks returns `false` then no further processing is done, no exceptions raised, machine state is not changed.
|
|
178
181
|
|
|
179
182
|
On `act!` just calls action block if it was given.
|
|
180
183
|
|
|
184
|
+
## Testing
|
|
185
|
+
|
|
186
|
+
Only 'public' API is unit-tested, internal implementation may be freely changed, so don't rely on it.
|
|
187
|
+
|
|
188
|
+
To run tests use `bundle exec rake test`
|
|
189
|
+
|
|
190
|
+
Try also `bundle exec ruby test/monster.rb`
|
|
191
|
+
|
|
181
192
|
## Contributing
|
|
182
193
|
|
|
183
194
|
1. Fork it
|
data/lib/hifsm/callbacks.rb
CHANGED
|
@@ -4,9 +4,13 @@ class Callbacks
|
|
|
4
4
|
def invoke(target, cb, *args)
|
|
5
5
|
if cb.nil?
|
|
6
6
|
elsif cb.is_a? Symbol
|
|
7
|
-
target.
|
|
7
|
+
if target.method(cb).arity > 0
|
|
8
|
+
target.send(cb, *args)
|
|
9
|
+
else
|
|
10
|
+
target.send(cb)
|
|
11
|
+
end
|
|
8
12
|
else
|
|
9
|
-
target.instance_exec
|
|
13
|
+
target.instance_exec(*args, &cb)
|
|
10
14
|
end
|
|
11
15
|
end
|
|
12
16
|
end
|
|
@@ -15,12 +19,12 @@ class Callbacks
|
|
|
15
19
|
@listeners = []
|
|
16
20
|
end
|
|
17
21
|
|
|
18
|
-
def add(&callback)
|
|
19
|
-
@listeners.push callback
|
|
22
|
+
def add(symbol = nil, &callback)
|
|
23
|
+
@listeners.push symbol || callback
|
|
20
24
|
end
|
|
21
25
|
|
|
22
26
|
def trigger(target, *args)
|
|
23
|
-
@listeners.
|
|
27
|
+
@listeners.map do |callback|
|
|
24
28
|
Callbacks.invoke target, callback, *args
|
|
25
29
|
end
|
|
26
30
|
end
|
data/lib/hifsm/event.rb
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
module Hifsm
|
|
2
2
|
class Event
|
|
3
|
-
CALLBACKS = [:before, :after].freeze
|
|
3
|
+
CALLBACKS = [:before, :after, :guard].freeze
|
|
4
4
|
|
|
5
5
|
attr_reader :name, :to
|
|
6
6
|
|
|
7
|
-
def initialize(name, to,
|
|
7
|
+
def initialize(name, to, guards)
|
|
8
8
|
@name = name
|
|
9
|
-
@guard = guard
|
|
10
9
|
@to = to
|
|
11
|
-
|
|
12
10
|
@callbacks = Hash.new {|h, key| h[key] = Callbacks.new }
|
|
11
|
+
|
|
12
|
+
guards.each do |g|
|
|
13
|
+
@callbacks[:guard].add g
|
|
14
|
+
end
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
CALLBACKS.each do |cb|
|
|
@@ -20,8 +22,8 @@ module Hifsm
|
|
|
20
22
|
@callbacks[cb].trigger(target, *args)
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
def guard?(target)
|
|
24
|
-
|
|
25
|
+
def guard?(target, *args)
|
|
26
|
+
trigger(target, :guard, *args).all?
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
end
|
data/lib/hifsm/fsm.rb
CHANGED
|
@@ -2,22 +2,16 @@ module Hifsm
|
|
|
2
2
|
class FSM
|
|
3
3
|
attr_reader :states, :transitions
|
|
4
4
|
|
|
5
|
-
class <<self
|
|
6
|
-
def define(&block)
|
|
7
|
-
Hifsm::FSM.new(&block)
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
5
|
def initialize(parent = nil, &block)
|
|
12
6
|
@parent = parent
|
|
13
7
|
@states = {}
|
|
14
|
-
@initial_state
|
|
8
|
+
@initial_state = nil
|
|
15
9
|
|
|
16
|
-
instance_eval
|
|
10
|
+
instance_eval(&block) if block
|
|
17
11
|
end
|
|
18
12
|
|
|
19
|
-
def
|
|
20
|
-
Hifsm::Machine.new(
|
|
13
|
+
def instantiate(target = nil, initial_state = nil)
|
|
14
|
+
Hifsm::Machine.new(self, target, initial_state)
|
|
21
15
|
end
|
|
22
16
|
|
|
23
17
|
def all_events
|
|
@@ -29,24 +23,30 @@ module Hifsm
|
|
|
29
23
|
end
|
|
30
24
|
|
|
31
25
|
def get_state!(name)
|
|
32
|
-
|
|
26
|
+
top_level_state, rest = name.to_s.split('.', 2)
|
|
27
|
+
st = @states[top_level_state] || raise(Hifsm::MissingState.new(name.to_s))
|
|
28
|
+
if rest
|
|
29
|
+
st.get_substate!(rest)
|
|
30
|
+
else
|
|
31
|
+
st
|
|
32
|
+
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def event(name, options, &block)
|
|
36
|
-
ev = Hifsm::Event.new(name, get_state!(options[:to]), options[:guard])
|
|
36
|
+
ev = Hifsm::Event.new(name, get_state!(options[:to]), array_wrap(options[:guard]))
|
|
37
37
|
from_states = array_wrap(options[:from])
|
|
38
38
|
from_states = @states.keys if from_states.empty?
|
|
39
39
|
from_states.each do |from|
|
|
40
40
|
st = get_state!(from)
|
|
41
41
|
st.add_transition(ev)
|
|
42
42
|
end
|
|
43
|
-
ev.instance_eval
|
|
43
|
+
ev.instance_eval(&block) if block
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def state(name, options = {}, &block)
|
|
47
47
|
st = @states[name.to_s] = Hifsm::State.new(name, @parent)
|
|
48
48
|
@initial_state = st if options[:initial]
|
|
49
|
-
st.instance_eval
|
|
49
|
+
st.instance_eval(&block) if block
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
private
|
data/lib/hifsm/machine.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module Hifsm
|
|
2
2
|
class Machine
|
|
3
|
-
def initialize(
|
|
3
|
+
def initialize(fsm, target, initial_state = nil)
|
|
4
4
|
@target = target || self
|
|
5
5
|
@fsm = fsm
|
|
6
6
|
|
|
7
|
-
@state = fsm.
|
|
7
|
+
@state = (initial_state && fsm.get_state!(initial_state) || fsm.initial_state!).enter!
|
|
8
8
|
|
|
9
9
|
mach = self
|
|
10
10
|
fsm.all_events.each do |event_name, event|
|
data/lib/hifsm/state.rb
CHANGED
|
@@ -5,7 +5,8 @@ module Hifsm
|
|
|
5
5
|
def initialize(name, parent = nil)
|
|
6
6
|
@name = name
|
|
7
7
|
@parent = parent
|
|
8
|
-
@action
|
|
8
|
+
@action = nil
|
|
9
|
+
@sub_fsm = nil
|
|
9
10
|
|
|
10
11
|
@callbacks = Hash.new {|h, key| h[key] = Callbacks.new }
|
|
11
12
|
@transitions = Hash.new {|h, key| h[key] = Array.new }
|
|
@@ -21,11 +22,11 @@ module Hifsm
|
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def state(*args, &block)
|
|
24
|
-
sub_fsm!.state
|
|
25
|
+
sub_fsm!.state(*args, &block)
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def event(*args, &block)
|
|
28
|
-
sub_fsm!.event
|
|
29
|
+
sub_fsm!.event(*args, &block)
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
def events
|
|
@@ -35,7 +36,7 @@ module Hifsm
|
|
|
35
36
|
def fire(target, event_name, *args, &new_state_callback)
|
|
36
37
|
event_name = event_name.to_s
|
|
37
38
|
@transitions[event_name].each do |ev|
|
|
38
|
-
if ev.guard?(target)
|
|
39
|
+
if ev.guard?(target, *args)
|
|
39
40
|
from_state = self
|
|
40
41
|
to_state = ev.to
|
|
41
42
|
if ev.trigger(target, :before, *args) &&
|
|
@@ -46,7 +47,7 @@ module Hifsm
|
|
|
46
47
|
to_state.trigger(target, :after_enter, *args)
|
|
47
48
|
ev.trigger(target, :after, *args)
|
|
48
49
|
end
|
|
49
|
-
return
|
|
50
|
+
return target
|
|
50
51
|
end
|
|
51
52
|
end
|
|
52
53
|
if @parent
|
|
@@ -64,9 +65,8 @@ module Hifsm
|
|
|
64
65
|
end
|
|
65
66
|
|
|
66
67
|
def act!(target, *args)
|
|
68
|
+
@parent.act!(target, *args) if @parent
|
|
67
69
|
@action && Callbacks.invoke(target, @action, *args)
|
|
68
|
-
if @sub_fsm
|
|
69
|
-
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def enter!
|
|
@@ -77,6 +77,11 @@ module Hifsm
|
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
def get_substate!(name)
|
|
81
|
+
raise Hifsm::MissingState.new(name.to_s) unless @sub_fsm
|
|
82
|
+
@sub_fsm.get_state!(name)
|
|
83
|
+
end
|
|
84
|
+
|
|
80
85
|
def to_s
|
|
81
86
|
if @parent
|
|
82
87
|
"#{@parent.to_s}.#{@name.to_s}"
|
data/lib/hifsm/version.rb
CHANGED
data/test/monster.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'hifsm'
|
|
2
2
|
|
|
3
3
|
class Monster
|
|
4
|
-
@@fsm = Hifsm::FSM.
|
|
4
|
+
@@fsm = Hifsm::FSM.new do
|
|
5
5
|
state :idle, :initial => true
|
|
6
6
|
state :attacking do
|
|
7
7
|
state :acquiring_target, :initial => true do
|
|
@@ -59,7 +59,7 @@ class Monster
|
|
|
59
59
|
def initialize
|
|
60
60
|
@debug = false
|
|
61
61
|
@home = 'home'
|
|
62
|
-
@state = @@fsm.
|
|
62
|
+
@state = @@fsm.instantiate(self) # or @@fsm.instantiate(self, 'attacking.pursuing')
|
|
63
63
|
@tick = 1
|
|
64
64
|
@low_hp = false
|
|
65
65
|
end
|
|
@@ -118,4 +118,7 @@ if $0 == __FILE__
|
|
|
118
118
|
ogre.enemy_dead # -> Woohoo!
|
|
119
119
|
ogre.act! # -> Acting @coming_back
|
|
120
120
|
# -> step step home
|
|
121
|
+
ogre.low_hp = true
|
|
122
|
+
ogre.sight 'player3'
|
|
123
|
+
ogre.act! # -> Acting @runaway
|
|
121
124
|
end
|
|
@@ -2,7 +2,7 @@ require 'setup_tests'
|
|
|
2
2
|
|
|
3
3
|
class TestAnyStateEvent < Minitest::Test
|
|
4
4
|
def setup
|
|
5
|
-
@fsm = Hifsm::FSM.
|
|
5
|
+
@fsm = Hifsm::FSM.new do
|
|
6
6
|
state :off, :initial => true
|
|
7
7
|
state :on
|
|
8
8
|
state :halt
|
|
@@ -11,7 +11,7 @@ class TestAnyStateEvent < Minitest::Test
|
|
|
11
11
|
event :toggle, :from => :on, :to => :off
|
|
12
12
|
event :halt, :to => :halt
|
|
13
13
|
end
|
|
14
|
-
@machine = @fsm.
|
|
14
|
+
@machine = @fsm.instantiate
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def test_halt_from_off
|
data/test/test_basic_fsm.rb
CHANGED
|
@@ -2,14 +2,14 @@ require 'setup_tests'
|
|
|
2
2
|
|
|
3
3
|
class TestBasicFSM < Minitest::Test
|
|
4
4
|
def setup
|
|
5
|
-
@fsm = Hifsm::FSM.
|
|
5
|
+
@fsm = Hifsm::FSM.new do
|
|
6
6
|
state :off, :initial => true
|
|
7
7
|
state :on
|
|
8
8
|
|
|
9
9
|
event :toggle, :from => :off, :to => :on
|
|
10
10
|
event :toggle, :from => :on, :to => :off
|
|
11
11
|
end
|
|
12
|
-
@machine = @fsm.
|
|
12
|
+
@machine = @fsm.instantiate
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def test_initial_state_is_off
|
data/test/test_event_guard.rb
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
require 'setup_tests'
|
|
2
2
|
|
|
3
3
|
class TestEventGuard < Minitest::Test
|
|
4
|
-
|
|
5
|
-
@wall = Struct.new(:stones).new(10)
|
|
4
|
+
Wall = Struct.new(:stones)
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
def build_wall(thickness)
|
|
7
|
+
fsm = Hifsm::FSM.new do
|
|
8
8
|
state :constructed, :initial => true
|
|
9
9
|
state :broken
|
|
10
10
|
|
|
11
11
|
event :break, :from => :constructed, :to => :broken, :guard => proc { stones < 5 }
|
|
12
12
|
end
|
|
13
|
-
|
|
13
|
+
wall = Wall.new(thickness)
|
|
14
|
+
@machine = fsm.instantiate(wall)
|
|
15
|
+
wall
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def test_cant_break_wall_10_stones_thick
|
|
19
|
+
wall = build_wall 10
|
|
17
20
|
assert_raises(Hifsm::MissingTransition) do
|
|
18
|
-
|
|
21
|
+
wall.break
|
|
19
22
|
end
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
def test_cant_break_thin_wall
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
wall = build_wall 3
|
|
27
|
+
wall.break
|
|
25
28
|
assert_equal 'broken', @machine.state
|
|
26
29
|
end
|
|
27
30
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'setup_tests'
|
|
2
|
+
|
|
3
|
+
class TestHierarchical < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
@fsm = Hifsm::FSM.new do
|
|
6
|
+
async = proc do
|
|
7
|
+
state :pending, :initial => true
|
|
8
|
+
state :sync
|
|
9
|
+
|
|
10
|
+
event :sync, :from => :pending, :to => :sync
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
state :off, :initial => true, &async
|
|
14
|
+
state :on, &async
|
|
15
|
+
|
|
16
|
+
event :toggle, :from => 'off.sync', :to => :on
|
|
17
|
+
event :toggle, :from => 'on.sync', :to => 'off.sync'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_initial_state_is_off_pending_by_default
|
|
22
|
+
machine = @fsm.instantiate
|
|
23
|
+
assert_equal 'off.pending', machine.state
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_explicit_initial_state
|
|
27
|
+
machine2 = @fsm.instantiate(nil, 'on.sync')
|
|
28
|
+
assert_equal 'on.sync', machine2.state
|
|
29
|
+
machine2.toggle
|
|
30
|
+
pass # assert_nothing_raised
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_toggle_raises_an_error_in_pending_state
|
|
34
|
+
machine = @fsm.instantiate
|
|
35
|
+
assert_raises(Hifsm::MissingTransition) do
|
|
36
|
+
machine.toggle
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_sync
|
|
41
|
+
machine = @fsm.instantiate
|
|
42
|
+
machine.sync
|
|
43
|
+
assert_equal 'off.sync', machine.state
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_toggle_from_off_sync_to_on_pending
|
|
47
|
+
machine = @fsm.instantiate
|
|
48
|
+
machine.sync
|
|
49
|
+
machine.toggle
|
|
50
|
+
assert_equal 'on.pending', machine.state
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_toggle_from_on_sync_to_off_sync
|
|
54
|
+
machine2 = @fsm.instantiate(nil, 'on.sync')
|
|
55
|
+
machine2.toggle
|
|
56
|
+
assert_equal 'off.sync', machine2.state
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'setup_tests'
|
|
2
|
+
|
|
3
|
+
class TestIflessFactorial < Minitest::Test
|
|
4
|
+
Value = Struct.new(:value)
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
@fsm = Hifsm::FSM.new do
|
|
8
|
+
state :idle, :initial => true
|
|
9
|
+
state :counting
|
|
10
|
+
|
|
11
|
+
event :count, :to => :idle do
|
|
12
|
+
guard { |x| x == 0 }
|
|
13
|
+
after { |x| self.value = 1 }
|
|
14
|
+
end
|
|
15
|
+
event :count, :to => :counting do
|
|
16
|
+
after do |x|
|
|
17
|
+
count(x - 1)
|
|
18
|
+
self.value *= x
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def factorial(n)
|
|
25
|
+
val = Value.new
|
|
26
|
+
@fsm.instantiate(val)
|
|
27
|
+
val.count(n).value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_factorial_0
|
|
31
|
+
assert_equal 1, factorial(0)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_factorial_5
|
|
35
|
+
assert_equal 120, factorial(5)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_factorial_100
|
|
39
|
+
assert_equal 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000, factorial(100)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'setup_tests'
|
|
2
|
+
|
|
3
|
+
class TestManyStates < Minitest::Test
|
|
4
|
+
def inefficient_factorial(n)
|
|
5
|
+
fsm = Hifsm::FSM.new do
|
|
6
|
+
state :value0 do
|
|
7
|
+
action { 1 }
|
|
8
|
+
end
|
|
9
|
+
(1..n).each do |x|
|
|
10
|
+
state "value#{x}" do
|
|
11
|
+
action do
|
|
12
|
+
x * prev.act!
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
event :prev, :from => "value#{x}", :to => "value#{x - 1}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
machine = fsm.instantiate(nil, "value#{n}")
|
|
19
|
+
machine.act!
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_factorial_0
|
|
23
|
+
assert_equal 1, inefficient_factorial(0)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_factorial_5
|
|
27
|
+
assert_equal 120, inefficient_factorial(5)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_factorial_100
|
|
31
|
+
assert_equal 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000, inefficient_factorial(100)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hifsm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vladimir Meremyanin
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-09-
|
|
11
|
+
date: 2014-09-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -78,6 +78,9 @@ files:
|
|
|
78
78
|
- test/test_any_state_event.rb
|
|
79
79
|
- test/test_basic_fsm.rb
|
|
80
80
|
- test/test_event_guard.rb
|
|
81
|
+
- test/test_hierarchical.rb
|
|
82
|
+
- test/test_ifless_factorial.rb
|
|
83
|
+
- test/test_many_states.rb
|
|
81
84
|
- test/test_monster.rb
|
|
82
85
|
homepage: http://github.com/stiff/hifsm
|
|
83
86
|
licenses:
|
|
@@ -110,4 +113,7 @@ test_files:
|
|
|
110
113
|
- test/test_any_state_event.rb
|
|
111
114
|
- test/test_basic_fsm.rb
|
|
112
115
|
- test/test_event_guard.rb
|
|
116
|
+
- test/test_hierarchical.rb
|
|
117
|
+
- test/test_ifless_factorial.rb
|
|
118
|
+
- test/test_many_states.rb
|
|
113
119
|
- test/test_monster.rb
|