finite_machine 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -147,7 +147,7 @@ describe FiniteMachine, 'events' do
147
147
 
148
148
  expect(fsm.current).to eql(:green)
149
149
 
150
- expect { fsm.stop }.to raise_error(FiniteMachine::TransitionError, /state 'green'/)
150
+ expect { fsm.stop }.to raise_error(FiniteMachine::InvalidStateError, /state 'green'/)
151
151
  end
152
152
 
153
153
  context 'when multiple from states' do
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe FiniteMachine, 'handlers' do
6
+
7
+ before(:each) {
8
+ Logger = Class.new do
9
+ attr_reader :result
10
+
11
+ def log_error(exception)
12
+ @result = "log_error(#{exception})"
13
+ end
14
+
15
+ def raise_error
16
+ raise FiniteMachine::TransitionError
17
+ end
18
+ end
19
+ }
20
+
21
+ it "allows to customise error handling" do
22
+ called = []
23
+ fsm = FiniteMachine.define do
24
+ initial :green
25
+
26
+ events {
27
+ event :slow, :green => :yellow
28
+ event :stop, :yellow => :red
29
+ }
30
+
31
+ handlers {
32
+ handle FiniteMachine::InvalidStateError do |exception|
33
+ called << 'invalidstate'
34
+ end
35
+ }
36
+ end
37
+
38
+ expect(fsm.current).to eql(:green)
39
+ fsm.stop
40
+ expect(fsm.current).to eql(:green)
41
+ expect(called).to eql([
42
+ 'invalidstate'
43
+ ])
44
+ end
45
+
46
+ it 'allows for :with to be symbol' do
47
+ logger = Logger.new
48
+ fsm = FiniteMachine.define do
49
+ initial :green
50
+
51
+ target logger
52
+
53
+ events {
54
+ event :slow, :green => :yellow
55
+ event :stop, :yellow => :red
56
+ }
57
+
58
+ handlers {
59
+ handle FiniteMachine::InvalidStateError, with: :log_error
60
+ }
61
+ end
62
+
63
+ expect(fsm.current).to eql(:green)
64
+ fsm.stop
65
+ expect(fsm.current).to eql(:green)
66
+ expect(logger.result).to eql('log_error(FiniteMachine::InvalidStateError)')
67
+ end
68
+
69
+ it 'allows for error type as string' do
70
+ logger = Logger.new
71
+ called = []
72
+ fsm = FiniteMachine.define do
73
+ initial :green
74
+
75
+ target logger
76
+
77
+ events {
78
+ event :slow, :green => :yellow
79
+ event :stop, :yellow => :red
80
+ }
81
+
82
+ callbacks {
83
+ on_enter_yellow do |event|
84
+ raise_error
85
+ end
86
+ }
87
+ handlers {
88
+ handle 'InvalidStateError' do |exception|
89
+ called << 'invalid_state_error'
90
+ end
91
+ }
92
+ end
93
+
94
+ expect(fsm.current).to eql(:green)
95
+ fsm.stop
96
+ expect(fsm.current).to eql(:green)
97
+ expect(called).to eql(['invalid_state_error'])
98
+ end
99
+ end
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe FiniteMachine, ':if, :unless' do
6
- before(:all) {
6
+ before(:each) {
7
7
  Car = Class.new do
8
8
  def turn_engine_on
9
9
  @engine_on = true
@@ -62,7 +62,7 @@ describe FiniteMachine, ':if, :unless' do
62
62
  initial :green
63
63
 
64
64
  events {
65
- event :slow, :green => :yellow, unless: -> { return true }
65
+ event :slow, :green => :yellow, unless: -> { true }
66
66
  event :stop, :yellow => :red
67
67
  }
68
68
 
@@ -125,7 +125,7 @@ describe FiniteMachine, ':if, :unless' do
125
125
  target car
126
126
 
127
127
  events {
128
- event :start, :neutral => :one, if: -> (car) { car.engine_on? }
128
+ event :start, :neutral => :one, if: proc {|car| car.engine_on? }
129
129
  event :shift, :one => :two
130
130
  }
131
131
  end
@@ -4,6 +4,16 @@ require 'spec_helper'
4
4
 
5
5
  describe FiniteMachine, 'initialize' do
6
6
 
7
+ before(:each) {
8
+ Logger = Class.new do
9
+ attr_accessor :level
10
+
11
+ def initialize
12
+ @level = :pending
13
+ end
14
+ end
15
+ }
16
+
7
17
  it "defaults initial state to :none" do
8
18
  fsm = FiniteMachine.define do
9
19
  events {
@@ -46,6 +56,23 @@ describe FiniteMachine, 'initialize' do
46
56
  fsm = FiniteMachine.define do
47
57
  initial state: :green, event: :start
48
58
 
59
+ events {
60
+ event :slow, :green => :none
61
+ event :stop, :yellow => :red
62
+ }
63
+ end
64
+
65
+ expect(fsm.current).to eql(:green)
66
+ fsm.slow
67
+ expect(fsm.current).to eql(:none)
68
+ fsm.start
69
+ expect(fsm.current).to eql(:green)
70
+ end
71
+
72
+ it "allows to specify deferred inital start event" do
73
+ fsm = FiniteMachine.define do
74
+ initial state: :green, event: :start, defer: true
75
+
49
76
  events {
50
77
  event :slow, :green => :yellow
51
78
  event :stop, :yellow => :red
@@ -56,4 +83,17 @@ describe FiniteMachine, 'initialize' do
56
83
  fsm.start
57
84
  expect(fsm.current).to eql(:green)
58
85
  end
86
+
87
+ it "evaluates initial state" do
88
+ logger = Logger.new
89
+ fsm = FiniteMachine.define do
90
+ initial logger.level
91
+
92
+ events {
93
+ event :slow, :green => :none
94
+ event :stop, :yellow => :red
95
+ }
96
+ end
97
+ expect(fsm.current).to eql(:pending)
98
+ end
59
99
  end
@@ -0,0 +1,137 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe FiniteMachine, '#target' do
6
+
7
+ it "allows to target external object" do
8
+ Car = Class.new do
9
+ attr_accessor :reverse_lights
10
+
11
+ def turn_reverse_lights_off
12
+ @reverse_lights = false
13
+ end
14
+
15
+ def turn_reverse_lights_on
16
+ @reverse_lights = true
17
+ end
18
+
19
+ def engine
20
+ context = self
21
+ @engine ||= FiniteMachine.define do
22
+ initial :neutral
23
+
24
+ target context
25
+
26
+ events {
27
+ event :forward, [:reverse, :neutral] => :one
28
+ event :shift, :one => :two
29
+ event :shift, :two => :one
30
+ event :back, [:neutral, :one] => :reverse
31
+ }
32
+
33
+ callbacks {
34
+ on_enter :reverse do |event|
35
+ turn_reverse_lights_on
36
+ end
37
+
38
+ on_exit :reverse do |event|
39
+ turn_reverse_lights_off
40
+ end
41
+ }
42
+ end
43
+ end
44
+ end
45
+ car = Car.new
46
+ expect(car.reverse_lights).to be_false
47
+ expect(car.engine.current).to eql(:neutral)
48
+ car.engine.back
49
+ expect(car.engine.current).to eql(:reverse)
50
+ expect(car.reverse_lights).to be_true
51
+ car.engine.forward
52
+ expect(car.engine.current).to eql(:one)
53
+ expect(car.reverse_lights).to be_false
54
+ end
55
+
56
+ it "references machine methods inside callback" do
57
+ called = []
58
+ fsm = FiniteMachine.define do
59
+ initial :green
60
+
61
+ events {
62
+ event :slow, :green => :yellow
63
+ event :stop, :yellow => :red
64
+ event :ready, :red => :yellow
65
+ event :go, :yellow => :green
66
+ }
67
+
68
+ callbacks {
69
+ on_enter_yellow do |event|
70
+ stop(:now)
71
+ end
72
+
73
+ on_enter_red do |event, param|
74
+ called << "#{event.from} #{param}"
75
+ end
76
+ }
77
+ end
78
+
79
+ expect(fsm.current).to eql(:green)
80
+ fsm.slow
81
+ expect(fsm.current).to eql(:red)
82
+ expect(called).to eql(['yellow now'])
83
+ end
84
+
85
+ it "allows context methods take precedence over machine ones" do
86
+ Car = Class.new do
87
+ attr_accessor :reverse_lights
88
+ attr_accessor :called
89
+
90
+ def turn_reverse_lights_off
91
+ @reverse_lights = false
92
+ end
93
+
94
+ def turn_reverse_lights_on
95
+ @reverse_lights = true
96
+ end
97
+
98
+ def engine
99
+ self.called ||= []
100
+ context ||= self
101
+ @engine ||= FiniteMachine.define do
102
+ initial :neutral
103
+
104
+ target context
105
+
106
+ events {
107
+ event :forward, [:reverse, :neutral] => :one
108
+ event :shift, :one => :two
109
+ event :shift, :two => :one
110
+ event :back, [:neutral, :one] => :reverse
111
+ }
112
+
113
+ callbacks {
114
+ on_enter :reverse do |event|
115
+ called << 'on_enter_reverse'
116
+ turn_reverse_lights_on
117
+ forward('Piotr!')
118
+ end
119
+ on_enter :forward do |event, name|
120
+ called << "on_enter_forward with #{name}"
121
+ end
122
+ }
123
+ end
124
+ end
125
+ end
126
+
127
+ car = Car.new
128
+ expect(car.reverse_lights).to be_false
129
+ expect(car.engine.current).to eql(:neutral)
130
+ car.engine.back
131
+ expect(car.engine.current).to eql(:one)
132
+ expect(car.called).to eql([
133
+ 'on_enter_reverse',
134
+ 'on_enter_forward with Piotr!'
135
+ ])
136
+ end
137
+ end
@@ -4,15 +4,24 @@ require 'spec_helper'
4
4
 
5
5
  describe FiniteMachine::Transition, 'parse_states' do
6
6
 
7
- let(:object) { described_class.new(attrs) }
7
+ let(:machine) { double }
8
8
 
9
- subject(:transition) { object.parse_states(attrs) }
9
+ subject(:transition) { described_class.new(machine, attrs) }
10
+
11
+ context 'without transitions' do
12
+ let(:attrs) { { } }
13
+
14
+ it "raises exception" do
15
+ expect { transition }.to raise_error(FiniteMachine::NotEnoughTransitionsError)
16
+ end
17
+ end
10
18
 
11
19
  context 'with :from, :to keys' do
12
20
  let(:attrs) { {from: [:green, :yellow], to: :red} }
13
21
 
14
22
  it "groups states" do
15
- expect(transition).to eql([[:green, :yellow], :red])
23
+ expect(transition.from).to eql(attrs[:from])
24
+ expect(transition.to).to eql(attrs[:to])
16
25
  end
17
26
  end
18
27
 
@@ -20,7 +29,8 @@ describe FiniteMachine::Transition, 'parse_states' do
20
29
  let(:attrs) { {[:green, :yellow] => :red} }
21
30
 
22
31
  it "groups states" do
23
- expect(transition).to eql([[:green, :yellow], :red])
32
+ expect(transition.from).to eql([:green, :yellow])
33
+ expect(transition.to).to eql(:red)
24
34
  end
25
35
  end
26
36
 
@@ -28,7 +38,8 @@ describe FiniteMachine::Transition, 'parse_states' do
28
38
  let(:attrs) { { :green => :red, :yellow => :red} }
29
39
 
30
40
  it "groups states" do
31
- expect(transition).to eql([[:green, :yellow], :red])
41
+ expect(transition.from).to eql([:green, :yellow])
42
+ expect(transition.to).to eql(:red)
32
43
  end
33
44
  end
34
45
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: finite_machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-09 00:00:00.000000000 Z
11
+ date: 2014-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,7 +52,9 @@ dependencies:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- description: A minimal finite state machine with a straightforward syntax.
55
+ description: A minimal finite state machine with a straightforward syntax. You can
56
+ quickly model states, add callbacks and use object-oriented techniques to integrate
57
+ with ORMs.
56
58
  email:
57
59
  - ''
58
60
  executables: []
@@ -62,6 +64,7 @@ files:
62
64
  - .gitignore
63
65
  - .rspec
64
66
  - .travis.yml
67
+ - CHANGELOG.md
65
68
  - Gemfile
66
69
  - LICENSE.txt
67
70
  - README.md
@@ -69,8 +72,10 @@ files:
69
72
  - finite_machine.gemspec
70
73
  - lib/finite_machine.rb
71
74
  - lib/finite_machine/callable.rb
75
+ - lib/finite_machine/catchable.rb
72
76
  - lib/finite_machine/dsl.rb
73
77
  - lib/finite_machine/event.rb
78
+ - lib/finite_machine/hooks.rb
74
79
  - lib/finite_machine/observer.rb
75
80
  - lib/finite_machine/state_machine.rb
76
81
  - lib/finite_machine/subscribers.rb
@@ -78,17 +83,20 @@ files:
78
83
  - lib/finite_machine/transition.rb
79
84
  - lib/finite_machine/version.rb
80
85
  - spec/spec_helper.rb
86
+ - spec/unit/callable/call_spec.rb
81
87
  - spec/unit/callbacks_spec.rb
82
88
  - spec/unit/can_spec.rb
83
89
  - spec/unit/define_spec.rb
84
90
  - spec/unit/events_spec.rb
85
91
  - spec/unit/finished_spec.rb
92
+ - spec/unit/handlers_spec.rb
86
93
  - spec/unit/if_unless_spec.rb
87
94
  - spec/unit/initialize_spec.rb
88
95
  - spec/unit/is_spec.rb
89
96
  - spec/unit/states_spec.rb
97
+ - spec/unit/target_spec.rb
90
98
  - spec/unit/transition/parse_states_spec.rb
91
- homepage: ''
99
+ homepage: https://github.com/peter-murach/finite_machine
92
100
  licenses:
93
101
  - MIT
94
102
  metadata: {}
@@ -114,13 +122,16 @@ specification_version: 4
114
122
  summary: A minimal finite state machine with a straightforward syntax.
115
123
  test_files:
116
124
  - spec/spec_helper.rb
125
+ - spec/unit/callable/call_spec.rb
117
126
  - spec/unit/callbacks_spec.rb
118
127
  - spec/unit/can_spec.rb
119
128
  - spec/unit/define_spec.rb
120
129
  - spec/unit/events_spec.rb
121
130
  - spec/unit/finished_spec.rb
131
+ - spec/unit/handlers_spec.rb
122
132
  - spec/unit/if_unless_spec.rb
123
133
  - spec/unit/initialize_spec.rb
124
134
  - spec/unit/is_spec.rb
125
135
  - spec/unit/states_spec.rb
136
+ - spec/unit/target_spec.rb
126
137
  - spec/unit/transition/parse_states_spec.rb