statemachine 0.0.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.
- data/CHANGES +12 -0
 - data/Rakefile +170 -0
 - data/lib/proc_calling.rb +54 -0
 - data/lib/state.rb +69 -0
 - data/lib/state_machine.rb +103 -0
 - data/lib/statemachine.rb +1 -0
 - data/lib/super_state.rb +68 -0
 - data/lib/transition.rb +71 -0
 - data/spec/sm_action_parameterization_spec.rb +114 -0
 - data/spec/sm_entry_exit_actions_spec.rb +49 -0
 - data/spec/sm_odds_n_ends_spec.rb +27 -0
 - data/spec/sm_simple_spec.rb +69 -0
 - data/spec/sm_super_state_spec.rb +80 -0
 - data/spec/sm_turnstile_spec.rb +78 -0
 - data/spec/spec_helper.rb +40 -0
 - data/spec/transition_spec.rb +97 -0
 - metadata +66 -0
 
    
        data/CHANGES
    ADDED
    
    
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,170 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift('lib')
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rake/gempackagetask'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rake/contrib/rubyforgepublisher'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'rake/clean'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'rake/rdoctask'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'spec/rake/spectask'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # Some of the tasks are in separate files since they are also part of the website documentation
         
     | 
| 
      
 10 
     | 
    
         
            +
            "load File.dirname(__FILE__) + '/tasks/examples.rake'
         
     | 
| 
      
 11 
     | 
    
         
            +
            load File.dirname(__FILE__) + '/tasks/examples_specdoc.rake'
         
     | 
| 
      
 12 
     | 
    
         
            +
            load File.dirname(__FILE__) + '/tasks/examples_with_rcov.rake'
         
     | 
| 
      
 13 
     | 
    
         
            +
            load File.dirname(__FILE__) + '/tasks/failing_examples_with_html.rake'
         
     | 
| 
      
 14 
     | 
    
         
            +
            load File.dirname(__FILE__) + '/tasks/verify_rcov.rake'"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            PKG_NAME = "statemachine"
         
     | 
| 
      
 17 
     | 
    
         
            +
            PKG_VERSION   = "0.0.0"
         
     | 
| 
      
 18 
     | 
    
         
            +
            PKG_TAG = "0_0_0"
         
     | 
| 
      
 19 
     | 
    
         
            +
            PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
         
     | 
| 
      
 20 
     | 
    
         
            +
            PKG_FILES = FileList[
         
     | 
| 
      
 21 
     | 
    
         
            +
              '[A-Z]*',
         
     | 
| 
      
 22 
     | 
    
         
            +
              'lib/**/*.rb', 
         
     | 
| 
      
 23 
     | 
    
         
            +
              'spec/**/*.rb' 
         
     | 
| 
      
 24 
     | 
    
         
            +
            #  'examples/**/*',
         
     | 
| 
      
 25 
     | 
    
         
            +
            ]
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            task :default => :spec
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            desc "Run all specs"
         
     | 
| 
      
 30 
     | 
    
         
            +
            Spec::Rake::SpecTask.new do |t|
         
     | 
| 
      
 31 
     | 
    
         
            +
              t.spec_files = FileList['spec/**/*_spec.rb']
         
     | 
| 
      
 32 
     | 
    
         
            +
              t.spec_opts = ['--diff','--color']
         
     | 
| 
      
 33 
     | 
    
         
            +
            #  t.rcov = true
         
     | 
| 
      
 34 
     | 
    
         
            +
            #  t.rcov_dir = 'doc/output/coverage'
         
     | 
| 
      
 35 
     | 
    
         
            +
            #  t.rcov_opts = ['--exclude', 'spec\/spec,bin\/spec']"
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            #desc 'Generate HTML documentation for website'
         
     | 
| 
      
 39 
     | 
    
         
            +
            #task :webgen do
         
     | 
| 
      
 40 
     | 
    
         
            +
            #  Dir.chdir 'doc' do
         
     | 
| 
      
 41 
     | 
    
         
            +
            #    output = nil
         
     | 
| 
      
 42 
     | 
    
         
            +
            #    IO.popen('webgen 2>&1') do |io|
         
     | 
| 
      
 43 
     | 
    
         
            +
            #      output = io.read
         
     | 
| 
      
 44 
     | 
    
         
            +
            #    end
         
     | 
| 
      
 45 
     | 
    
         
            +
            #    raise "ERROR while running webgen: #{output}" if output =~ /ERROR/n || $? != 0
         
     | 
| 
      
 46 
     | 
    
         
            +
            #  end
         
     | 
| 
      
 47 
     | 
    
         
            +
            #end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            #desc 'Generate RDoc'
         
     | 
| 
      
 50 
     | 
    
         
            +
            #rd = Rake::RDocTask.new do |rdoc|
         
     | 
| 
      
 51 
     | 
    
         
            +
            #  rdoc.rdoc_dir = 'doc/output/rdoc'
         
     | 
| 
      
 52 
     | 
    
         
            +
            #  rdoc.options << '--title' << 'RSpec' << '--line-numbers' << '--inline-source' << '--main' << 'README'
         
     | 
| 
      
 53 
     | 
    
         
            +
            #  rdoc.rdoc_files.include('README', 'CHANGES', 'EXAMPLES.rd', 'lib/**/*.rb')
         
     | 
| 
      
 54 
     | 
    
         
            +
            #end
         
     | 
| 
      
 55 
     | 
    
         
            +
            #task :rdoc => :examples_specdoc # We generate EXAMPLES.rd
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            spec = Gem::Specification.new do |s|
         
     | 
| 
      
 58 
     | 
    
         
            +
              s.name = PKG_NAME
         
     | 
| 
      
 59 
     | 
    
         
            +
              s.version = PKG_VERSION
         
     | 
| 
      
 60 
     | 
    
         
            +
              s.summary = Spec::VERSION::DESCRIPTION
         
     | 
| 
      
 61 
     | 
    
         
            +
              s.description = <<-EOF
         
     | 
| 
      
 62 
     | 
    
         
            +
                StateMachine is a ruby library for building Finite State Machines (FSM), also known as Finite State Automata (FSA).
         
     | 
| 
      
 63 
     | 
    
         
            +
              EOF
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              s.files = PKG_FILES.to_a
         
     | 
| 
      
 66 
     | 
    
         
            +
              s.require_path = 'lib'
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            #  s.has_rdoc = true
         
     | 
| 
      
 69 
     | 
    
         
            +
            #  s.rdoc_options = rd.options
         
     | 
| 
      
 70 
     | 
    
         
            +
            #  s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$|^EXAMPLES.rd$/ }.to_a
         
     | 
| 
      
 71 
     | 
    
         
            +
              
         
     | 
| 
      
 72 
     | 
    
         
            +
              s.test_files = Dir.glob('spec/*_spec.rb')
         
     | 
| 
      
 73 
     | 
    
         
            +
              s.require_path = 'lib'
         
     | 
| 
      
 74 
     | 
    
         
            +
              s.autorequire = 'statemachine'
         
     | 
| 
      
 75 
     | 
    
         
            +
            #  s.bindir = "bin"
         
     | 
| 
      
 76 
     | 
    
         
            +
            #  s.executables = ["spec"]
         
     | 
| 
      
 77 
     | 
    
         
            +
            #  s.default_executable = "spec"
         
     | 
| 
      
 78 
     | 
    
         
            +
              s.author = ["Micah Martin"]
         
     | 
| 
      
 79 
     | 
    
         
            +
              s.email = "statemachine-devel@rubyforge.org"
         
     | 
| 
      
 80 
     | 
    
         
            +
              s.homepage = "http://statemachine.rubyforge.org"
         
     | 
| 
      
 81 
     | 
    
         
            +
              s.rubyforge_project = "statemachine"
         
     | 
| 
      
 82 
     | 
    
         
            +
            end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            Rake::GemPackageTask.new(spec) do |pkg|
         
     | 
