finite 0.0.1 → 1.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.
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: