baby_bots 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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in baby_bots.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012, Justin Hamilton
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ Baby Bots
2
+ =========
3
+
4
+ A small finite-state automata library
5
+ -------------------------------------
6
+
7
+ This is a small finite-state automata library written in Ruby both for a
8
+ project, as well as to teach me how to build gems (I'm not really much of
9
+ a Ruby guy).
10
+
11
+ Let me know of any improviments, thank you!
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/baby_bots.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/baby_bots/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Justin Hamilton"]
6
+ gem.email = ["justinanthonyhamilton@gmail.com"]
7
+ gem.description = %q{A tiny finite-state automata library.}
8
+ gem.summary = %q{While there are many fsa libraries out there, I wanted to implement my own so I could learn how to create a module/gem, as I am not really a Ruby guy and have no idea how.}
9
+ gem.homepage = "https://github.com/jamiltron/BabyBots"
10
+ gem.email = "justinanthonyhamilton@gmail.com"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "baby_bots"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = BabyBots::VERSION
18
+ end
@@ -0,0 +1,98 @@
1
+ module BabyBots
2
+
3
+ class NoSuchStateException < Exception
4
+ end
5
+
6
+ class NoSuchTransitionException < Exception
7
+ end
8
+
9
+ class BabyBot
10
+ attr_accessor :curr, :states, :start
11
+
12
+ def initialize(states={})
13
+ @states = states
14
+ @start = nil
15
+ @curr = nil
16
+ end
17
+
18
+ # add a new state to the state machine
19
+ def add_state(state, start=nil)
20
+ # key on state names to the actual state hash
21
+ @states[state.state] = state
22
+ if start
23
+ @start = state
24
+ @curr = @start
25
+ end
26
+ end
27
+
28
+
29
+ # accepts a hash of hashes consiting of {state => {event => transition, ...} ...}
30
+ # structure, and adds these states to the state machine, assumes first state
31
+ # is the starting state
32
+ def build(table)
33
+ first_state = true
34
+
35
+ # iterate through the provided {state => {event => transition, ...}, ...}
36
+ table.each do |state, state_table|
37
+ temp_state = State.new(state)
38
+
39
+ # iterate through each event and transition, building up the transitions
40
+ state_table.each do |event, transition|
41
+ temp_state.add_transition(event, transition)
42
+ end
43
+
44
+ # finally, add the state to the machine, and since we've already
45
+ # added a start state, clear the first_state flag
46
+ add_state(temp_state, first_state)
47
+ first_state = false
48
+ end
49
+ end
50
+
51
+ # this is the driving function behind the fsa, process
52
+ # will check the current state, doing any processing necessary
53
+ # on the input based on whether or not this
54
+
55
+ def process(event=nil)
56
+ # get the current state
57
+ curr_state = @curr
58
+
59
+ # check if we need to preprocess the event
60
+ if respond_to?("pre_#{@curr.state}")
61
+ event = send("pre_#{@curr.state}", event)
62
+ end
63
+
64
+ next_state = @states[curr.table[event]]
65
+ if next_state.nil?
66
+ next_state = @states[curr.table[:else]]
67
+ end
68
+
69
+ # if the event is nil, and there is no :else clause,
70
+ # throw an exception
71
+ if next_state.nil?
72
+ raise NoSuchTransitionException,
73
+ "No valid transition #{event} for #{@curr.state}"
74
+ end
75
+
76
+ # check if we need to postprocess the event, this will act
77
+ # as the "return" from any state transition (even self-looping transitions)
78
+ if respond_to?("post_#{@curr.state}")
79
+ ret_val = send("post_#{@curr.state}", event)
80
+ end
81
+
82
+
83
+ # actually transition, and make sure such a transition exists
84
+ @curr = next_state
85
+ if @curr.nil?
86
+ raise NoSuchStateException,
87
+ "No valid state #{@curr} for transition #{event} from #{curr_state}"
88
+ end
89
+
90
+ return ret_val
91
+ end
92
+
93
+ def restart
94
+ @curr = @start
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,22 @@
1
+ module BabyBots
2
+
3
+ class State
4
+ attr_reader :state, :table
5
+
6
+ def initialize(state, table={})
7
+ @state = state
8
+ @table = table
9
+ end
10
+
11
+ def add_transition(event, transition, &callback)
12
+ @table[event] = transition
13
+ end
14
+
15
+ # the idea behind build is that you can call multiple
16
+ # :event :transition and the build method
17
+ # will parse them out and add them to state
18
+ def build(*args)
19
+ args.map {|k,v| add_transition(k, v) }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module BabyBots
2
+ VERSION = "0.0.1"
3
+ end
data/lib/baby_bots.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'baby_bots/version'
2
+ require 'baby_bots/baby_bot'
3
+ require 'baby_bots/state'
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: baby_bots
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Justin Hamilton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-30 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: A tiny finite-state automata library.
15
+ email: justinanthonyhamilton@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .gitignore
21
+ - Gemfile
22
+ - LICENSE
23
+ - README.md
24
+ - Rakefile
25
+ - baby_bots.gemspec
26
+ - lib/baby_bots.rb
27
+ - lib/baby_bots/baby_bot.rb
28
+ - lib/baby_bots/state.rb
29
+ - lib/baby_bots/version.rb
30
+ homepage: https://github.com/jamiltron/BabyBots
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 1.8.10
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: While there are many fsa libraries out there, I wanted to implement my own
54
+ so I could learn how to create a module/gem, as I am not really a Ruby guy and have
55
+ no idea how.
56
+ test_files: []