finite_machine 0.1.0 → 0.2.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.
@@ -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