| 
      
 85 
     | 
    
         
            +
              pkg.need_zip = true
         
     | 
| 
      
 86 
     | 
    
         
            +
              pkg.need_tar = true
         
     | 
| 
      
 87 
     | 
    
         
            +
            end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            def egrep(pattern)
         
     | 
| 
      
 90 
     | 
    
         
            +
              Dir['**/*.rb'].each do |fn|
         
     | 
| 
      
 91 
     | 
    
         
            +
                count = 0
         
     | 
| 
      
 92 
     | 
    
         
            +
                open(fn) do |f|
         
     | 
| 
      
 93 
     | 
    
         
            +
                  while line = f.gets
         
     | 
| 
      
 94 
     | 
    
         
            +
                    count += 1
         
     | 
| 
      
 95 
     | 
    
         
            +
                    if line =~ pattern
         
     | 
| 
      
 96 
     | 
    
         
            +
                      puts "#{fn}:#{count}:#{line}"
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            desc "Look for TODO and FIXME tags in the code"
         
     | 
| 
      
 104 
     | 
    
         
            +
            task :todo do
         
     | 
| 
      
 105 
     | 
    
         
            +
              egrep /(FIXME|TODO|TBD)/
         
     | 
| 
      
 106 
     | 
    
         
            +
            end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            task :clobber do
         
     | 
| 
      
 109 
     | 
    
         
            +
              rm_rf 'doc/output'
         
     | 
| 
      
 110 
     | 
    
         
            +
            end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
            task :release => [:clobber, :verify_committed, :verify_user, :verify_password, :spec, :publish_packages, :tag, :publish_website, :publish_news]
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
            desc "Verifies that there is no uncommitted code"
         
     | 
| 
      
 115 
     | 
    
         
            +
            task :verify_committed do
         
     | 
| 
      
 116 
     | 
    
         
            +
              IO.popen('svn stat') do |io|
         
     | 
| 
      
 117 
     | 
    
         
            +
                io.each_line do |line|
         
     | 
| 
      
 118 
     | 
    
         
            +
                  raise "\n!!! Do a svn commit first !!!\n\n" if line =~ /^\s*M\s*/
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
            end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            desc "Creates a tag in svn"
         
     | 
| 
      
 124 
     | 
    
         
            +
            task :tag do
         
     | 
| 
      
 125 
     | 
    
         
            +
              puts "Creating tag in SVN"
         
     | 
| 
      
 126 
     | 
    
         
            +
              `svn cp svn+ssh://#{ENV['RUBYFORGE_USER']}@rubyforge.org/var/svn/statemachine/trunk svn+ssh://#{ENV['RUBYFORGE_USER']}@rubyforge.org/var/svn/statemachine/tags/#{PKG_VERSION} -m "Tag release #{PKG_TAG}"`
         
     | 
| 
      
 127 
     | 
    
         
            +
              puts "Done!"
         
     | 
| 
      
 128 
     | 
    
         
            +
            end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
            #desc "Build the website, but do not publish it"
         
     | 
| 
      
 132 
     | 
    
         
            +
            #task :website => [:clobber, :verify_rcov, :webgen, :failing_examples_with_html, :spec, :examples_specdoc, :rdoc]
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
            #desc "Upload Website to RubyForge"
         
     | 
| 
      
 135 
     | 
    
         
            +
            #task :publish_website => [:verify_user, :website] do
         
     | 
| 
      
 136 
     | 
    
         
            +
            #  publisher = Rake::SshDirPublisher.new(
         
     | 
| 
      
 137 
     | 
    
         
            +
            #    "rspec-website@rubyforge.org",
         
     | 
| 
      
 138 
     | 
    
         
            +
            #    "/var/www/gforge-projects/#{PKG_NAME}",
         
     | 
| 
      
 139 
     | 
    
         
            +
            #    "doc/output"
         
     | 
| 
      
 140 
     | 
    
         
            +
            #  )
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
            #  publisher.upload
         
     | 
| 
      
 143 
     | 
    
         
            +
            #end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
            task :verify_user do
         
     | 
| 
      
 146 
     | 
    
         
            +
              raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
         
     | 
| 
      
 147 
     | 
    
         
            +
            end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            task :verify_password do
         
     | 
| 
      
 150 
     | 
    
         
            +
              raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
         
     | 
| 
      
 151 
     | 
    
         
            +
            end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
            desc "Publish gem+tgz+zip on RubyForge. You must make sure lib/version.rb is aligned with the CHANGELOG file"
         
     | 
| 
      
 154 
     | 
    
         
            +
            task :publish_packages => [:verify_user, :verify_password, :package] do
         
     | 
| 
      
 155 
     | 
    
         
            +
              require 'meta_project'
         
     | 
| 
      
 156 
     | 
    
         
            +
              require 'rake/contrib/xforge'
         
     | 
| 
      
 157 
     | 
    
         
            +
              release_files = FileList[
         
     | 
| 
      
 158 
     | 
    
         
            +
                "pkg/#{PKG_FILE_NAME}.gem",
         
     | 
| 
      
 159 
     | 
    
         
            +
                "pkg/#{PKG_FILE_NAME}.tgz",
         
     | 
| 
      
 160 
     | 
    
         
            +
                "pkg/#{PKG_FILE_NAME}.zip"
         
     | 
| 
      
 161 
     | 
    
         
            +
              ]
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
              Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new(PKG_NAME)) do |xf|
         
     | 
| 
      
 164 
     | 
    
         
            +
                # Never hardcode user name and password in the Rakefile!
         
     | 
| 
      
 165 
     | 
    
         
            +
                xf.user_name = ENV['RUBYFORGE_USER']
         
     | 
| 
      
 166 
     | 
    
         
            +
                xf.password = ENV['RUBYFORGE_PASSWORD']
         
     | 
| 
      
 167 
     | 
    
         
            +
                xf.files = release_files.to_a
         
     | 
| 
      
 168 
     | 
    
         
            +
                xf.release_name = "StateMachine #{PKG_VERSION}"
         
     | 
| 
      
 169 
     | 
    
         
            +
              end
         
     | 
| 
      
 170 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/proc_calling.rb
    ADDED
    
    | 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module StateMachine
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              module ProcCalling
         
     | 
| 
      
 4 
     | 
    
         
            +
                
         
     | 
| 
      
 5 
     | 
    
         
            +
                private
         
     | 
| 
      
 6 
     | 
    
         
            +
                  
         
     | 
| 
      
 7 
     | 
    
         
            +
                def call_proc(proc, args, message)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  arity = proc.arity
         
     | 
| 
      
 9 
     | 
    
         
            +
                  if should_call_with(arity, 0, args, message)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    proc.call
         
     | 
| 
      
 11 
     | 
    
         
            +
                  elsif should_call_with(arity, 1, args, message)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    proc.call args[0]
         
     | 
| 
      
 13 
     | 
    
         
            +
                  elsif should_call_with(arity, 2, args, message)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    proc.call args[0], args[1]
         
     | 
| 
      
 15 
     | 
    
         
            +
                  elsif should_call_with(arity, 3, args, message)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    proc.call args[0], args[1], args[2]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  elsif should_call_with(arity, 4, args, message)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    proc.call args[0], args[1], args[2], args[3]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  elsif should_call_with(arity, 5, args, message)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    proc.call args[0], args[1], args[2], args[3], args[4]
         
     | 
| 
      
 21 
     | 
    
         
            +
                  elsif should_call_with(arity, 6, args, message)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    proc.call args[0], args[1], args[2], args[3], args[4], args[5]
         
     | 
| 
      
 23 
     | 
    
         
            +
                  elsif should_call_with(arity, 7, args, message)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    proc.call args[0], args[1], args[2], args[3], args[4], args[5], args[6]
         
     | 
| 
      
 25 
     | 
    
         
            +
                  elsif should_call_with(arity, 8, args, message)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    proc.call args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]
         
     | 
