finite 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f1002bb014d485c4ae60030a8d9de3213579f3d2
4
- data.tar.gz: 165c19b3e8a913584cd52a78125bc5bdb46e8c97
3
+ metadata.gz: efb775ca43d0ce5dddd4215fde0c54b5f764e097
4
+ data.tar.gz: f617e7113c8f30f590c353dfa664776e74cb6c32
5
5
  SHA512:
6
- metadata.gz: a7feedd329e35cf82cedb04f72c80bbfcc7bb5e60043302a2e18f8b68ee23c837ed259271747991792f7cf4aa70a6a74cd1ec0b1ed7ff7602a961d7f9e165adc
7
- data.tar.gz: d9c11ca96d496a28995f88269e6a04a080f98619bb8f3f0f4d9561164550e4fbf478b21a602e86779bff8403a6e6839088eb78046a64df3233307be58f82d540
6
+ metadata.gz: 7e6a27d3620e1ed8a3d80099d9ff9ae7ac693ac04a81ba570b6048565e9cc6d94cd4a7ff69e5944489d652aec55ace9cabc9b688ae60d64e6c6d37762352f3e0
7
+ data.tar.gz: ad0e60854b2334e045f78c35e0649e610e56abb9253ed0f22c6260972a8b469206e385052a1748dccc23ef84d7602bee120b44aafd2488aa6ab61f0583197d80
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ spec/null.txt
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- # Finite 0.0.1
1
+ # Finite [![Build Status](https://travis-ci.org/kristenmills/finite.png)](https://travis-ci.org/kristenmills/finite)
2
+
2
3
 
3
4
  A simple state machine implementation for ruby
4
5
 
@@ -17,8 +18,92 @@ Or install it yourself as:
17
18
  $ gem install finite
18
19
 
19
20
  ## Usage
20
-
21
- TODO
21
+ ```ruby
22
+
23
+ class Elevator
24
+ include Finite
25
+
26
+ finite initial: :idle do
27
+
28
+ before do
29
+ "This is called before every state but has no purpose other than to show it's existence in this example."
30
+ end
31
+
32
+ before :doors_closing do
33
+ puts 'Doors Closing!'
34
+ end
35
+
36
+ before :doors_opening do
37
+ puts 'Doors Opening!'
38
+ end
39
+
40
+ event :prepare do
41
+ go from: :idle, to: :doors_closing
42
+ end
43
+
44
+ event :go_up do
45
+ go from: :doors_closing, to: :elevator_going_up
46
+ after do
47
+ puts 'Going Up!'
48
+ end
49
+ end
50
+
51
+ event :go_down do
52
+ go from: :doors_closing, to: :elevator_going_down
53
+ after do
54
+ puts 'Going Down!'
55
+ end
56
+ end
57
+
58
+ event :start do
59
+ go from: [:elevator_going_up, :elevator_going_down], to: :moving
60
+ end
61
+
62
+ event :approach do
63
+ go from: :moving, to: :stopping
64
+ end
65
+
66
+ event :stop do
67
+ go from: :stopping, to: :doors_opening
68
+ before do
69
+ announce_floor
70
+ end
71
+ end
72
+
73
+ event :open_doors do
74
+ go from: :doors_opening, to: :at_floor
75
+ end
76
+
77
+ event :finish do
78
+ go from: :at_floor, to: :checking_next_dest
79
+ end
80
+
81
+ event :make_request do
82
+ go from: :checking_next_dest, to: :doors_closing
83
+ end
84
+
85
+ event :make_no_request do
86
+ go from: :checking_next_dest, to: :idle
87
+ end
88
+ end
89
+
90
+ def announce_floor
91
+ puts "Arriving on floor #{rand(10)}"
92
+ end
93
+ end
94
+ ```
95
+
96
+ ```ruby
97
+ elevator = Elevator.new
98
+ elevator.current_state # => :idle
99
+ elevator.can_prepare? # => true
100
+ elevator.can_open_doors? # => false
101
+ elevator.open_doors # => RuntimeError 'Invalid Transition'
102
+ elevator.idle? # => true
103
+ elevator.prepare # => 'Doors Closing!'
104
+ elevator.current_state # => :doors_closing
105
+ elevator.possible_events # => [:go_up, :go_down]
106
+ ```
22
107
 
