pretty-fsm 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/Manifest +10 -0
- data/README +7 -0
- data/Rakefile +24 -0
- data/examples/door.rb +51 -0
- data/examples/timed_door.rb +41 -0
- data/lib/pretty-fsm/fsm.rb +55 -0
- data/lib/pretty-fsm/timed_event.rb +28 -0
- data/lib/pretty-fsm.rb +2 -0
- data/nbproject/project.properties +7 -0
- data/nbproject/project.xml +14 -0
- data/pretty-fsm.gemspec +30 -0
- metadata +80 -0
data/Manifest
ADDED
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake'
|
4
|
+
require 'echoe'
|
5
|
+
#require 'yard'
|
6
|
+
|
7
|
+
Echoe.new('pretty-fsm') do |p|
|
8
|
+
p.author = 'v01d'
|
9
|
+
p.summary = "Finite State Machine class with intuitive integration"
|
10
|
+
p.url = "http://github.com/v01d/pretty-fsm"
|
11
|
+
p.version = "0.1"
|
12
|
+
# p.dependencies = ['yard']
|
13
|
+
# p.eval = proc { s.has_rdoc = 'yard' }
|
14
|
+
end
|
15
|
+
|
16
|
+
#Rake::TaskManager.class_eval do
|
17
|
+
# def remove_task(task)
|
18
|
+
# @tasks.delete(task.to_s)
|
19
|
+
# end
|
20
|
+
#end
|
21
|
+
|
22
|
+
#Rake.application.remove_task(:docs)
|
23
|
+
#YARD::Rake::YardocTask.new(:docs) {|t| t.options = ['--verbose','--no-private','--hide-void']}
|
24
|
+
|
data/examples/door.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
require 'pretty-fsm'
|
3
|
+
|
4
|
+
class Door
|
5
|
+
include PrettyFSM::Abbreviate
|
6
|
+
|
7
|
+
attr_reader(:fsm)
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@fsm = PrettyFSM::FSM.new(self, :open) do
|
11
|
+
transition :from => :open, :to => :close, :if => :can_close?
|
12
|
+
transition :from => :close, :to => :open, :if => :can_open?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
loop do
|
18
|
+
@fsm.advance
|
19
|
+
sleep(0.25)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def start_open
|
24
|
+
puts "Openned door"
|
25
|
+
@counter = 10
|
26
|
+
end
|
27
|
+
|
28
|
+
def while_open
|
29
|
+
@counter -= 1
|
30
|
+
puts @counter.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def can_close?
|
34
|
+
@counter == 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def start_close
|
38
|
+
puts "Closed door"
|
39
|
+
end
|
40
|
+
|
41
|
+
def while_close
|
42
|
+
@counter += 1
|
43
|
+
puts @counter.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def can_open?
|
47
|
+
@counter == 10
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Door.new.run
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
require 'pretty-fsm'
|
3
|
+
|
4
|
+
class Door
|
5
|
+
include PrettyFSM::Abbreviate
|
6
|
+
|
7
|
+
attr_reader(:fsm)
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@fsm = PrettyFSM::FSM.new(self, :open)
|
11
|
+
@close_timer = PrettyFSM::TimedEvent.new(5)
|
12
|
+
@open_timer = PrettyFSM::TimedEvent.new(3)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
loop do
|
17
|
+
@fsm.advance
|
18
|
+
sleep(0.25)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def start_open
|
23
|
+
puts "Openned door, will close on #{@close_timer.duration} seconds"
|
24
|
+
end
|
25
|
+
|
26
|
+
def while_open
|
27
|
+
puts "Waiting to be closed"
|
28
|
+
@close_timer.try { start(:close) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def start_close
|
32
|
+
puts "Closed door, will close on #{@open_timer.duration} seconds"
|
33
|
+
end
|
34
|
+
|
35
|
+
def while_close
|
36
|
+
puts "Waiting to be opened"
|
37
|
+
@close_timer.try { start(:open) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Door.new.run
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module PrettyFSM
|
2
|
+
class FSM
|
3
|
+
# This will be nil if the FSM hasn't made the initial transition yet.
|
4
|
+
attr_reader :state
|
5
|
+
attr_accessor :object
|
6
|
+
|
7
|
+
# _object_ is an instance where all messages regarding transitions and states are sent. States are named with
|
8
|
+
# Symbol instances. The prefixes, are the prefixes to the message names that _object_ will receive (if it responds to them).
|
9
|
+
def initialize(object, initial_state, while_prefix = 'while_', start_prefix = 'start_', end_prefix = 'end_')
|
10
|
+
@object = object
|
11
|
+
@while_prefix,@start_prefix,@end_prefix = while_prefix,start_prefix,end_prefix
|
12
|
+
@initial_state = initial_state
|
13
|
+
@state = nil
|
14
|
+
@transitions = Hash.new {|k,v| []}
|
15
|
+
if (block_given?) then self.instance_eval(&Proc.new) end
|
16
|
+
end
|
17
|
+
|
18
|
+
# This method should be called periodically. It will act as a timestepper.
|
19
|
+
# 'while' methods will be called here.
|
20
|
+
def advance
|
21
|
+
if (@state.nil?) then start(@initial_state) end
|
22
|
+
call_fsm_method(@while_prefix)
|
23
|
+
|
24
|
+
possible_next_state, = @transitions[@state].find {|state,condition| puts state,condition; @object.send(condition)}
|
25
|
+
start(possible_next_state) unless possible_next_state.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Adds a transition definition. Only necessary if you want the FSM to advance itself from a state
|
29
|
+
def transition(options)
|
30
|
+
@transitions[options[:from]].push([ options[:to], options[:if] ])
|
31
|
+
end
|
32
|
+
|
33
|
+
# Transitions the FSM into the specified state, calling the 'end' and 'start' method, of the old and new states, respectively.
|
34
|
+
# Any additional parameter passed to this method will be received by the corresponding 'start' method.
|
35
|
+
def start(new_state, *args)
|
36
|
+
call_fsm_method(@end_prefix) unless @state.nil?
|
37
|
+
@state = new_state
|
38
|
+
call_fsm_method(@start_prefix, args)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def call_fsm_method(prefix, args = [])
|
43
|
+
method_name = (prefix + @state.to_s).to_sym
|
44
|
+
if (@object.respond_to?(method_name)) then @object.send(method_name, *args) end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# You can use this mixin to abbreviate your calls to FSM#start
|
49
|
+
module Abbreviate
|
50
|
+
# calls self.fsm.start
|
51
|
+
def start(new_state, *args)
|
52
|
+
self.fsm.start(new_state, *args)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module FSM
|
2
|
+
# This class is useful to "register" actions to be performed after certain time. You would normally use this
|
3
|
+
# in a FSM state, to switch to another state after a while.
|
4
|
+
# The notion of 'time' (the _now_ and _duration_ parameters) can be arbitrary, it could be any number for example (as long as it makes sense).
|
5
|
+
class TimedEvent
|
6
|
+
attr_accessor :duration
|
7
|
+
|
8
|
+
# Create a TimedEvent that will fire after _duration_ seconds (can be a fractional number) starting from _now_.
|
9
|
+
def initialize(duration)
|
10
|
+
self.reset
|
11
|
+
@duration = duration
|
12
|
+
end
|
13
|
+
|
14
|
+
# Resets the timer, to fire after #duration seconds after _now_
|
15
|
+
def reset(now = Time.now)
|
16
|
+
@time = now
|
17
|
+
end
|
18
|
+
|
19
|
+
# This method should be called periodically with a block. If #duration seconds have passed since last reset, it will
|
20
|
+
# call the passed block.
|
21
|
+
def try(now = Time.now)
|
22
|
+
if ((now - @time) >= @duration)
|
23
|
+
yield
|
24
|
+
self.reset
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/pretty-fsm.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project xmlns="http://www.netbeans.org/ns/project/1">
|
3
|
+
<type>org.netbeans.modules.ruby.rubyproject</type>
|
4
|
+
<configuration>
|
5
|
+
<data xmlns="http://www.netbeans.org/ns/ruby-project/1">
|
6
|
+
<name>fsm</name>
|
7
|
+
<source-roots>
|
8
|
+
<root id="src.lib.dir"/>
|
9
|
+
<root id="src.examples.dir"/>
|
10
|
+
</source-roots>
|
11
|
+
<test-roots/>
|
12
|
+
</data>
|
13
|
+
</configuration>
|
14
|
+
</project>
|
data/pretty-fsm.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{pretty-fsm}
|
5
|
+
s.version = "0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["v01d"]
|
9
|
+
s.date = %q{2010-03-26}
|
10
|
+
s.description = %q{Finite State Machine class with intuitive integration}
|
11
|
+
s.email = %q{}
|
12
|
+
s.extra_rdoc_files = ["README", "lib/pretty-fsm.rb", "lib/pretty-fsm/fsm.rb", "lib/pretty-fsm/timed_event.rb"]
|
13
|
+
s.files = ["Manifest", "README", "Rakefile", "examples/door.rb", "examples/timed_door.rb", "lib/pretty-fsm.rb", "lib/pretty-fsm/fsm.rb", "lib/pretty-fsm/timed_event.rb", "nbproject/project.properties", "nbproject/project.xml", "pretty-fsm.gemspec"]
|
14
|
+
s.homepage = %q{http://github.com/v01d/pretty-fsm}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Pretty-fsm", "--main", "README"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{pretty-fsm}
|
18
|
+
s.rubygems_version = %q{1.3.6}
|
19
|
+
s.summary = %q{Finite State Machine class with intuitive integration}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
else
|
27
|
+
end
|
28
|
+
else
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pretty-fsm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- v01d
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-03-26 00:00:00 -03:00
|
17
|
+
default_executable:
|
18
|
+
dependencies: []
|
19
|
+
|
20
|
+
description: Finite State Machine class with intuitive integration
|
21
|
+
email: ""
|
22
|
+
executables: []
|
23
|
+
|
24
|
+
extensions: []
|
25
|
+
|
26
|
+
extra_rdoc_files:
|
27
|
+
- README
|
28
|
+
- lib/pretty-fsm.rb
|
29
|
+
- lib/pretty-fsm/fsm.rb
|
30
|
+
- lib/pretty-fsm/timed_event.rb
|
31
|
+
files:
|
32
|
+
- Manifest
|
33
|
+
- README
|
34
|
+
- Rakefile
|
35
|
+
- examples/door.rb
|
36
|
+
- examples/timed_door.rb
|
37
|
+
- lib/pretty-fsm.rb
|
38
|
+
- lib/pretty-fsm/fsm.rb
|
39
|
+
- lib/pretty-fsm/timed_event.rb
|
40
|
+
- nbproject/project.properties
|
41
|
+
- nbproject/project.xml
|
42
|
+
- pretty-fsm.gemspec
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/v01d/pretty-fsm
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --line-numbers
|
50
|
+
- --inline-source
|
51
|
+
- --title
|
52
|
+
- Pretty-fsm
|
53
|
+
- --main
|
54
|
+
- README
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 1
|
70
|
+
- 2
|
71
|
+
version: "1.2"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project: pretty-fsm
|
75
|
+
rubygems_version: 1.3.6
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Finite State Machine class with intuitive integration
|
79
|
+
test_files: []
|
80
|
+
|