| 
      
 27 
     | 
    
         
            +
                  elsif arity < 0 and args and args.length > 8
         
     | 
| 
      
 28 
     | 
    
         
            +
                    proc.call args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]
         
     | 
| 
      
 29 
     | 
    
         
            +
                  else
         
     | 
| 
      
 30 
     | 
    
         
            +
                    raise StateMachineException.new("Too many arguments(#{args.length}). (#{message})")
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                def should_call_with(arity, n, args, message)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  actual = args ? args.length : 0
         
     | 
| 
      
 36 
     | 
    
         
            +
                  if arity == n
         
     | 
| 
      
 37 
     | 
    
         
            +
                    return enough_args?(actual, arity, arity, message)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  elsif arity < 0
         
     | 
| 
      
 39 
     | 
    
         
            +
                    required_args = (arity * -1) - 1
         
     | 
| 
      
 40 
     | 
    
         
            +
                    return (actual == n and enough_args?(actual, required_args, arity, message))
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                def enough_args?(actual, required, arity, message)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  if actual >= required
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 47 
     | 
    
         
            +
                  else
         
     | 
| 
      
 48 
     | 
    
         
            +
                    raise StateMachineException.new("Insufficient parameters. (#{message})")
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
                
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/state.rb
    ADDED
    
    | 
         @@ -0,0 +1,69 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/proc_calling'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module StateMachine
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              class State
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                include ProcCalling
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                attr_reader :id, :statemachine, :entry_action, :exit_action
         
     | 
| 
      
 10 
     | 
    
         
            +
                attr_accessor :superstate
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(id, state_machine)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @id = id
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @statemachine = state_machine
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @transitions = {}
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def add(transition)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @transitions[transition.event] = transition
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              
         
     | 
| 
      
 22 
     | 
    
         
            +
                def transitions
         
     | 
| 
      
 23 
     | 
    
         
            +
                  return @superstate ? @transitions.merge(@superstate.transitions) : @transitions
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def local_transitions
         
     | 
| 
      
 27 
     | 
    
         
            +
                  return @transitions
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def [] (event)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  return transitions[event]
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              
         
     | 
| 
      
 34 
     | 
    
         
            +
                def on_entry action
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @entry_action = action
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              
         
     | 
| 
      
 38 
     | 
    
         
            +
                def on_exit action
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @exit_action = action
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
                
         
     | 
| 
      
 42 
     | 
    
         
            +
                def exit(args)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @statemachine.trace("\texiting #{self}")
         
     | 
| 
      
 44 
     | 
    
         
            +
                  call_proc(@exit_action, args, "exit action for #{self}") if @exit_action
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @superstate.existing(self) if @superstate
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def enter(args)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @statemachine.trace("\tentering #{self}")
         
     | 
| 
      
 50 
     | 
    
         
            +
                  call_proc(@entry_action, args, "entry action for #{self}") if @entry_action
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
                
         
     | 
| 
      
 53 
     | 
    
         
            +
                def is_superstate?
         
     | 
| 
      
 54 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 58 
     | 
    
         
            +
                  return "'#{id}' state"
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def add_substates(*substate_ids)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  raise StateMachineException.new("At least one parameter is required for add_substates.") if substate_ids.length == 0
         
     | 
| 
      
 63 
     | 
    
         
            +
                  replacement = Superstate.new(self, @transitions, substate_ids)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  @statemachine.replace_state(@id, replacement)
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
              
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,103 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/state'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/super_state'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/transition'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/proc_calling'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module StateMachine
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              class StateMachineException < Exception
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              class MissingTransitionException < StateMachineException
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
              
         
     | 
| 
      
 14 
     | 
    
         
            +
              class StateMachine
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                include ProcCalling
         
     | 
| 
      
 17 
     | 
    
         
            +
              
         
     | 
| 
      
 18 
     | 
    
         
            +
                attr_reader :states, :state, :running
         
     | 
| 
      
 19 
     | 
    
         
            +
                attr_accessor :start_state, :tracer
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @states = {}
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @start_state = nil
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @state = nil
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @running = false
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              
         
     | 
| 
      
 28 
     | 
    
         
            +
                def add(origin_id, event, destination_id, action = nil)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  origin = acquire_state(origin_id)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @start_state = origin if @start_state == nil
         
     | 
| 
      
 31 
     | 
    
         
            +
                  destination = acquire_state(destination_id)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  origin.add(Transition.new(origin, destination, event, action))
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              
         
     | 
| 
      
 35 
     | 
    
         
            +
                def run
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @state = @start_state
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @running = true
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
                alias :reset :run
         
     | 
| 
      
 40 
     | 
    
         
            +
              
         
     | 
| 
      
 41 
     | 
    
         
            +
                def [] (state_id)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  return @states[state_id]
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                def state= value
         
     | 
| 
      
 46 
     | 
    
         
            +
                  if @states[value]
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @state = @states[value]
         
     | 
| 
      
 48 
     | 
    
         
            +
                  elsif value and @states[value.to_sym]
         
     | 
| 
      
 49 
     | 
    
         
            +
                    @state = @states[value.to_sym]
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              
         
     | 
| 
      
 53 
     | 
    
         
            +
                def process_event(event, *args)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  trace "Event: #{event}"
         
     | 
| 
      
 55 
     | 
    
         
            +
                  if @state
         
     | 
| 
      
 56 
     | 
    
         
            +
                    transition = @state.transitions[event]
         
     | 
| 
      
 57 
     | 
    
         
            +
                    if transition
         
     | 
| 
      
 58 
     | 
    
         
            +
                      @state = transition.invoke(@state, args)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    else
         
     | 
| 
      
 60 
     | 
    
         
            +
                      raise MissingTransitionException.new("#{@state} does not respond to the '#{event}' event.")
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @running = @state != nil
         
     | 
| 
      
 63 
     | 
    
         
            +
                  else
         
     | 
| 
      
 64 
     | 
    
         
            +
                    raise StateMachineException.new("The state machine isn't in any state.  Did you forget to call run?")
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              
         
     | 
| 
      
 68 
     | 
    
         
            +
                def method_missing(message, *args)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  if @state and @state[message]
         
     | 
| 
      
 70 
     | 
    
         
            +
                    method = self.method(:process_event)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    params = [message.to_sym].concat(args)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    call_proc(method, params, "method_missing")
         
     | 
| 
      
 73 
     | 
    
         
            +
                  else
         
     | 
| 
      
 74 
     | 
    
         
            +
                    super(message, args)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              
         
     | 
| 
      
 78 
     | 
    
         
            +
                def acquire_state(state_id)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  return nil if state_id == nil
         
     | 
| 
      
 80 
     | 
    
         
            +
                  state = @states[state_id]
         
     | 
| 
      
 81 
     | 
    
         
            +
                  if not state
         
     | 
| 
      
 82 
     | 
    
         
            +
                    state = State.new(state_id, self)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    @states[state_id] = state
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  return state
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
                
         
     | 
| 
      
 88 
     | 
    
         
            +
                def replace_state(state_id, replacement_state)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  @states[state_id] = replacement_state
         
     | 
| 
      
 90 
     | 
    
         
            +
                  @states.values.each do |state|
         
     | 
| 
      
 91 
     | 
    
         
            +
                    state.local_transitions.values.each do |transition|
         
     | 
| 
      
 92 
     | 
    
         
            +
                      transition.destination = replacement_state if transition.destination.id == state_id
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
                
         
     | 
| 
      
 97 
     | 
    
         
            +
                def trace(message)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  @tracer.puts message if @tracer
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
              
         
     | 
| 
      
 101 
     | 
    
         
            +
              end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/statemachine.rb
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/state_machine'
         
     | 
    
        data/lib/super_state.rb
    ADDED
    
    | 
         @@ -0,0 +1,68 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module StateMachine
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              class Superstate < State
         
     | 