23
108
  ## Contributing
24
109
 
data/Rakefile CHANGED
@@ -1 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/finite.gemspec CHANGED
@@ -20,4 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "simplecov"
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "yard"
23
26
  end
@@ -0,0 +1,13 @@
1
+ module Finite
2
+ # The class methods for any class that include the finite base
3
+ module ClassMethods
4
+ # The finite method for the dsl
5
+ #
6
+ # @param opts [Hash] any options including initial state
7
+ # @param block [Block] the block of code that creates the state machine
8
+ def finite(opts, &block)
9
+ StateMachine.machines ||= Hash.new
10
+ StateMachine.machines[self] = StateMachine.new(opts[:initial], self, &block)
11
+ end
12
+ end
13
+ end
data/lib/finite/event.rb CHANGED
@@ -1,5 +1,68 @@
1
1
  module Finite
2
+
3
+ # The event class. Represents an event in the state machine
2
4
  class Event
3
- # some code
5
+
6
+ attr_reader :name, :transitions, :callbacks
7
+
8
+ # Create an event object
9
+ #
10
+ # @param name [Symbol] the name of the event
11
+ # @param block [Block] the block of code in the event
12
+ def initialize(name, &block)
13
+ @name = name
14
+ @transitions = Hash.new
15
+ @callbacks = {before: Array.new, after: Array.new}
16
+ instance_eval &block
17
+ end
18
+
19
+ # Are two events equal
20
+ #
21
+ # @param event [Object] the object you are comparing it to
22
+ # @return true if they are equal false if not
23
+ def ==(event)
24
+ if event.is_a? Event
25
+ @name == event.name
26
+ elsif event.is_a? Symbol
27
+ @name == event
28
+ else
29
+ false
30
+ end
31
+ end
32
+
33
+ # overrriden for puts and print
34
+ def to_s
35
+ @name.to_s
36
+ end
37
+
38
+ # Overridden for p
39
+ def inspect
40
+ @name
41
+ end
42
+
43
+ private
44
+ # The transition method for the dsl
45
+ #
46
+ # @param opts [Hash] the options for a transition
47
+ def go(opts)
48
+ options = []
49
+ if opts[:from].is_a? Array
50
+ opts[:from].each do |from|
51
+ options << {from: from, to: opts[:to]}
52
+ end
53
+ else
54
+ options << opts
55
+ end
56
+ options.each do |opt|
57
+ @transitions[opt[:from]] = Transition.new(opt)
58
+ end
59
+ end
60
+
61
+ # Create the callback methods
62
+ [:after, :before].each do |callback|
63
+ define_method callback do |*args, &block|
64
+ @callbacks[callback] << block
65
+ end
66
+ end
4
67
  end
5
68
  end
@@ -0,0 +1,37 @@
1
+ module Finite
2
+ # Get's the current state
3
+ # @return the current state for an object
4
+ def current_state
5
+ machine = StateMachine.machines[self.class]
6
+ @current_state or machine.states[machine.initial]
7
+ end
8
+
9
+ # Get's (and sets) the array of states
10
+ # @return the array of states
11
+ def states
12
+ @states ||= StateMachine.machines[self.class].states
13
+ @states
14
+ end
15
+
16
+ # Get's (and sets) the array of events
17
+ # @return the array of events
18
+ def events
19
+ @events ||= StateMachine.machines[self.class].events
20
+ @events
21
+ end
22
+
23
+ # Get's (and sets) the array of callbacks
24
+ # @return the array of callbacks
25
+ def callbacks
26
+ @callbacks ||= StateMachine.machines[self.class].callbacks
27
+ @callbacks
28
+ end
29
+
30
+ # Get's all the possible events you can perform
31
+ # @return any event that you can perform given your state
32
+ def possible_events
33
+ pos = Array.new
34
+ events.each_value{|event| pos << event if event.transitions.key?(current_state.name)}
35
+ pos
36
+ end
37
+ end
@@ -1,5 +1,121 @@
1
1
  module Finite
