barebone-fsm 0.0.1
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.
- data/lib/barebone-fsm.rb +172 -0
- metadata +47 -0
data/lib/barebone-fsm.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
##
|
2
|
+
# == Overview
|
3
|
+
# ---
|
4
|
+
# This module implements a basic finite-state machine (FSM).
|
5
|
+
# An FSM consists of a finite number of states,
|
6
|
+
# with one of them being the current state of the FSM.
|
7
|
+
# Transitions are defined between states, which are triggered on events.
|
8
|
+
# For details on FSM, see this wiki page: {FSM}[http://en.wikipedia.org/wiki/Finite-state_machine].
|
9
|
+
#
|
10
|
+
# The motivation behind the module was to implement a very basic barebone FSM in Ruby.
|
11
|
+
# Features are kept at minimum as well as the code.
|
12
|
+
# Only two classes for the FSM are defined as the following:
|
13
|
+
# * FSM -> the finite state machine class
|
14
|
+
# * FSMState -> the state class
|
15
|
+
#
|
16
|
+
# Author:: Md. Imrul Hassan (mailto:mihassan@gmail.com)
|
17
|
+
# Copyright:: Copyright: Md. Imrul Hassan, 2013
|
18
|
+
#
|
19
|
+
# == Status
|
20
|
+
# The module works, but further testing and documentation is needed.
|
21
|
+
# The api is not stable yet, I may decide to change the way FSM is used.
|
22
|
+
#
|
23
|
+
# == Features
|
24
|
+
# Apart from having support for states and events, this module offers the following features:
|
25
|
+
# 1. Default state
|
26
|
+
# 2. Default event for each state
|
27
|
+
# 3. Entry and exit events for each state
|
28
|
+
#
|
29
|
+
# == Usage
|
30
|
+
# ---
|
31
|
+
# A simple example:
|
32
|
+
#
|
33
|
+
# fsm = FSM::FSM.new
|
34
|
+
# state = fsm[:state_name]
|
35
|
+
# state.event(:event_name) do |st, ev|
|
36
|
+
# puts "#{ev} triggered on state #{st}"
|
37
|
+
# :new_state}
|
38
|
+
# end
|
39
|
+
# fsm.event :event_name
|
40
|
+
#
|
41
|
+
# A complete example:
|
42
|
+
#
|
43
|
+
# fsm = FSM::FSM.new(:stopped)
|
44
|
+
#
|
45
|
+
# fsm[:stopped].event(:open) { puts "[Stopped]: Door Opened"; :open}
|
46
|
+
# fsm[:stopped].event(:start) { puts "[Stopped]: Started"; :started}
|
47
|
+
# fsm[:stopped].event(:enter) {|st, ev| puts "[Stopped]: Eneter into state #{st}"}
|
48
|
+
# fsm[:stopped].event(:exit) {|st, ev| puts "[Stopped]: Exit from state #{st}"}
|
49
|
+
#
|
50
|
+
# fsm[:open].event(:close) { puts "[Open]: Door Closed"; :stopped}
|
51
|
+
# fsm[:open].event(:default) {|st, ev| puts "[Open]: Event [#{ev}] not defined in state #{st}"; :open}
|
52
|
+
# fsm[:open].event(:enter) {|st, ev| puts "[Open]: Eneter into state #{st}"}
|
53
|
+
# fsm[:open].event(:exit) {|st, ev| puts "[Open]: Exit from state #{st}"}
|
54
|
+
#
|
55
|
+
# fsm[:started].event(:open) { puts "[Started]: Door Opened"; :open}
|
56
|
+
# fsm[:started].event(:stop) { puts "[Started]: Stopped"; :stopped}
|
57
|
+
# fsm[:started].event(:enter) {|st, ev| puts "[Started]: Eneter into state #{st}"}
|
58
|
+
# fsm[:started].event(:exit) {|st, ev| puts "[Started]: Exit from state #{st}"}
|
59
|
+
#
|
60
|
+
# puts fsm
|
61
|
+
#
|
62
|
+
# fsm.event :open
|
63
|
+
# fsm.event :start
|
64
|
+
# fsm.event :close
|
65
|
+
# fsm.event :start
|
66
|
+
# fsm.event :stop
|
67
|
+
# fsm.event :start
|
68
|
+
#
|
69
|
+
# puts sm
|
70
|
+
#
|
71
|
+
module FSM
|
72
|
+
|
73
|
+
# == Overview
|
74
|
+
# ---
|
75
|
+
# FSMState class represents a state of the finite state machine.
|
76
|
+
#
|
77
|
+
# == Usage
|
78
|
+
# ---
|
79
|
+
# state = FSMState.new :state_name
|
80
|
+
# state.event(:event_name) {|st, ev| puts "#{ev} triggered on state #{st}"; :new_state} # creates the event when block is given
|
81
|
+
# puts state
|
82
|
+
# state.event :event_name # triggers the event when block is absent
|
83
|
+
#
|
84
|
+
class FSMState
|
85
|
+
|
86
|
+
attr_reader :name
|
87
|
+
|
88
|
+
def initialize(state_name)
|
89
|
+
@name = state_name
|
90
|
+
@events = {}
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_s()
|
94
|
+
@name.to_s +
|
95
|
+
": [" +
|
96
|
+
@events.keys.map(&:to_s).join(', ') +
|
97
|
+
"]"
|
98
|
+
end
|
99
|
+
|
100
|
+
def event(event_name, &event_block)
|
101
|
+
if block_given? then
|
102
|
+
@events[event_name] = event_block
|
103
|
+
else
|
104
|
+
if @events.has_key? event_name then
|
105
|
+
@events[event_name].call @name, event_name
|
106
|
+
elsif @events.has_key? :default then
|
107
|
+
@events[:default].call @name, event_name
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
# == Overview
|
115
|
+
# ---
|
116
|
+
# This class implements the finite-state machine.
|
117
|
+
# FSM class exposes the states it contains and can trigger an event.
|
118
|
+
# States are created on the fly first time it's referenced through index operator [].
|
119
|
+
#
|
120
|
+
# The FSM state transits to the default state if the latest event does not define the next state.
|
121
|
+
# If default state is not set, then state does not change on undefined state.
|
122
|
+
# The initial state of the FSM is the first state mentioned.
|
123
|
+
# This can be either the default state if defined or the first referenced state.
|
124
|
+
#
|
125
|
+
# == Usage
|
126
|
+
# ---
|
127
|
+
# fsm = FSM.new :default_state
|
128
|
+
# fsm[:default_state].event(:first_event) do |st, ev| # the state is defined and referenced at the same time
|
129
|
+
# puts "The first transition from the default_state to state_name"
|
130
|
+
# :state_name # the next state is defined here
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
class FSM
|
134
|
+
attr_reader :state
|
135
|
+
|
136
|
+
def initialize(default_state=nil)
|
137
|
+
@states = {}
|
138
|
+
if default_state then
|
139
|
+
@state = @default = default_state
|
140
|
+
@states[@state] = FSMState.new(@state)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_s()
|
145
|
+
"FSM" +
|
146
|
+
": {" +
|
147
|
+
@states.values.map{ |st|
|
148
|
+
(st.name==@state ? ">" : "") + st.to_s
|
149
|
+
}.join(', ') +
|
150
|
+
"}"
|
151
|
+
end
|
152
|
+
|
153
|
+
def [](state_name)
|
154
|
+
unless @states.has_key? state_name then
|
155
|
+
@states[state_name] = FSMState.new(state_name)
|
156
|
+
@state ||= state_name
|
157
|
+
end
|
158
|
+
@states[state_name]
|
159
|
+
end
|
160
|
+
|
161
|
+
def event(event_name)
|
162
|
+
@states[@state].event :exit
|
163
|
+
new_state = @states[@state].event event_name
|
164
|
+
new_state = nil if not @states.has_key? new_state
|
165
|
+
new_state ||= @default_state
|
166
|
+
new_state ||= @state
|
167
|
+
@state = new_state
|
168
|
+
@states[@state].event :enter
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: barebone-fsm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Md. Imrul Hassan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-18 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A barebone implementation of finite state machine keeping simplicity
|
15
|
+
in mind.
|
16
|
+
email: mihassan@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/barebone-fsm.rb
|
22
|
+
homepage: http://rubygems.org/gems/barebone-fsm
|
23
|
+
licenses: []
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 1.8.24
|
43
|
+
signing_key:
|
44
|
+
specification_version: 3
|
45
|
+
summary: A barebone finite state machine(FSM).
|
46
|
+
test_files: []
|
47
|
+
has_rdoc:
|