| 
      
 4 
     | 
    
         
            +
              
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_writer :start_state
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(state, transitions, substate_ids)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @id = state.id
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @statemachine = state.statemachine
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @transitions = transitions
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @entry_action = state.entry_action
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @exit_action = state.exit_action
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @superstate = state.superstate
         
     | 
| 
      
 14 
     | 
    
         
            +
                  do_substate_adding(substate_ids)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                def is_superstate?
         
     | 
| 
      
 18 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
                
         
     | 
| 
      
 21 
     | 
    
         
            +
                def start_state
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if @use_history and @history_state
         
     | 
| 
      
 23 
     | 
    
         
            +
                    return @history_state
         
     | 
| 
      
 24 
     | 
    
         
            +
                  else
         
     | 
| 
      
 25 
     | 
    
         
            +
                    return @start_state
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
                
         
     | 
| 
      
 29 
     | 
    
         
            +
                def existing(substate)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @history_state = substate
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              
         
     | 
| 
      
 33 
     | 
    
         
            +
                def add_substates(*substate_ids)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  do_substate_adding(substate_ids)
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                
         
     | 
| 
      
 37 
     | 
    
         
            +
                def use_history
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @use_history = true;
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 42 
     | 
    
         
            +
                  return "'#{id}' superstate"
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                private
         
     | 
| 
      
 46 
     | 
    
         
            +
              
         
     | 
| 
      
 47 
     | 
    
         
            +
                def do_substate_adding(substate_ids)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  substate_ids.each do |substate_id|
         
     | 
| 
      
 49 
     | 
    
         
            +
                    substate = @statemachine.acquire_state(substate_id)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @start_state = substate if not @start_state
         
     | 
| 
      
 51 
     | 
    
         
            +
                    substate.superstate = self
         
     | 
| 
      
 52 
     | 
    
         
            +
                    check_for_substate_recursion
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
              
         
     | 
| 
      
 56 
     | 
    
         
            +
                def check_for_substate_recursion
         
     | 
| 
      
 57 
     | 
    
         
            +
                  tmp_state = @superstate
         
     | 
| 
      
 58 
     | 
    
         
            +
                  while tmp_state
         
     | 
| 
      
 59 
     | 
    
         
            +
                    if tmp_state == self
         
     | 
| 
      
 60 
     | 
    
         
            +
                      raise StateMachineException.new("Cyclic substates not allowed. (#{id})")
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end 
         
     | 
| 
      
 62 
     | 
    
         
            +
                    tmp_state = tmp_state.superstate
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/transition.rb
    ADDED
    
    | 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/proc_calling'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module StateMachine
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              class Transition
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                include ProcCalling
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                attr_reader :origin, :event, :action
         
     | 
| 
      
 10 
     | 
    
         
            +
                attr_accessor :destination
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(origin, destination, event, action)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @origin = origin
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @destination = destination
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @event = event
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @action = action
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                def invoke(origin, args)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  exits, entries = exits_and_entries(origin)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  exits.each { |exited_state| exited_state.exit(args) }
         
     | 
| 
      
 22 
     | 
    
         
            +
                  
         
     | 
| 
      
 23 
     | 
    
         
            +
                  call_proc(@action, args, "transition action from #{origin} invoked by '#{event}' event") if @action
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  entries.each { |entered_state| entered_state.enter(args) }
         
     | 
| 
      
 26 
     | 
    
         
            +
                  
         
     | 
| 
      
 27 
     | 
    
         
            +
                  terminal_state = @destination
         
     | 
| 
      
 28 
     | 
    
         
            +
                  while terminal_state and terminal_state.is_superstate?
         
     | 
| 
      
 29 
     | 
    
         
            +
                    terminal_state = terminal_state.start_state
         
     | 
| 
      
 30 
     | 
    
         
            +
                    terminal_state.enter(args)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  
         
     | 
| 
      
 33 
     | 
    
         
            +
                  return terminal_state
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
                
         
     | 
| 
      
 36 
     | 
    
         
            +
                def exits_and_entries(origin)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  exits = []
         
     | 
| 
      
 38 
     | 
    
         
            +
                  entries = exits_and_entries_helper(exits, origin)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  
         
     | 
| 
      
 40 
     | 
    
         
            +
                  return exits, entries.reverse
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              
         
     | 
| 
      
 43 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 44 
     | 
    
         
            +
                  return "#{origin.id} ---#{event}---> #{destination.id} : #{action}"
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                private
         
     | 
| 
      
 48 
     | 
    
         
            +
                
         
     | 
| 
      
 49 
     | 
    
         
            +
                def exits_and_entries_helper(exits, exit_state)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  entries = entries_to_destination(exit_state)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  return entries if entries
         
     | 
| 
      
 52 
     | 
    
         
            +
                  return [] if exit_state == nil
         
     | 
| 
      
 53 
     | 
    
         
            +
                  
         
     | 
| 
      
 54 
     | 
    
         
            +
                  exits << exit_state
         
     | 
| 
      
 55 
     | 
    
         
            +
                  exits_and_entries_helper(exits, exit_state.superstate)
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
                
         
     | 
| 
      
 58 
     | 
    
         
            +
                def entries_to_destination(exit_state)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  entries = []
         
     | 
| 
      
 60 
     | 
    
         
            +
                  state = @destination
         
     | 
| 
      
 61 
     | 
    
         
            +
                  while state    
         
     | 
| 
      
 62 
     | 
    
         
            +
                    entries << state
         
     | 
| 
      
 63 
     | 
    
         
            +
                    return entries if exit_state == state.superstate
         
     | 
| 
      
 64 
     | 
    
         
            +
                    state = state.superstate
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                  return nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
                
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
              
         
     | 
| 
      
 71 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,114 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "State Machine Odds And Ends" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              include SwitchStateMachine
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 7 
     | 
    
         
            +
                create_switch
         
     | 
| 
      
 8 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              specify "action with one parameter" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |value| @status = value } )
         
     | 
| 
      
 13 
     | 
    
         
            +
                @sm.set "blue"
         
     | 
| 
      
 14 
     | 
    
         
            +
                @status.should_equal "blue"
         
     | 
| 
      
 15 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              specify "action with two parameters" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b| @status = [a, b].join(",") } )
         
     | 
| 
      
 20 
     | 
    
         
            +
                @sm.set "blue", "green"
         
     | 
| 
      
 21 
     | 
    
         
            +
                @status.should_equal "blue,green"
         
     | 
| 
      
 22 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              specify "action with three parameters" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } )
         
     | 
| 
      
 27 
     | 
    
         
            +
                @sm.set "blue", "green", "red"
         
     | 
| 
      
 28 
     | 
    
         
            +
                @status.should_equal "blue,green,red"
         
     | 
| 
      
 29 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              specify "action with four parameters" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c, d| @status = [a, b, c, d].join(",") } )
         
     | 
| 
      
 34 
     | 
    
         
            +
                @sm.set "blue", "green", "red", "orange"
         
     | 
| 
      
 35 
     | 
    
         
            +
                @status.should_equal "blue,green,red,orange"
         
     | 
| 
      
 36 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              specify "action with five parameters" do
         
     | 
| 
      
 40 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c, d, e| @status = [a, b, c, d, e].join(",") } )
         
     | 
| 
      
 41 
     | 
    
         
            +
                @sm.set "blue", "green", "red", "orange", "yellow"
         
     | 
| 
      
 42 
     | 
    
         
            +
                @status.should_equal "blue,green,red,orange,yellow"
         
     | 
| 
      
 43 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
              
         
     | 
| 
      
 46 
     | 
    
         
            +
              specify "action with six parameters" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c, d, e, f| @status = [a, b, c, d, e, f].join(",") } )
         
     | 
| 
      
 48 
     | 
    
         
            +
                @sm.set "blue", "green", "red", "orange", "yellow", "indigo"
         
     | 
| 
      
 49 
     | 
    
         
            +
                @status.should_equal "blue,green,red,orange,yellow,indigo"
         
     | 
| 
      
 50 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              specify "action with seven parameters" do
         
     | 
| 
      
 54 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c, d, e, f, g| @status = [a, b, c, d, e, f, g].join(",") } )
         
     | 
| 
      
 55 
     | 
    
         
            +
                @sm.set "blue", "green", "red", "orange", "yellow", "indigo", "violet"
         
     | 
| 
      
 56 
     | 
    
         
            +
                @status.should_equal "blue,green,red,orange,yellow,indigo,violet"
         
     | 
| 
      
 57 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              specify "action with eight parameters" do
         
     | 
| 
      
 61 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c, d, e, f, g, h| @status = [a, b, c, d, e, f, g, h].join(",") } )
         
     | 
| 
      
 62 
     | 
    
         
            +
                @sm.set "blue", "green", "red", "orange", "yellow", "indigo", "violet", "ultra-violet"
         
     | 
| 
      
 63 
     | 
    
         
            +
                @status.should_equal "blue,green,red,orange,yellow,indigo,violet,ultra-violet"
         
     | 
| 
      
 64 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
              
         
     | 
| 
      
 67 
     | 
    
         
            +
              specify "To many parameters" do
         
     | 
| 
      
 68 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c, d, e, f, g, h, i| @status = [a, b, c, d, e, f, g, h, i].join(",") } )
         
     | 
| 
      
 69 
     | 
    
         
            +
                begin
         
     | 
| 
      
 70 
     | 
    
         
            +
                  @sm.process_event(:set, "blue", "green", "red", "orange", "yellow", "indigo", "violet", "ultra-violet", "Yikes!")
         
     | 
| 
      
 71 
     | 
    
         
            +
                rescue StateMachine::StateMachineException => e
         
     | 
| 
      
 72 
     | 
    
         
            +
                  e.message.should_equal "Too many arguments(9). (transition action from 'off' state invoked by 'set' event)"
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
              
         
     | 
| 
      
 76 
     | 
    
         
            +
              specify "calling process_event with parameters" do
         
     | 
| 
      
 77 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } )
         
     | 
| 
      
 78 
     | 
    
         
            +
                @sm.process_event(:set, "blue", "green", "red")
         
     | 
| 
      
 79 
     | 
    
         
            +
                @status.should_equal "blue,green,red"
         
     | 
| 
      
 80 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              specify "Insufficient params" do
         
     | 
| 
      
 84 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } )
         
     | 
| 
      
 85 
     | 
    
         
            +
                begin
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @sm.set "blue", "green"
         
     | 
| 
      
 87 
     | 
    
         
            +
                rescue StateMachine::StateMachineException => e
         
     | 
| 
      
 88 
     | 
    
         
            +
                  e.message.should_equal "Insufficient parameters. (transition action from 'off' state invoked by 'set' event)"
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
              
         
     | 
| 
      
 92 
     | 
    
         
            +
              specify "infinate args" do
         
     | 
| 
      
 93 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |*a| @status = a.join(",") } )
         
     | 
| 
      
 94 
     | 
    
         
            +
                @sm.set(1, 2, 3)
         
     | 
| 
      
 95 
     | 
    
         
            +
                @status.should_equal "1,2,3"
         
     | 
| 
      
 96 
     | 
    
         
            +
                
         
     | 
| 
      
 97 
     | 
    
         
            +
                @sm.state = :off
         
     | 
| 
      
 98 
     | 
    
         
            +
                @sm.set(1, 2, 3, 4, 5, 6)
         
     | 
| 
      
 99 
     | 
    
         
            +
                @status.should_equal "1,2,3,4,5,6"
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
              
         
     | 
| 
      
 102 
     | 
    
         
            +
              specify "Insufficient params when params are infinate" do
         
     | 
| 
      
 103 
     | 
    
         
            +
                @sm.add(:off, :set, :on, Proc.new { |a, *b| @status = a.to_s + ":" + b.join(",") } )
         
     | 
| 
      
 104 
     | 
    
         
            +
                @sm.set(1, 2, 3)
         
     | 
| 
      
 105 
     | 
    
         
            +
                @status.should_equal "1:2,3"
         
     | 
| 
      
 106 
     | 
    
         
            +
                
         
     | 
| 
      
 107 
     | 
    
         
            +
                @sm.state = :off
         
     | 
| 
      
 108 
     | 
    
         
            +
                begin
         
     | 
| 
      
 109 
     | 
    
         
            +
                  @sm.set
         
     | 
| 
      
 110 
     | 
    
         
            +
                rescue StateMachine::StateMachineException => e
         
     | 
| 
      
 111 
     | 
    
         
            +
                  e.message.should_equal "Insufficient parameters. (transition action from 'off' state invoked by 'set' event)"
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
              end
         
     | 
| 
      
 114 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "State Machine Entry and Exit Actions" do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 6 
     | 
    
         
            +
                @log = []
         
     | 
| 
      
 7 
     | 
    
         
            +
                @sm = StateMachine::StateMachine.new
         
     | 
| 
      
 8 
     | 
    
         
            +
                @sm.add(:off, :toggle, :on, Proc.new { @log << "on" } )
         
     | 
| 
      
 9 
     | 
    
         
            +
                @sm.add(:on, :toggle, :off, Proc.new { @log << "off" } )
         
     | 
| 
      
 10 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              specify "entry action" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                @sm[:on].on_entry Proc.new { @log << "entered_on" }
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                @sm.toggle
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                @log.join(",").should_equal "on,entered_on"
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              specify "exit action" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                @sm[:off].on_exit Proc.new { @log << "exited_off" }
         
     | 
| 
      
 23 
     | 
    
         
            +
                
         
     | 
| 
      
 24 
     | 
    
         
            +
                @sm.toggle
         
     | 
| 
      
 25 
     | 
    
         
            +
                
         
     | 
| 
      
 26 
     | 
    
         
            +
                @log.join(",").should_equal "exited_off,on"
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              specify "exit and entry" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                @sm[:off].on_exit Proc.new { @log << "exited_off" }
         
     | 
| 
      
 31 
     | 
    
         
            +
                @sm[:on].on_entry Proc.new { @log << "entered_on" }
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                @sm.toggle
         
     | 
| 
      
 34 
     | 
    
         
            +
                
         
     | 
| 
      
 35 
     | 
    
         
            +
                @log.join(",").should_equal "exited_off,on,entered_on"
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
              
         
     | 
| 
      
 38 
     | 
    
         
            +
              specify "entry and exit actions may be parameterized" do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @sm[:off].on_exit Proc.new { |a| @log << "exited_off(#{a})" }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @sm[:on].on_entry Proc.new { |a, b| @log << "entered_on(#{a},#{b})" }
         
     | 
| 
      
 41 
     | 
    
         
            +
                  
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @sm.toggle "one", "two"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @log.join(",").should_equal "exited_off(one),on,entered_on(one,two)"
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "State Machine Odds And Ends" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              include SwitchStateMachine
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 7 
     | 
    
         
            +
                create_switch
         
     | 
| 
      
 8 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              specify "method missing delegates to super in case of no event" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                lambda { @sm.blah }.should_raise NoMethodError
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
              
         
     | 
| 
      
 15 
     | 
    
         
            +
              specify "set state with string" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                @sm.state.id.should_be :off
         
     | 
| 
      
 17 
     | 
    
         
            +
                @sm.state = "on"
         
     | 
| 
      
 18 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              specify "set state with symbol" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                @sm.state.id.should_be :off
         
     | 
| 
      
 23 
     | 
    
         
            +
                @sm.state = :on
         
     | 
| 
      
 24 
     | 
    
         
            +
                @sm.state.id.should_be :on
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,69 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "simple cases:" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 5 
     | 
    
         
            +
                @sm = StateMachine::StateMachine.new
         
     | 
| 
      
 6 
     | 
    
         
            +
                @count = 0
         
     | 
| 
      
 7 
     | 
    
         
            +
                @proc = Proc.new {@count = @count + 1}
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              specify "one transition has states" do
         
     | 
| 
      
 11 
     | 
    
         
            +
                @sm.add(:on, :flip, :off, @proc)
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                @sm.states.length.should_be 2
         
     | 
| 
      
 14 
     | 
    
         
            +
                @sm[:on].should_not_be nil
         
     | 
| 
      
 15 
     | 
    
         
            +
                @sm[:off].should_not_be nil
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
              specify "one trasition create connects states with transition" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                @sm.add(:on, :flip, :off, @proc)
         
     | 
| 
      
 20 
     | 
    
         
            +
                origin = @sm[:on]
         
     | 
| 
      
 21 
     | 
    
         
            +
                destination = @sm[:off]
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                origin.transitions.length.should_be 1
         
     | 
| 
      
 24 
     | 
    
         
            +
                destination.transitions.length.should_be 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                transition = origin[:flip]
         
     | 
| 
      
 26 
     | 
    
         
            +
                check_transition(transition, :on, :off, :flip, @proc)
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              specify "end state" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                @sm.add(:start, :blah, nil, @proc)
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 33 
     | 
    
         
            +
                @sm.running.should.be true
         
     | 
| 
      
 34 
     | 
    
         
            +
                @sm.process_event(:blah)
         
     | 
| 
      
 35 
     | 
    
         
            +
                @sm.state.should.be nil
         
     | 
| 
      
 36 
     | 
    
         
            +
                @sm.running.should.be false;
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              specify "reset" do
         
     | 
| 
      
 40 
     | 
    
         
            +
                @sm.add(:start, :blah, nil, @proc)
         
     | 
| 
      
 41 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 42 
     | 
    
         
            +
                @sm.process_event(:blah)
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                @sm.reset
         
     | 
| 
      
 45 
     | 
    
         
            +
                
         
     | 
| 
      
 46 
     | 
    
         
            +
                @sm.state.should.be @sm[:start]
         
     | 
| 
      
 47 
     | 
    
         
            +
                @sm.running.should.be true
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
              
         
     | 
| 
      
 50 
     | 
    
         
            +
              specify "exception when state machine is not running" do
         
     | 
| 
      
 51 
     | 
    
         
            +
                @sm.add(:on, :flip, :off)
         
     | 
| 
      
 52 
     | 
    
         
            +
                
         
     | 
| 
      
 53 
     | 
    
         
            +
                begin
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @sm.process_event(:flip)
         
     | 
| 
      
 55 
     | 
    
         
            +
                rescue StateMachine::StateMachineException => e
         
     | 
| 
      
 56 
     | 
    
         
            +
                  e.message.should_equal "The state machine isn't in any state.  Did you forget to call run?"
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              specify "no proc in transition" do
         
     | 
| 
      
 61 
     | 
    
         
            +
                @sm.add(:on, :flip, :off)
         
     | 
| 
      
 62 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 63 
     | 
    
         
            +
                
         
     | 
| 
      
 64 
     | 
    
         
            +
                @sm.flip
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              
         
     | 
| 
      
 68 
     | 
    
         
            +
              
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,80 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "Turn Stile" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              include TurnstileStateMachine
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 7 
     | 
    
         
            +
                create_turnstile
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                @out_out_order = false
         
     | 
| 
      
 10 
     | 
    
         
            +
                @sm.add(:operative, :maintain, :maintenance, Proc.new { @out_of_order = true } )
         
     | 
| 
      
 11 
     | 
    
         
            +
                @sm.add(:maintenance, :operate, :operative, Proc.new { @out_of_order = false } )
         
     | 
| 
      
 12 
     | 
    
         
            +
                @sm[:operative].add_substates(:locked, :unlocked)
         
     | 
| 
      
 13 
     | 
    
         
            +
                
         
     | 
| 
      
 14 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              specify "substates respond to superstate transitions" do
         
     | 
| 
      
 18 
     | 
    
         
            +
                @sm.process_event(:maintain)
         
     | 
| 
      
 19 
     | 
    
         
            +
                @sm.state.id.should_be :maintenance
         
     | 
| 
      
 20 
     | 
    
         
            +
                @locked.should_be true
         
     | 
| 
      
 21 
     | 
    
         
            +
                @out_of_order.should_be true
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              specify "after transitions, substates respond to superstate transitions" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                @sm.coin
         
     | 
| 
      
 26 
     | 
    
         
            +
                @sm.maintain
         
     | 
| 
      
 27 
     | 
    
         
            +
                @sm.state.id.should_be :maintenance
         
     | 
| 
      
 28 
     | 
    
         
            +
                @locked.should_be false
         
     | 
| 
      
 29 
     | 
    
         
            +
                @out_of_order.should_be true
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
              
         
     | 
| 
      
 32 
     | 
    
         
            +
              specify "transitions back to superstate go to history state" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                @sm[:operative].use_history
         
     | 
| 
      
 34 
     | 
    
         
            +
                @sm.maintain
         
     | 
| 
      
 35 
     | 
    
         
            +
                @sm.operate
         
     | 
| 
      
 36 
     | 
    
         
            +
                @sm.state.id.should_be :locked
         
     | 
| 
      
 37 
     | 
    
         
            +
                @out_of_order.should_be false
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                @sm.coin
         
     | 
| 
      
 40 
     | 
    
         
            +
                @sm.maintain
         
     | 
| 
      
 41 
     | 
    
         
            +
                @sm.operate
         
     | 
| 
      
 42 
     | 
    
         
            +
                @sm.state.id.should_be :unlocked
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
              
         
     | 
| 
      
 45 
     | 
    
         
            +
              specify "missing substates are added" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                @sm[:operative].add_substates(:blah)
         
     | 
| 
      
 47 
     | 
    
         
            +
                @sm[:blah].should_not_be nil
         
     | 
| 
      
 48 
     | 
    
         
            +
                @sm[:blah].superstate.id.should_be :operative
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              specify "recursive superstates not allowed" do
         
     | 
| 
      
 52 
     | 
    
         
            +
                begin
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @sm[:operative].add_substates(:operative)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  self.should_fail_with_message("exception expected")
         
     | 
| 
      
 55 
     | 
    
         
            +
                rescue StateMachine::StateMachineException => e
         
     | 
| 
      
 56 
     | 
    
         
            +
                  e.message.should_equal "Cyclic substates not allowed. (operative)"
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              specify "recursive superstates (2 levels) not allowed" do
         
     | 
| 
      
 61 
     | 
    
         
            +
                begin
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @sm[:operative].add_substates(:blah)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @sm[:blah].add_substates(:operative)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  self.should_fail_with_message("exception expected")
         
     | 
| 
      
 65 
     | 
    
         
            +
                rescue StateMachine::StateMachineException => e
         
     | 
| 
      
 66 
     | 
    
         
            +
                  e.message.should_equal "Cyclic substates not allowed. (blah)"
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
              
         
     | 
| 
      
 70 
     | 
    
         
            +
              specify "exception when add_substates called without args" do
         
     | 
| 
      
 71 
     | 
    
         
            +
                begin
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @sm[:locked].add_substates()
         
     | 
| 
      
 73 
     | 
    
         
            +
                  self.should_fail_with_message("exception expected")
         
     | 
| 
      
 74 
     | 
    
         
            +
                rescue StateMachine::StateMachineException => e
         
     | 
| 
      
 75 
     | 
    
         
            +
                  e.message.should_equal "At least one parameter is required for add_substates."
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
              
         
     | 
| 
      
 79 
     | 
    
         
            +
              
         
     | 
| 
      
 80 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "Turn Stile" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              include TurnstileStateMachine
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 7 
     | 
    
         
            +
                create_turnstile
         
     | 
| 
      
 8 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              specify "connections" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                @sm.states.length.should_be 2
         
     | 
| 
      
 13 
     | 
    
         
            +
                locked_state = @sm[:locked]
         
     | 
| 
      
 14 
     | 
    
         
            +
                unlocked_state = @sm[:unlocked]
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                locked_state.transitions.length.should_be 2
         
     | 
| 
      
 17 
     | 
    
         
            +
                unlocked_state.transitions.length.should_be 2
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                check_transition(locked_state[:coin], :locked, :unlocked, :coin, @unlock)
         
     | 
| 
      
 20 
     | 
    
         
            +
                check_transition(locked_state[:pass], :locked, :locked, :pass, @alarm)
         
     | 
| 
      
 21 
     | 
    
         
            +
                check_transition(unlocked_state[:pass], :unlocked, :locked, :pass, @lock)
         
     | 
| 
      
 22 
     | 
    
         
            +
                check_transition(unlocked_state[:coin], :unlocked, :locked, :coin, @thankyou)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              specify "start state" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                @sm.run
         
     | 
| 
      
 27 
     | 
    
         
            +
                @sm.start_state.should.be @sm[:locked]
         
     | 
| 
      
 28 
     | 
    
         
            +
                @sm.state.should.be @sm[:locked]
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
              
         
     | 
| 
      
 31 
     | 
    
         
            +
              specify "bad event" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                begin
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @sm.process_event(:blah)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  self.should.fail_with_message("Exception expected")
         
     | 
| 
      
 35 
     | 
    
         
            +
                rescue Exception => e
         
     | 
| 
      
 36 
     | 
    
         
            +
                  e.class.should.be StateMachine::MissingTransitionException
         
     | 
| 
      
 37 
     | 
    
         
            +
                  e.to_s.should_equal "'locked' state does not respond to the 'blah' event."
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
              
         
     | 
| 
      
 41 
     | 
    
         
            +
              specify "locked state with a coin" do
         
     | 
| 
      
 42 
     | 
    
         
            +
                @sm.process_event(:coin)
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                @sm.state.should.be @sm[:unlocked]
         
     | 
| 
      
 45 
     | 
    
         
            +
                @locked.should.be false
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              specify "locked state with pass event" do
         
     | 
| 
      
 49 
     | 
    
         
            +
                @sm.process_event(:pass)
         
     | 
| 
      
 50 
     | 
    
         
            +
                
         
     | 
| 
      
 51 
     | 
    
         
            +
                @sm.state.should.be @sm[:locked]
         
     | 
| 
      
 52 
     | 
    
         
            +
                @locked.should.be true
         
     | 
| 
      
 53 
     | 
    
         
            +
                @alarm.should.be true
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              specify "unlocked state with coin" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                @sm.process_event(:coin)
         
     | 
| 
      
 58 
     | 
    
         
            +
                @sm.process_event(:coin)
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                @sm.state.should.be @sm[:locked]
         
     | 
| 
      
 61 
     | 
    
         
            +
                @thankyou_status.should.be true
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              specify "unlocked state with pass event" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                @sm.process_event(:coin)
         
     | 
| 
      
 66 
     | 
    
         
            +
                @sm.process_event(:pass)
         
     | 
| 
      
 67 
     | 
    
         
            +
                
         
     | 
| 
      
 68 
     | 
    
         
            +
                @sm.state.should.be @sm[:locked]
         
     | 
| 
      
 69 
     | 
    
         
            +
                @locked.should.be true
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              specify "events invoked via method_missing" do
         
     | 
| 
      
 73 
     | 
    
         
            +
                @sm.coin
         
     | 
| 
      
 74 
     | 
    
         
            +
                @sm.state.should.be @sm[:unlocked]
         
     | 
| 
      
 75 
     | 
    
         
            +
                @sm.pass
         
     | 
| 
      
 76 
     | 
    
         
            +
                @sm.state.should.be @sm[:locked]
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/../lib/state_machine'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            def check_transition(transition, origin_id, destination_id, event, action)
         
     | 
| 
      
 4 
     | 
    
         
            +
              transition.should_not_be nil
         
     | 
| 
      
 5 
     | 
    
         
            +
              transition.event.should_be event
         
     | 
| 
      
 6 
     | 
    
         
            +
              transition.action.should_be action
         
     | 
| 
      
 7 
     | 
    
         
            +
              transition.origin.id.should_be origin_id
         
     | 
| 
      
 8 
     | 
    
         
            +
              transition.destination.id.should_be destination_id
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module SwitchStateMachine
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
              def create_switch
         
     | 
| 
      
 14 
     | 
    
         
            +
                @status = "off"
         
     | 
| 
      
 15 
     | 
    
         
            +
                @sm = StateMachine::StateMachine.new
         
     | 
| 
      
 16 
     | 
    
         
            +
                @sm.add(:off, :toggle, :on, Proc.new { @status = "on" } )
         
     | 
| 
      
 17 
     | 
    
         
            +
                @sm.add(:on, :toggle, :off, Proc.new { @status = "off" } )
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
              
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            module TurnstileStateMachine
         
     | 
| 
      
 23 
     | 
    
         
            +
              
         
     | 
| 
      
 24 
     | 
    
         
            +
              def create_turnstile
         
     | 
| 
      
 25 
     | 
    
         
            +
                @locked = true
         
     | 
| 
      
 26 
     | 
    
         
            +
                @alarm_status = false
         
     | 
| 
      
 27 
     | 
    
         
            +
                @thankyou_status = false
         
     | 
| 
      
 28 
     | 
    
         
            +
                @lock = Proc.new { @locked = true }
         
     | 
| 
      
 29 
     | 
    
         
            +
                @unlock = Proc.new { @locked = false }
         
     | 
| 
      
 30 
     | 
    
         
            +
                @alarm = Proc.new { @alarm_status = true }
         
     | 
| 
      
 31 
     | 
    
         
            +
                @thankyou = Proc.new { @thankyou_status = true }
         
     | 
| 
      
 32 
     | 
    
         
            +
              
         
     | 
| 
      
 33 
     | 
    
         
            +
                @sm = StateMachine::StateMachine.new
         
     | 
| 
      
 34 
     | 
    
         
            +
                @sm.add(:locked, :coin, :unlocked, @unlock)
         
     | 
| 
      
 35 
     | 
    
         
            +
                @sm.add(:unlocked, :pass, :locked, @lock)
         
     | 
| 
      
 36 
     | 
    
         
            +
                @sm.add(:locked, :pass, :locked, @alarm)
         
     | 
| 
      
 37 
     | 
    
         
            +
                @sm.add(:unlocked, :coin, :locked, @thankyou)
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
              
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,97 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/../lib/state_machine'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            context "Transition Calculating Exits and Entries" do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 6 
     | 
    
         
            +
                @a = StateMachine::State.new("a", nil)
         
     | 
| 
      
 7 
     | 
    
         
            +
                @b = StateMachine::State.new("b", nil)
         
     | 
| 
      
 8 
     | 
    
         
            +
                @c = StateMachine::State.new("c", nil)
         
     | 
| 
      
 9 
     | 
    
         
            +
                @d = StateMachine::State.new("d", nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                @e = StateMachine::State.new("e", nil)
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
              specify "to nil" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, nil, nil, nil)
         
     | 
| 
      
 15 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 16 
     | 
    
         
            +
                exits.to_s.should_equal [@a].to_s
         
     | 
| 
      
 17 
     | 
    
         
            +
                entries.to_s.should_equal [].to_s
         
     | 
| 
      
 18 
     | 
    
         
            +
                entries.length.should_be 0
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              specify "to itself" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @a, nil, nil)
         
     | 
| 
      
 23 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 24 
     | 
    
         
            +
                exits.to_s.should_equal [@a].to_s
         
     | 
| 
      
 25 
     | 
    
         
            +
                entries.to_s.should_equal [@a].to_s
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              specify "to friend" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @b, nil, nil)
         
     | 
| 
      
 30 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 31 
     | 
    
         
            +
                exits.to_s.should_equal [@a].to_s
         
     | 
| 
      
 32 
     | 
    
         
            +
                entries.to_s.should_equal [@b].to_s
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              specify "to parent" do
         
     | 
| 
      
 36 
     | 
    
         
            +
                @a.superstate = @b
         
     | 
| 
      
 37 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @b, nil, nil)
         
     | 
| 
      
 38 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 39 
     | 
    
         
            +
                exits.to_s.should_equal [@a, @b].to_s
         
     | 
| 
      
 40 
     | 
    
         
            +
                entries.to_s.should_equal [@b].to_s
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              specify "to uncle" do
         
     | 
| 
      
 44 
     | 
    
         
            +
                @a.superstate = @b
         
     | 
| 
      
 45 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @c, nil, nil)
         
     | 
| 
      
 46 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 47 
     | 
    
         
            +
                exits.to_s.should_equal [@a, @b].to_s
         
     | 
| 
      
 48 
     | 
    
         
            +
                entries.to_s.should_equal [@c].to_s
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              specify "to cousin" do
         
     | 
| 
      
 52 
     | 
    
         
            +
                @a.superstate = @b
         
     | 
| 
      
 53 
     | 
    
         
            +
                @c.superstate = @d
         
     | 
| 
      
 54 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @c, nil, nil)
         
     | 
| 
      
 55 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 56 
     | 
    
         
            +
                exits.to_s.should_equal [@a, @b].to_s
         
     | 
| 
      
 57 
     | 
    
         
            +
                entries.to_s.should_equal [@d, @c].to_s
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
              
         
     | 
| 
      
 60 
     | 
    
         
            +
              specify "to nephew" do
         
     | 
| 
      
 61 
     | 
    
         
            +
                @a.superstate = @b
         
     | 
| 
      
 62 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@c, @a, nil, nil)
         
     | 
| 
      
 63 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@c)
         
     | 
| 
      
 64 
     | 
    
         
            +
                exits.to_s.should_equal [@c].to_s
         
     | 
| 
      
 65 
     | 
    
         
            +
                entries.to_s.should_equal [@b,@a].to_s
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              specify "to sister" do
         
     | 
| 
      
 69 
     | 
    
         
            +
                @a.superstate = @c
         
     | 
| 
      
 70 
     | 
    
         
            +
                @b.superstate = @c
         
     | 
| 
      
 71 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @b, nil, nil)
         
     | 
| 
      
 72 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 73 
     | 
    
         
            +
                exits.to_s.should_equal [@a].to_s
         
     | 
| 
      
 74 
     | 
    
         
            +
                entries.to_s.should_equal [@b].to_s
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
              
         
     | 
| 
      
 77 
     | 
    
         
            +
              specify "to second cousin" do
         
     | 
| 
      
 78 
     | 
    
         
            +
                @a.superstate = @b
         
     | 
| 
      
 79 
     | 
    
         
            +
                @b.superstate = @c
         
     | 
| 
      
 80 
     | 
    
         
            +
                @d.superstate = @e
         
     | 
| 
      
 81 
     | 
    
         
            +
                @e.superstate = @c
         
     | 
| 
      
 82 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @d, nil, nil)
         
     | 
| 
      
 83 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 84 
     | 
    
         
            +
                exits.to_s.should_equal [@a, @b].to_s
         
     | 
| 
      
 85 
     | 
    
         
            +
                entries.to_s.should_equal [@e, @d].to_s
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
              specify "to grandparent" do
         
     | 
| 
      
 89 
     | 
    
         
            +
                @a.superstate = @b
         
     | 
| 
      
 90 
     | 
    
         
            +
                @b.superstate = @c
         
     | 
| 
      
 91 
     | 
    
         
            +
                transition = StateMachine::Transition.new(@a, @c, nil, nil)
         
     | 
| 
      
 92 
     | 
    
         
            +
                exits, entries = transition.exits_and_entries(@a)
         
     | 
| 
      
 93 
     | 
    
         
            +
                exits.to_s.should_equal [@a, @b, @c].to_s
         
     | 
| 
      
 94 
     | 
    
         
            +
                entries.to_s.should_equal [@c].to_s
         
     | 
| 
      
 95 
     | 
    
         
            +
              end
         
     | 
| 
      
 96 
     | 
    
         
            +
              
         
     | 
| 
      
 97 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            rubygems_version: 0.8.11
         
     | 
| 
      
 3 
     | 
    
         
            +
            specification_version: 1
         
     | 
| 
      
 4 
     | 
    
         
            +
            name: statemachine
         
     | 
| 
      
 5 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 6 
     | 
    
         
            +
              version: 0.0.0
         
     | 
| 
      
 7 
     | 
    
         
            +
            date: 2006-10-25 00:00:00 -05:00
         
     | 
| 
      
 8 
     | 
    
         
            +
            summary: RSpec-0.6.4 - BDD for Ruby http://rspec.rubyforge.org/
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 10 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 11 
     | 
    
         
            +
            email: statemachine-devel@rubyforge.org
         
     | 
| 
      
 12 
     | 
    
         
            +
            homepage: http://statemachine.rubyforge.org
         
     | 
| 
      
 13 
     | 
    
         
            +
            rubyforge_project: statemachine
         
     | 
| 
      
 14 
     | 
    
         
            +
            description: StateMachine is a ruby library for building Finite State Machines (FSM), also known as Finite State Automata (FSA).
         
     | 
| 
      
 15 
     | 
    
         
            +
            autorequire: statemachine
         
     | 
| 
      
 16 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 17 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 18 
     | 
    
         
            +
            has_rdoc: false
         
     | 
| 
      
 19 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Version::Requirement 
         
     | 
| 
      
 20 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 21 
     | 
    
         
            +
              - - ">"
         
     | 
| 
      
 22 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 23 
     | 
    
         
            +
                  version: 0.0.0
         
     | 
| 
      
 24 
     | 
    
         
            +
              version: 
         
     | 
| 
      
 25 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 26 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 27 
     | 
    
         
            +
            cert_chain: 
         
     | 
| 
      
 28 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 29 
     | 
    
         
            +
            - - Micah Martin
         
     | 
| 
      
 30 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 31 
     | 
    
         
            +
            - CHANGES
         
     | 
| 
      
 32 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 33 
     | 
    
         
            +
            - lib/proc_calling.rb
         
     | 
| 
      
 34 
     | 
    
         
            +
            - lib/state.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            - lib/state_machine.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            - lib/statemachine.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            - lib/super_state.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
            - lib/transition.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            - spec/sm_action_parameterization_spec.rb
         
     | 
| 
      
 40 
     | 
    
         
            +
            - spec/sm_entry_exit_actions_spec.rb
         
     | 
| 
      
 41 
     | 
    
         
            +
            - spec/sm_odds_n_ends_spec.rb
         
     | 
| 
      
 42 
     | 
    
         
            +
            - spec/sm_simple_spec.rb
         
     | 
| 
      
 43 
     | 
    
         
            +
            - spec/sm_super_state_spec.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            - spec/sm_turnstile_spec.rb
         
     | 
| 
      
 45 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            - spec/transition_spec.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            test_files: 
         
     | 
| 
      
 48 
     | 
    
         
            +
            - spec/sm_action_parameterization_spec.rb
         
     | 
| 
      
 49 
     | 
    
         
            +
            - spec/sm_entry_exit_actions_spec.rb
         
     | 
| 
      
 50 
     | 
    
         
            +
            - spec/sm_odds_n_ends_spec.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - spec/sm_simple_spec.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            - spec/sm_super_state_spec.rb
         
     | 
| 
      
 53 
     | 
    
         
            +
            - spec/sm_turnstile_spec.rb
         
     | 
| 
      
 54 
     | 
    
         
            +
            - spec/transition_spec.rb
         
     | 
| 
      
 55 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            dependencies: []
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     |