2
- class Machine
3
- # some code
2
+ # The State Machine class. Represents the whole state machine
3
+ class StateMachine
4
+
5
+ class << self
6
+ attr_accessor :machines
7
+ end
8
+
9
+ attr_reader :states, :initial, :events, :callbacks
10
+
11
+ # Create a new state machine
12
+ #
13
+ # @param initial_state [Symbol] the initial state of this state machine
14
+ # @param klass [Class] the class of the state machine
15
+ # @param block [Block] the block of code that creates it
16
+ def initialize(initial_state, klass, &block)
17
+ @class = klass
18
+ @initial = initial_state
19
+ @states = Hash.new
20
+ @events = Hash.new
21
+ @callbacks = {before: Hash.new , after: Hash.new}
22
+ instance_eval &block
23
+ end
24
+
25
+ # Add an event to the state machine
26
+ #
27
+ # @param event_name [Symbol] the event you are trying to add
28
+ # @param block [Block] the block of code that creates an event
29
+ # @raise [Exception] if the event already exists
30
+ def add_event(event_name, &block)
31
+ # We don't want to randomly override things that we shouldn't
32
+ raise "Method already taken can_#{event_name}?" if @class.methods.include?(:"can_#{event_name}?")
33
+ raise "Method already taken #{event_name}" if @class.methods.include?(:"#{event_name}")
34
+ raise 'Event #{event_name} already exists. Rename or combine the events' if events.include? event_name
35
+ event = Event.new(event_name, &block)
36
+ @events[event_name] = event
37
+ event.transitions.each_value do |transition|
38
+ add_state transition.to
39
+ add_state transition.from
40
+ end
41
+ @class.send(:define_method, :"can_#{event_name}?") do
42
+ event.transitions.key? current_state.name
43
+ end
44
+ @class.send(:define_method, :"#{event_name}") do
45
+ if event.transitions.key? current_state.name
46
+
47
+ event.callbacks[:before].each do |callback|
48
+ self.instance_eval &callback
49
+ end
50
+
51
+ if callbacks[:before].key? :all
52
+ callbacks[:before][:all].each do |callback|
53
+ self.instance_eval &callback
54
+ end
55
+ end
56
+
57
+ new_state = states[event.transitions[current_state.name].to]
58
+
59
+ if callbacks[:before].key? new_state.name
60
+ callbacks[:before][new_state.name].each do |callback|
61
+ self.instance_eval &callback
62
+ end
63
+ end
64
+ @current_state = new_state
65
+
66
+ if callbacks[:after].key? :all
67
+ callbacks[:after][:all].each do |callback|
68
+ self.instance_eval &callback
69
+ end
70
+ end
71
+ if callbacks[:after].key? current_state.name
72
+ callbacks[:after][current_state.name].each do |callback|
73
+ self.instance_eval &callback
74
+ end
75
+ end
76
+
77
+ event.callbacks[:after].each do |callback|
78
+ self.instance_eval &callback
79
+ end
80
+ else
81
+ raise 'Invalid Transition'
82
+ end
83
+ end
84
+ end
85
+
86
+ # Add a state to the the state machine if the state hasn't already been
87
+ # created
88
+ #
89
+ # @param state [Symbol] the state you are trying to add
90
+ def add_state(state)
91
+ if not @states.include? state
92
+ # Prevents arbitrarily overriding methods that you shouldn't be
93
+ raise "Method already taken #{state}?" if @class.methods.include?(:"#{state}?")
94
+ @states[state] = State.new(state)
95
+ @class.send(:define_method, :"#{state}?"){current_state == state}
96
+ end
97
+ end
98
+
99
+ private
100
+ # The event method for the dsl
101
+ #
102
+ # @param name [Symbol] the name of the event
103
+ # @param block [Block] the block of code that creates events
104
+ def event(name, &block)
105
+ add_event name, &block
106
+ end
107
+
108
+ # Create the callback methods
109
+ [:after, :before].each do |callback|
110
+ define_method callback do |*args, &block|
111
+ if args.count > 0
112
+ callbacks[callback][args[0]] ||= Array.new
113
+ callbacks[callback][args[0]] << block
114
+ else
115
+ callbacks[callback][:all] ||= Array.new
116
+ callbacks[callback][:all] << block
117
+ end
118
+ end
119
+ end
4
120
  end
5
121
  end
data/lib/finite/state.rb CHANGED
@@ -1,5 +1,38 @@
1
1
  module Finite
2
- class State
3
- # some code
4
- end
2
+
3
+ # The State class. Represents a state in the state machine.
4
+ class State
5
+ attr_reader :name
6
+
7
+ # Create a new state
8
+ #
9
+ # @param name [Symbol] the name of the state
10
+ def initialize(name)
11
+ @name = name
12
+ end
13
+
14
+ # Overide the == method for state
15
+ #
16
+ # @param state [Object] the state your comparing to
17
+ # @return true if they are equal false if not
18
+ def ==(state)
19
+ if state.is_a? Symbol
20
+ @name == state
21
+ elsif state.is_a? State
22
+ @name == state.name
23
+ else
24
+ false
25
+ end
26
+ end
27
+
28
+ # overrriden for puts and print
29
+ def to_s
30
+ @name.to_s
31
+ end
32
+
33
+ # Overridden for p
34
+ def inspect
35
+ @name
36
+ end
37
+ end
5
38
  end
@@ -1,5 +1,24 @@
1
1
  module Finite
2
+
3
+ # The transition class. Represents a transition between two states
2
4
  class Transition
3
- # some code
5
+
6
+ attr_reader :to, :from
7
+
8
+ # Create a new transition object
9
+ #
10
+ # @param opts [Hash] the options for a transition. Include :to and :from
11
+ def initialize(opts)
12
+ @from = opts[:from]
13
+ @to = opts[:to]
14
+ end
15
+
16
+ # Does this transition equal another transition?
17
+ #
18
+ # @param other [Transition] another transition
19
+ # @return true if they are equal false if not
20
+ def ==(other)
21
+ from == other.from and to == other.to
22
+ end
4
23
  end
5
24
  end
@@ -1,3 +1,4 @@
1
1
  module Finite
2
- VERSION = "0.0.1"
2
+ # The version number
3
+ VERSION = "1.0.0"
3
4
  end
data/lib/finite.rb CHANGED
@@ -1,5 +1,19 @@
1
- require 'finite/version'
1
+ [
2
+ 'version',
3
+ 'transition',
4
+ 'event',
5
+ 'state',
6
+ 'machine',
7
+ 'class_methods',
8
+ 'finite'
9
+ ].each { |file| require File.join(File.dirname(__FILE__), 'finite', file) }
2
10
 
11
+ # The Finite module. The module that contains all the classes and methods for
12
+ # the finite gem.
3
13
  module Finite
4
- # Your code goes here...
5
- end
14
+ # Override included method
15
+ def self.included(base)
16
+ base.extend(ClassMethods)
17
+ super
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Elevator do
4
+ before(:each) do
5
+ @elevator = Elevator.new
6
+ end
7
+
8
+ it 'has a state machine' do
9
+ expect(Finite::StateMachine.machines[Elevator]).to_not be_nil
10
+ end
11
+
12
+ context 'states' do
13
+ it 'has a current state' do
14
+ expect(@elevator.current_state).to_not be_nil
15
+ expect(@elevator.current_state).to eq(:idle)
16
+ end
17
+
18
+ it 'has methods to tell whether it is in a state or not' do
19
+ expect(@elevator.idle?).to be_true
20
+ expect(@elevator.moving?).to be_false
21
+ end
22
+
23
+ it 'can access all states' do
24
+ expect(@elevator.states).to_not be_nil
25
+ expect(@elevator.states.count).to be(9)
26
+ end
27
+ end
28
+
29
+ context 'events' do
30
+ it 'can access all events' do
31
+ expect(@elevator.events).to_not be_nil
32
+ expect(@elevator.events.count).to be(10)
33
+ end
34
+
35
+ it 'can access possible events for a given state' do
36
+ expect(@elevator.possible_events).to eq([:prepare])
37
+ end
38
+
39
+ it 'has methods to tell whether an event can be performed' do
40
+ expect(@elevator.can_prepare?).to be_true
41
+ expect(@elevator.can_go_up?).to be_false
42
+ end
43
+
44
+ it 'can perform events' do
45
+ @elevator.prepare
46
+ expect(@elevator.current_state).to eq(:doors_closing)
47
+ expect(@elevator.doors_closing?).to be_true
48
+ expect(@elevator.idle?).to be_false
49
+ expect(@elevator.possible_events).to eq([:go_up,:go_down])
50
+ expect{@elevator.start}.to raise_error
51
+ @elevator.go_down
52
+ expect(@elevator.can_start?).to be_true
53
+ @elevator.start
54
+ @elevator.approach
55
+ @elevator.stop
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Finite::Event do
4
+ before(:each) do
5
+ @block = Proc.new do
6
+ go from: :state1, to: :state2
7
+ after do
8
+ 'hello again'
9
+ end
10
+ before do
11
+ 'hello for the first time'
12
+ end
13
+ end
14
+ end
15
+
16
+ it 'has a name' do
17
+ event = Finite::Event.new(:event1, &@block)
18
+ expect(event.name).to eq(:event1)
19
+ end
20
+
21
+ context 'equality' do
22
+ it 'equals symbols that have the same name' do
23
+ event = Finite::Event.new(:event1, &@block)
24
+ expect(event).to eq(:event1)
25
+ expect(event).not_to eq(:event2)
26
+ end
27
+
28
+ it 'equals events with the same name' do
29
+ event1 = Finite::Event.new(:event1, &@block)
30
+ event2 = Finite::Event.new(:event2, &@block)
31
+ event3 = Finite::Event.new(:event1, &@block)
32
+
33
+ expect(event1).to eq(event3)
34
+ expect(event1).not_to eq(event2)
35
+ end
36
+
37
+ it "doesn't equal things that aren't symbols or events" do
38
+ event = Finite::Event.new(:event1, &@block)
39
+ expect(event).not_to eq('string')
40
+ end
41
+ end
42
+
43
+ it 'should create transitions' do
44
+ event = Finite::Event.new(:event1, &@block)
45
+ event.transitions.count.should be(1)
46
+ event.transitions[:state1].to.should eq(:state2)
47
+ event.transitions[:state1].from.should eq(:state1)
48
+ end
49
+
50
+ it 'should create callbacks' do
51
+ event = Finite::Event.new(:event1, &@block)
52
+
53
+ expect(event.callbacks[:before]).not_to be_nil
54
+ expect(event.callbacks[:after]).not_to be_nil
55
+ expect(event.callbacks[:after][0].call).to eq('hello again')
56
+ expect(event.callbacks[:before][0].call).to eq('hello for the first time')
57
+ end
58
+
59
+ it 'has to_s and inspect methods' do
60
+ event = Finite::Event.new(:event, &@block)
61
+ expect(event.to_s).to eq('event')
62
+ expect(event.inspect).to eq(:event)
63
+ end
64
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Finite::StateMachine do
4
+ before(:each) do
5
+ @elevator = Elevator.new
6
+ @machine = Finite::StateMachine.machines[Elevator]
7
+ end
8
+
9
+ context 'adding events' do
10
+ it 'has events' do
11
+ expect(@machine.events.count).to be(10)
12
+ end
13
+
14
+ it 'cannot have events with the same name' do
15
+ expect{@machine.add_event(:prepare){}}.to raise_error
16
+ end
17
+
18
+ it 'cannot be stupid with your event naming' do
19
+ expect{@machine.add_event(:to_s)}.to raise_error
20
+ end
21
+
22
+ it 'increases in size when an event is added' do
23
+ @machine.add_event(:random_event){}
24
+ expect(@machine.events.count).to be(11)
25
+ end
26
+ it 'adds the proper helper methods' do
27
+ expect(@elevator.methods).to include(:random_event)
28
+ expect(@elevator.methods).to include(:can_random_event?)
29
+ end
30
+ end
31
+
32
+ context 'adding states' do
33
+ it 'has states' do
34
+ expect(@machine.states.count).to be(9)
35
+ end
36
+
37
+ it 'cannot be stupid with your state naming' do
38
+ expect{@machine.add_state(:const_defined){}}.to raise_error
39
+ end
40
+
41
+ it 'cannot have states with the same name' do
42
+ @machine.add_state(:doors_closing){}
43
+ expect(@machine.states.count).to be(9)
44
+ end
45
+
46
+ it 'increases in size when a state is added' do
47
+ @machine.add_state(:random_state){}
48
+ expect(@machine.states.count).to be(10)
49
+ end
50
+
51
+ it 'adds the proper helper method' do
52
+ expect(@elevator.methods).to include(:random_state?)
53
+ end
54
+ end
55
+
56
+ context 'callbacks' do
57
+ it 'has after and before keys' do
58
+ expect(@machine.callbacks).to include(:before)
59
+ expect(@machine.callbacks).to include(:after)
60
+ end
61
+
62
+ it 'adds callbacks' do
63
+ expect(@machine.callbacks[:before]).to include(:doors_closing)
64
+ expect(@machine.callbacks[:before]).to include(:doors_opening)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,94 @@
1
+
2
+ class Elevator
3
+ include Finite
4
+
5
+ def initialize
6
+ @before_called = 0
7
+ @after_called = 0
8
+ end
9
+
10
+ finite initial: :idle do
11
+
12
+ before :doors_closing do
13
+ puts 'Doors Closing!'
14
+ end
15
+
16
+ before :doors_opening do
17
+ puts 'Doors Opening!'
18
+ end
19
+
20
+ after :doors_closing do
21
+ puts "I'm no longer idle"
22
+ end
23
+
24
+ before do
25
+ @before_called += 1
26
+ end
27
+
28
+ after do
29
+ @after_called += 1
30
+ end
31
+
32
+
33
+ event :prepare do
34
+ go from: :idle, to: :doors_closing
35
+ end
36
+
37
+ event :go_up do
38
+ go from: :doors_closing, to: :elevator_going_up
39
+ after do
40
+ puts 'Going Up!'
41
+ end
42
+ end
43
+
44
+ event :go_down do
45
+ go from: :doors_closing, to: :elevator_going_down
46
+ after do
47
+ puts 'Going Down!'
48
+ end
49
+ end
50
+
51
+ event :start do
52
+ go from: [:elevator_going_up, :elevator_going_down], to: :moving
53
+ end
54
+
55
+ event :approach do
56
+ go from: :moving, to: :stopping
57
+ end
58
+
59
+ event :stop do
60
+ go from: :stopping, to: :doors_opening
61
+ before do
62
+ announce_floor
63
+ end
64
+ end
65
+
66
+ event :open_doors do
67
+ go from: :doors_opening, to: :at_floor
68
+ end
69
+
70
+ event :finish do
71
+ go from: :at_floor, to: :checking_next_dest
72
+ end
73
+
74
+ event :make_request do
75
+ go from: :checking_next_dest, to: :doors_closing
76
+ end
77
+
78
+ event :make_no_request do
79
+ go from: :checking_next_dest, to: :idle
80
+ end
81
+ end
82
+ def announce_floor
83
+ puts "Arriving on floor #{rand(10)}"
84
+ end
85
+ end
86
+
87
+ # elevator = Elevator.new
88
+ # elevator.prepare
89
+ # elevator.go_up
90
+ # elevator.start
91
+ # elevator.approach
92
+ # elevator.stop
93
+ # puts elevator.can_open_doors?
94
+ # puts elevator.can_finish?
@@ -0,0 +1,20 @@
1
+ require 'rspec'
2
+ require 'simplecov'
3
+
4
+ SimpleCov.start
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'finite')
6
+ Dir[File.dirname(__FILE__) + "/models/*.rb"].sort.each { |f| require File.expand_path(f) }
7
+
8
+ RSpec.configure do |config|
9
+ original_stderr = $stderr
10
+ original_stdout = $stdout
11
+ config.before(:all) do
12
+ # Redirect stderr and stdout
13
+ $stderr = File.new(File.join(File.dirname(__FILE__), 'null.txt'), 'w')
14
+ $stdout = File.new(File.join(File.dirname(__FILE__), 'null.txt'), 'w')
15
+ end
16
+ config.after(:all) do
17
+ $stderr = original_stderr
18
+ $stdout = original_stdout
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Finite::State do
4
+ before(:each) do
5
+ @name = :state_name
6
+ end
7
+
8
+ it 'has a name' do
9
+ Finite::State.new(@name).name.should eq(:state_name)
10
+ end
11
+ context 'equality' do
12
+ it 'equals a symbol of the same name' do
13
+ state = Finite::State.new(@name)
14
+ expect(state).to eq(:state_name)
15
+ expect(state).not_to eq(:different_name)
16
+ end
17
+
18
+ it 'equals a state with the same name' do
19
+ state1 = Finite::State.new(@name)
20
+ state2 = Finite::State.new(:different_name)
21
+ state3 = Finite::State.new(@name)
22
+ expect(state1).to eq(state3)
23
+ expect(state1).not_to eq(state2)
24
+ end
25
+
26
+ it "doesn't equal objects that aren't states or symbols" do
27
+ state = Finite::State.new(@name)
28
+ expect(state).not_to eq('string')
29
+ end
30
+ end
31
+ it 'has to_s and inspect methods' do
32
+ state = Finite::State.new(@name)
33
+ expect(state.to_s).to eq('state_name')
34
+ expect(state.inspect).to eq(:state_name)
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Finite::Transition do
4
+ it 'has a to and a from' do
5
+ transition = Finite::Transition.new({from: :state1, to: :state2})
6
+ expect(transition.from).to eq(:state1)
7
+ expect(transition.to).to eq(:state2)
8
+ end
9
+
10
+ it 'equals transitions with the same to and from' do
11
+ transition1 = Finite::Transition.new({from: :state1, to: :state2})
12
+ transition2 = Finite::Transition.new({from: :state1, to: :state3})
13
+ transition3 = Finite::Transition.new({from: :state4, to: :state2})
14
+ transition4 = Finite::Transition.new({from: :state1, to: :state2})
15
+
16
+ expect(transition1).not_to eq(transition2)
17
+ expect(transition1).not_to eq(transition3)
18
+ expect(transition1).to eq(transition4)
19
+ end
20
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: finite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kristen Mills
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-29 00:00:00.000000000 Z
11
+ date: 2013-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,48 @@ dependencies:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
41
83
  description: A simple state machine implementation for ruby
42
84
  email:
43
85
  - kristen@kristen-mills.com
@@ -46,17 +88,27 @@ extensions: []
46
88
  extra_rdoc_files: []
47
89
  files:
48
90
  - .gitignore
91
+ - .travis.yml
49
92
  - Gemfile
50
93
  - LICENSE.txt
51
94
  - README.md
52
95
  - Rakefile
53
96
  - finite.gemspec
54
97
  - lib/finite.rb
98
+ - lib/finite/class_methods.rb
55
99
  - lib/finite/event.rb
100
+ - lib/finite/finite.rb
56
101
  - lib/finite/machine.rb
57
102
  - lib/finite/state.rb
58
103
  - lib/finite/transition.rb
59
104
  - lib/finite/version.rb
105
+ - spec/elevator_spec.rb
106
+ - spec/event_spec.rb
107
+ - spec/machine_spec.rb
108
+ - spec/models/elevator.rb
109
+ - spec/spec_helper.rb
110
+ - spec/state_spec.rb
111
+ - spec/transition_spec.rb
60
112
  homepage: http://github.com/kristenmills/finite
61
113
  licenses:
62
114
  - MIT
@@ -81,4 +133,12 @@ rubygems_version: 2.0.3
81
133
  signing_key:
82
134
  specification_version: 4
83
135
  summary: A simple state machine implementation for ruby
84
- test_files: []
136
+ test_files:
137
+ - spec/elevator_spec.rb
138
+ - spec/event_spec.rb
139
+ - spec/machine_spec.rb
140
+ - spec/models/elevator.rb
141
+ - spec/spec_helper.rb
142
+ - spec/state_spec.rb
143
+ - spec/transition_spec.rb
144
+ has_rdoc: