finite_machine 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +7 -0
  4. data/Gemfile +5 -4
  5. data/README.md +49 -9
  6. data/lib/finite_machine.rb +1 -2
  7. data/lib/finite_machine/choice_merger.rb +5 -5
  8. data/lib/finite_machine/definition.rb +9 -0
  9. data/lib/finite_machine/dsl.rb +16 -13
  10. data/lib/finite_machine/env.rb +19 -0
  11. data/lib/finite_machine/state_machine.rb +3 -3
  12. data/lib/finite_machine/version.rb +1 -1
  13. data/spec/spec_helper.rb +7 -14
  14. data/spec/unit/alias_target_spec.rb +3 -3
  15. data/spec/unit/async_events_spec.rb +1 -1
  16. data/spec/unit/callable/call_spec.rb +3 -3
  17. data/spec/unit/callbacks_spec.rb +1 -1
  18. data/spec/unit/can_spec.rb +3 -3
  19. data/spec/unit/choice_spec.rb +31 -3
  20. data/spec/unit/define_spec.rb +1 -1
  21. data/spec/unit/definition_spec.rb +48 -5
  22. data/spec/unit/event/add_spec.rb +1 -1
  23. data/spec/unit/event/eql_spec.rb +1 -1
  24. data/spec/unit/event/initialize_spec.rb +1 -1
  25. data/spec/unit/event/inspect_spec.rb +1 -1
  26. data/spec/unit/event/next_transition_spec.rb +1 -1
  27. data/spec/unit/event_queue_spec.rb +1 -1
  28. data/spec/unit/events_chain/check_choice_conditions_spec.rb +1 -1
  29. data/spec/unit/events_chain/clear_spec.rb +1 -1
  30. data/spec/unit/events_chain/insert_spec.rb +1 -1
  31. data/spec/unit/events_chain/inspect_spec.rb +1 -1
  32. data/spec/unit/events_chain/select_transition_spec.rb +1 -1
  33. data/spec/unit/events_spec.rb +1 -1
  34. data/spec/unit/handlers_spec.rb +3 -3
  35. data/spec/unit/hook_event/eql_spec.rb +1 -1
  36. data/spec/unit/hook_event/initialize_spec.rb +1 -1
  37. data/spec/unit/hooks/call_spec.rb +1 -1
  38. data/spec/unit/hooks/inspect_spec.rb +1 -1
  39. data/spec/unit/hooks/register_spec.rb +1 -1
  40. data/spec/unit/if_unless_spec.rb +5 -5
  41. data/spec/unit/initialize_spec.rb +3 -3
  42. data/spec/unit/inspect_spec.rb +1 -2
  43. data/spec/unit/is_spec.rb +1 -1
  44. data/spec/unit/log_transitions_spec.rb +1 -1
  45. data/spec/unit/logger_spec.rb +1 -2
  46. data/spec/unit/respond_to_spec.rb +4 -3
  47. data/spec/unit/state_parser/inspect_spec.rb +1 -1
  48. data/spec/unit/state_parser/parse_states_spec.rb +1 -1
  49. data/spec/unit/states_spec.rb +1 -2
  50. data/spec/unit/subscribers_spec.rb +1 -1
  51. data/spec/unit/target_spec.rb +7 -8
  52. data/spec/unit/terminated_spec.rb +1 -1
  53. data/spec/unit/transition/inspect_spec.rb +1 -1
  54. data/spec/unit/transition/parse_states_spec.rb +1 -1
  55. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f3f7827c0cdd099708b2dd384b7d7acfe82449d8
4
- data.tar.gz: 1aa5b2f9964b04c5ff1c7d642acd6eb67b985411
3
+ metadata.gz: ec0da72426b4f28c1b3e06cb7bce0de974ac4445
4
+ data.tar.gz: 36d0560b1fc8148cf9c3d194aff3843148e56854
5
5
  SHA512:
6
- metadata.gz: 2146d17c6edc868af3e1dc7e0a772893e2b7c4b1954a2a259dd3a9bca6a750083ac06a78ce1bc10fbc3c04902a98ce7ae659a42948d558a3a3fd25ccc942ae4b
7
- data.tar.gz: 4ac655d7e523e6c2d872844b65de8fa0b29449b7d33b4c6cf8834e8586b5b68503cda2653f266e4a4f9cf07291d47031513caf97d04fe2e33f88e6e154f917ad
6
+ metadata.gz: 57dbe7dada41dcfe1fafda95f2a5e7664cdaa62c506e9afdf5f943aa561bae2ea2d9a9a399bc910a08c82e3c76e5350345f89471c90e4deb9e8133a4a37c3a73
7
+ data.tar.gz: a14127d9c43b5bcb68b0223c4b5dc3f807c48513ba6fe89fda7e0f4e191e849ac013d2144bf489c54fbe71b9b7c61d0999bef986e436159a3de287acdae807e8
data/.travis.yml CHANGED
@@ -5,6 +5,7 @@ rvm:
5
5
  - 1.9.3
6
6
  - 2.0.0
7
7
  - 2.1.0
8
+ - 2.2.0
8
9
  - ruby-head
9
10
  matrix:
10
11
  include:
@@ -16,8 +17,6 @@ matrix:
16
17
  allow_failures:
17
18
  - rvm: ruby-head
18
19
  - rvm: jruby-head
19
- - rvm: jruby-20mode
20
- - rvm: jruby-21mode
21
20
  - rvm: rbx-2
22
21
  fast_finish: true
23
22
  branches:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ 0.10.1 (May 24, 2015)
2
+
3
+ * Add ability to inherit state machine definitions
4
+ * Add Env class for holiding machine envionment references
5
+ * Change DSL to delegate calls to machine instance
6
+ * Change ChoiceMerger to use machine directly
7
+
1
8
  0.10.0 (November 16, 2014)
2
9
 
3
10
  * Add #alias_target to allow renaming of target object by @reggieb
data/Gemfile CHANGED
@@ -3,13 +3,14 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :development do
6
- gem 'rake', '~> 10.3.2'
7
- gem 'rspec', '~> 3.1.0'
6
+ gem 'pry', '~> 0.10.1'
7
+ gem 'rake', '~> 10.4.2'
8
+ gem 'rspec', '~> 3.2.0'
8
9
  gem 'yard', '~> 0.8.7'
9
10
  end
10
11
 
11
12
  group :metrics do
12
- gem 'coveralls', '~> 0.7.0'
13
- gem 'simplecov', '~> 0.8.2'
13
+ gem 'coveralls', '~> 0.8.1'
14
+ gem 'simplecov', '~> 0.10.0'
14
15
  gem 'yardstick', '~> 0.9.9'
15
16
  end
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # FiniteMachine
2
- [![Gem Version](https://badge.fury.io/rb/finite_machine.png)][gem]
3
- [![Build Status](https://secure.travis-ci.org/peter-murach/finite_machine.png?branch=master)][travis]
4
- [![Code Climate](https://codeclimate.com/github/peter-murach/finite_machine.png)][codeclimate]
5
- [![Coverage Status](https://coveralls.io/repos/peter-murach/finite_machine/badge.png)][coverage]
6
- [![Inline docs](http://inch-ci.org/github/peter-murach/finite_machine.png)][inchpages]
2
+ [![Gem Version](https://badge.fury.io/rb/finite_machine.svg)][gem]
3
+ [![Build Status](https://secure.travis-ci.org/peter-murach/finite_machine.svg?branch=master)][travis]
4
+ [![Code Climate](https://codeclimate.com/github/peter-murach/finite_machine/badges/gpa.svg)][codeclimate]
5
+ [![Coverage Status](https://coveralls.io/repos/peter-murach/finite_machine/badge.svg)][coverage]
6
+ [![Inline docs](http://inch-ci.org/github/peter-murach/finite_machine.svg)][inchpages]
7
7
  [![Gitter](https://badges.gitter.im/Join Chat.svg)][gitter]
8
8
 
9
9
  [gem]: http://badge.fury.io/rb/finite_machine
@@ -13,7 +13,7 @@
13
13
  [inchpages]: http://inch-ci.org/github/peter-murach/finite_machine
14
14
  [gitter]: https://gitter.im/peter-murach/finite_machine?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
15
15
 
16
- A minimal finite state machine with a straightforward and intuitive syntax. You can quickly model states and add callbacks that can be triggered synchronously or asynchronously. The machine is event driven with a focus on passing synchronous and asynchronous messages to trigger state transitions.
16
+ > A minimal finite state machine with a straightforward and intuitive syntax. You can quickly model states and add callbacks that can be triggered synchronously or asynchronously. The machine is event driven with a focus on passing synchronous and asynchronous messages to trigger state transitions.
17
17
 
18
18
  ## Features
19
19
 
@@ -91,6 +91,7 @@ Or install it yourself as:
91
91
  * [7. Stand-Alone FiniteMachine](#7-stand-alone-finitemachine)
92
92
  * [7.1 Creating a Definition](#71-creating-a-definition)
93
93
  * [7.2 Targeting definition](#72-targeting-definition)
94
+ * [7.3 Definition inheritance](#73-definition-inheritance)
94
95
  * [8. Integration](#8-integration)
95
96
  * [8.1 Plain Ruby Objects](#81-plain-ruby-objects)
96
97
  * [8.2 ActiveRecord](#82-activerecord)
@@ -232,7 +233,7 @@ end
232
233
 
233
234
  ### 1.3 terminal
234
235
 
235
- To specify a final state **FiniteMachine** uses the `terminal` method. The `terminal` can accpet more than one state.
236
+ To specify a final state **FiniteMachine** uses the `terminal` method. The `terminal` can accept more than one state.
236
237
 
237
238
  ```ruby
238
239
  fm = FiniteMachine.define do
@@ -1213,6 +1214,45 @@ class Car
1213
1214
  end
1214
1215
  ```
1215
1216
 
1217
+ ### 7.3 Definition inheritance
1218
+
1219
+ You can create more specialised versions of a generic definition by using inheritance. Assuming a generic state machine definition:
1220
+
1221
+ ```ruby
1222
+ class GenericStateMachine < FiniteMachine::Definition
1223
+ initial :red
1224
+
1225
+ events {
1226
+ event :start, :red => :green
1227
+ }
1228
+
1229
+ callbacks {
1230
+ on_enter { |event| ... }
1231
+ }
1232
+ end
1233
+ ```
1234
+
1235
+ we can easily create a more specifc definition that adds new event and more specifc callback to the mix.
1236
+
1237
+ ```ruby
1238
+ class SpecificStateMachine < GenericStateMachine
1239
+ events {
1240
+ event :stop, :green => :yellow
1241
+ }
1242
+
1243
+ callbacks {
1244
+ on_enter(:yellow) { |event| ... }
1245
+ }
1246
+ end
1247
+ ```
1248
+
1249
+ Finally to use the specific state machine definition do:
1250
+
1251
+ ```ruby
1252
+ specific_fsm = SpecificStateMachine.new
1253
+ specific_fsm.target ... # Target specific object
1254
+ ```
1255
+
1216
1256
  ## 8 Integration
1217
1257
 
1218
1258
  Since **FiniteMachine** is an object in its own right, it leaves integration with other systems up to you. In contrast to other Ruby libraries, it does not extend from models (i.e. ActiveRecord) to transform them into a state machine or require mixing into exisiting classes.
@@ -1318,7 +1358,7 @@ class Account < ActiveRecord::Base
1318
1358
 
1319
1359
  callbacks {
1320
1360
  on_enter do |event|
1321
- target.state = event.to
1361
+ target.state = state
1322
1362
  end
1323
1363
  }
1324
1364
  end
@@ -1363,4 +1403,4 @@ Creating a standalone **FiniteMachine** brings a number of benefits, one of them
1363
1403
 
1364
1404
  ## Copyright
1365
1405
 
1366
- Copyright (c) 2014 Piotr Murach. See LICENSE for further details.
1406
+ Copyright (c) 2014-2015 Piotr Murach. See LICENSE for further details.
@@ -15,6 +15,7 @@ require "finite_machine/choice_merger"
15
15
  require "finite_machine/async_proxy"
16
16
  require "finite_machine/async_call"
17
17
  require "finite_machine/hook_event"
18
+ require "finite_machine/env"
18
19
  require "finite_machine/event"
19
20
  require "finite_machine/event_builder"
20
21
  require "finite_machine/event_queue"
@@ -78,8 +79,6 @@ module FiniteMachine
78
79
  # Raised when argument is already defined
79
80
  AlreadyDefinedError = Class.new(::ArgumentError)
80
81
 
81
- Environment = Struct.new(:target, :aliases)
82
-
83
82
  class << self
84
83
  attr_accessor :logger
85
84
 
@@ -6,16 +6,16 @@ module FiniteMachine
6
6
  include Threadable
7
7
 
8
8
  # The context where choice is executed
9
- attr_threadsafe :context
9
+ attr_threadsafe :machine
10
10
 
11
- # The options passed in to the context
11
+ # The options passed in to the machine
12
12
  attr_threadsafe :options
13
13
 
14
14
  # Initialize a ChoiceMerger
15
15
  #
16
16
  # @api private
17
- def initialize(context, options)
18
- self.context = context
17
+ def initialize(machine, options)
18
+ self.machine = machine
19
19
  self.options = options
20
20
  end
21
21
 
@@ -36,7 +36,7 @@ module FiniteMachine
36
36
  def choice(to, attrs = {})
37
37
  opts = options.dup
38
38
  opts.merge!(attrs)
39
- transition_builder = TransitionBuilder.new(context.machine, opts)
39
+ transition_builder = TransitionBuilder.new(machine, opts)
40
40
  transition_builder.call(options[:from] => to)
41
41
  end
42
42
  alias_method :default, :choice
@@ -43,6 +43,15 @@ module FiniteMachine
43
43
  end
44
44
  end
45
45
 
46
+ # Set deferrerd methods on the subclass
47
+ #
48
+ # @api private
49
+ def self.inherited(subclass)
50
+ super
51
+
52
+ self.deferreds.each { |d| subclass.add_deferred(d) }
53
+ end
54
+
46
55
  # Delay lookup of DSL method
47
56
  #
48
57
  # @param [Symbol] method_name
@@ -22,9 +22,12 @@ module FiniteMachine
22
22
  self.machine = machine
23
23
  end
24
24
 
25
+ # Delegate attributes to machine instance
26
+ #
27
+ # @api private
25
28
  def method_missing(method_name, *args, &block)
26
- if @machine.respond_to?(method_name)
27
- @machine.send(method_name, *args, &block)
29
+ if machine.respond_to?(method_name)
30
+ machine.send(method_name, *args, &block)
28
31
  else
29
32
  super
30
33
  end
@@ -88,7 +91,7 @@ module FiniteMachine
88
91
  state = (value && !value.is_a?(Hash)) ? value : raise_missing_state
89
92
  name, self.defer, silent = parse(options)
90
93
  self.initial_event = name
91
- machine.event(name, FiniteMachine::DEFAULT_STATE => state, silent: silent)
94
+ event(name, FiniteMachine::DEFAULT_STATE => state, silent: silent)
92
95
  end
93
96
 
94
97
  # Trigger initial event
@@ -97,7 +100,7 @@ module FiniteMachine
97
100
  #
98
101
  # @api private
99
102
  def trigger_init
100
- machine.send(:"#{initial_event}") unless defer
103
+ public_send(:"#{initial_event}") unless defer
101
104
  end
102
105
 
103
106
  # Attach state machine to an object
@@ -117,9 +120,9 @@ module FiniteMachine
117
120
  # @api public
118
121
  def target(object = nil)
119
122
  if object.nil?
120
- machine.env.target
123
+ env.target
121
124
  else
122
- machine.env.target = object
125
+ env.target = object
123
126
  end
124
127
  end
125
128
 
@@ -141,7 +144,7 @@ module FiniteMachine
141
144
  #
142
145
  # @api public
143
146
  def alias_target(alias_name)
144
- machine.env.aliases << alias_name.to_sym
147
+ env.aliases << alias_name.to_sym
145
148
  end
146
149
 
147
150
  # Define terminal state
@@ -153,7 +156,7 @@ module FiniteMachine
153
156
  #
154
157
  # @api public
155
158
  def terminal(*values)
156
- machine.final_state = values
159
+ self.final_state = values
157
160
  end
158
161
 
159
162
  # Define state machine events
@@ -167,7 +170,7 @@ module FiniteMachine
167
170
  #
168
171
  # @api public
169
172
  def events(&block)
170
- machine.events_dsl.call(&block)
173
+ events_dsl.call(&block)
171
174
  end
172
175
 
173
176
  # Define state machine callbacks
@@ -181,21 +184,21 @@ module FiniteMachine
181
184
  #
182
185
  # @api public
183
186
  def callbacks(&block)
184
- machine.observer.call(&block)
187
+ observer.call(&block)
185
188
  end
186
189
 
187
190
  # Error handler that throws exception when machine is in illegal state
188
191
  #
189
192
  # @api public
190
193
  def handlers(&block)
191
- machine.errors.call(&block)
194
+ errors.call(&block)
192
195
  end
193
196
 
194
197
  # Decide whether to log transitions
195
198
  #
196
199
  # @api public
197
200
  def log_transitions(value)
198
- machine.log_transitions = value
201
+ self.log_transitions = value
199
202
  end
200
203
 
201
204
  private
@@ -256,7 +259,7 @@ module FiniteMachine
256
259
  sync_exclusive do
257
260
  attributes = attrs.merge!(name: name)
258
261
  if block_given?
259
- merger = ChoiceMerger.new(self, attributes)
262
+ merger = ChoiceMerger.new(machine, attributes)
260
263
  merger.instance_eval(&block)
261
264
  else
262
265
  transition_builder = TransitionBuilder.new(machine, attributes)
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module FiniteMachine
4
+ # Holds references to targets and aliases
5
+ #
6
+ # @api public
7
+ class Env
8
+ include Threadable
9
+
10
+ attr_threadsafe :target
11
+
12
+ attr_threadsafe :aliases
13
+
14
+ def initialize(target, aliases)
15
+ @target = target
16
+ @aliases = aliases
17
+ end
18
+ end # Env
19
+ end # FiniteMachine
@@ -62,12 +62,12 @@ module FiniteMachine
62
62
  attributes = args.last.is_a?(Hash) ? args.pop : {}
63
63
  @initial_state = DEFAULT_STATE
64
64
  @subscribers = Subscribers.new(self)
65
- @events_dsl = EventsDSL.new(self)
66
- @errors = ErrorsDSL.new(self)
67
65
  @observer = Observer.new(self)
68
66
  @transitions = Hash.new { |hash, name| hash[name] = Hash.new }
69
67
  @events_chain = EventsChain.new(self)
70
- @env = Environment.new(self, [])
68
+ @env = Env.new(self, [])
69
+ @events_dsl = EventsDSL.new(self)
70
+ @errors = ErrorsDSL.new(self)
71
71
  @dsl = DSL.new(self, attributes)
72
72
 
73
73
  @dsl.call(&block) if block_given?
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module FiniteMachine
4
- VERSION = "0.10.0"
4
+ VERSION = "0.10.1"
5
5
  end
data/spec/spec_helper.rb CHANGED
@@ -21,19 +21,12 @@ RSpec.configure do |config|
21
21
  config.run_all_when_everything_filtered = true
22
22
  config.filter_run :focus
23
23
  config.raise_errors_for_deprecations!
24
-
25
- # Run specs in random order to surface order dependencies. If you find an
26
- # order dependency and want to debug it, you can fix the order by providing
27
- # the seed, which is printed after each run.
28
- # --seed 1234
29
- config.order = 'random'
30
-
31
- # Remove defined constants
32
- config.before :each do
33
- [:Car, :DummyLogger, :Bug, :User, :Engine].each do |class_name|
34
- if Object.const_defined?(class_name)
35
- Object.send(:remove_const, class_name)
36
- end
37
- end
24
+ config.mock_with :rspec do |mocks|
25
+ mocks.verify_partial_doubles = true
26
+ end
27
+ config.disable_monkey_patching!
28
+ if config.files_to_run.one?
29
+ config.default_formatter = 'doc'
38
30
  end
31
+ config.order = :random
39
32
  end
@@ -2,10 +2,10 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Definition, '#alias_target' do
5
+ RSpec.describe FiniteMachine::Definition, '#alias_target' do
6
6
 
7
7
  before do
8
- Car = Class.new do
8
+ stub_const("Car", Class.new do
9
9
  def turn_reverse_lights_off
10
10
  @reverse_lights = false
11
11
  end
@@ -17,7 +17,7 @@ describe FiniteMachine::Definition, '#alias_target' do
17
17
  def reverse_lights?
18
18
  @reverse_lights ||= false
19
19
  end
20
- end
20
+ end)
21
21
  end
22
22
 
23
23
  it "aliases target" do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'async_events' do
5
+ RSpec.describe FiniteMachine, 'async_events' do
6
6
 
7
7
  it 'runs events asynchronously' do
8
8
  called = []
@@ -2,10 +2,10 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Callable, '#call' do
5
+ RSpec.describe FiniteMachine::Callable, '#call' do
6
6
 
7
7
  before(:each) {
8
- Car = Class.new do
8
+ stub_const("Car", Class.new do
9
9
  attr_reader :result
10
10
 
11
11
  def initialize
@@ -31,7 +31,7 @@ describe FiniteMachine::Callable, '#call' do
31
31
  @result = 'engine_on'
32
32
  !!@engine_on
33
33
  end
34
- end
34
+ end)
35
35
  }
36
36
 
37
37
  let(:called) { [] }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'callbacks' do
5
+ RSpec.describe FiniteMachine, 'callbacks' do
6
6
 
7
7
  it "triggers default init event" do
8
8
  called = []
@@ -2,13 +2,13 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'can?' do
5
+ RSpec.describe FiniteMachine, 'can?' do
6
6
  before(:each) {
7
- Bug = Class.new do
7
+ stub_const("Bug", Class.new do
8
8
  def pending?
9
9
  false
10
10
  end
11
- end
11
+ end)
12
12
  }
13
13
 
14
14
  it "allows to check if event can be fired" do
@@ -2,13 +2,13 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, '#choice' do
5
+ RSpec.describe FiniteMachine, '#choice' do
6
6
  before(:each) {
7
- User = Class.new do
7
+ stub_const("User", Class.new do
8
8
  def promo?(token = false)
9
9
  token == :yes
10
10
  end
11
- end
11
+ end)
12
12
  }
13
13
 
14
14
  it "allows for static choice based on conditional branching" do
@@ -185,6 +185,34 @@ describe FiniteMachine, '#choice' do
185
185
  expect(fsm.current).to eq(:green)
186
186
  end
187
187
 
188
+ it "performs matching transitions for multiple event definitions with the same name" do
189
+ ticket = double(:ticket, :pending? => true, :finished? => true)
190
+ fsm = FiniteMachine.define do
191
+ initial :inactive
192
+
193
+ target ticket
194
+
195
+ events {
196
+ event :advance, from: [:inactive, :paused, :fulfilled] do
197
+ choice :active, if: proc { |_ticket| !_ticket.pending? }
198
+ end
199
+
200
+ event :advance, from: [:inactive, :active, :fulfilled] do
201
+ choice :paused, if: proc { |_ticket| _ticket.pending? }
202
+ end
203
+
204
+ event :advance, from: [:inactive, :active, :paused] do
205
+ choice :fulfilled, if: proc { |_ticket| _ticket.finished? }
206
+ end
207
+ }
208
+ end
209
+ expect(fsm.current).to eq(:inactive)
210
+ fsm.advance
211
+ expect(fsm.current).to eq(:paused)
212
+ fsm.advance
213
+ expect(fsm.current).to eq(:fulfilled)
214
+ end
215
+
188
216
  it "sets callback properties correctly" do
189
217
  expected = {name: :init, from: :none, to: :red, a: nil, b: nil, c: nil }
190
218
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'define' do
5
+ RSpec.describe FiniteMachine, 'define' do
6
6
 
7
7
  context 'with block' do
8
8
  it "creates system state machine" do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Definition, 'definition' do
5
+ RSpec.describe FiniteMachine::Definition, 'definition' do
6
6
 
7
7
  before do
8
8
  class Engine < FiniteMachine::Definition
@@ -42,7 +42,7 @@ describe FiniteMachine::Definition, 'definition' do
42
42
  end
43
43
 
44
44
  it "allows to create standalone machine" do
45
- Car = Class.new do
45
+ stub_const("Car", Class.new do
46
46
  def turn_reverse_lights_off
47
47
  @reverse_lights = false
48
48
  end
@@ -54,7 +54,7 @@ describe FiniteMachine::Definition, 'definition' do
54
54
  def reverse_lights?
55
55
  @reverse_lights ||= false
56
56
  end
57
- end
57
+ end)
58
58
 
59
59
  car = Car.new
60
60
  engine = Engine.new
@@ -63,10 +63,53 @@ describe FiniteMachine::Definition, 'definition' do
63
63
 
64
64
  engine.forward
65
65
  expect(engine.current).to eq(:one)
66
- expect(car.reverse_lights?).to be false
66
+ expect(car.reverse_lights?).to eq(false)
67
67
 
68
68
  engine.back
69
69
  expect(engine.current).to eq(:reverse)
70
- expect(car.reverse_lights?).to be true
70
+ expect(car.reverse_lights?).to eq(true)
71
+ end
72
+
73
+ it "supports inheritance of definitions" do
74
+ class GenericStateMachine < FiniteMachine::Definition
75
+ initial :red
76
+
77
+ events {
78
+ event :start, :red => :green
79
+ }
80
+
81
+ callbacks {
82
+ on_enter { |event| target << 'generic' }
83
+ }
84
+ end
85
+
86
+ class SpecificStateMachine < GenericStateMachine
87
+ events {
88
+ event :stop, :green => :yellow
89
+ }
90
+
91
+ callbacks {
92
+ on_enter(:yellow) { |event| target << 'specific' }
93
+ }
94
+ end
95
+
96
+ generic_fsm = GenericStateMachine.new
97
+ specific_fsm = SpecificStateMachine.new
98
+ called = []
99
+ generic_fsm.target called
100
+ specific_fsm.target called
101
+
102
+ expect(generic_fsm.states).to match_array([:none, :red, :green])
103
+ expect(specific_fsm.states).to match_array([:none, :red, :green, :yellow])
104
+
105
+ expect(specific_fsm.current).to eq(:red)
106
+
107
+ specific_fsm.start
108
+ expect(specific_fsm.current).to eq(:green)
109
+ expect(called).to match_array(['generic'])
110
+
111
+ specific_fsm.stop
112
+ expect(specific_fsm.current).to eq(:yellow)
113
+ expect(called).to match_array(['generic', 'generic', 'specific'])
71
114
  end
72
115
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Event, '#<<' do
5
+ RSpec.describe FiniteMachine::Event, '#<<' do
6
6
  let(:machine) { double(:machine) }
7
7
 
8
8
  let(:object) { described_class }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Event, 'eql?' do
5
+ RSpec.describe FiniteMachine::Event, 'eql?' do
6
6
  let(:machine) { double(:machine) }
7
7
  let(:name) { :green }
8
8
  let(:options) { {} }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Event, 'new' do
5
+ RSpec.describe FiniteMachine::Event, 'new' do
6
6
  let(:machine) { double(:machine) }
7
7
  let(:name) { :green }
8
8
  let(:options) { {} }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Event, '#inspect' do
5
+ RSpec.describe FiniteMachine::Event, '#inspect' do
6
6
  let(:machine) { double(:machine) }
7
7
 
8
8
  let(:object) { described_class }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Event, '#next_transition' do
5
+ RSpec.describe FiniteMachine::Event, '#next_transition' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  subject(:event) { object.new(machine, name: :test) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::EventQueue do
5
+ RSpec.describe FiniteMachine::EventQueue do
6
6
 
7
7
  subject(:event_queue) { described_class.new }
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::EventsChain, '#clear' do
5
+ RSpec.describe FiniteMachine::EventsChain, '#clear' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  let(:machine) { double(:machine) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::EventsChain, '#insert' do
5
+ RSpec.describe FiniteMachine::EventsChain, '#insert' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  let(:machine) { double(:machine) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::EventsChain, '#insert' do
5
+ RSpec.describe FiniteMachine::EventsChain, '#insert' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  let(:machine) { double(:machine) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::EventsChain, '#insert' do
5
+ RSpec.describe FiniteMachine::EventsChain, '#insert' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  let(:machine) { double(:machine) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::EventsChain, '#select_transition' do
5
+ RSpec.describe FiniteMachine::EventsChain, '#select_transition' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  let(:machine) { double(:machine) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'events' do
5
+ RSpec.describe FiniteMachine, 'events' do
6
6
 
7
7
  it "allows for hash rocket syntax to describe transition" do
8
8
  fsm = FiniteMachine.define do
@@ -2,10 +2,10 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'handlers' do
5
+ RSpec.describe FiniteMachine, 'handlers' do
6
6
 
7
7
  before(:each) {
8
- DummyLogger = Class.new do
8
+ stub_const("DummyLogger", Class.new do
9
9
  attr_reader :result
10
10
 
11
11
  def log_error(exception)
@@ -15,7 +15,7 @@ describe FiniteMachine, 'handlers' do
15
15
  def raise_error
16
16
  raise FiniteMachine::TransitionError
17
17
  end
18
- end
18
+ end)
19
19
  }
20
20
 
21
21
  it "allows to customise error handling" do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::HookEvent, 'eql?' do
5
+ RSpec.describe FiniteMachine::HookEvent, 'eql?' do
6
6
  let(:name) { :green }
7
7
  let(:transition) { double(:transition) }
8
8
  let(:data) { [:foo, :bar] }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::HookEvent, 'new' do
5
+ RSpec.describe FiniteMachine::HookEvent, 'new' do
6
6
  let(:name) { :green }
7
7
  let(:transition) { double(:transition) }
8
8
  let(:data) { [:foo, :bar] }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Hooks, '#call' do
5
+ RSpec.describe FiniteMachine::Hooks, '#call' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  subject(:hooks) { object.new }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Hooks, '#inspect' do
5
+ RSpec.describe FiniteMachine::Hooks, '#inspect' do
6
6
  subject(:hooks) { described_class.new }
7
7
 
8
8
  it "displays name and transitions" do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Hooks, '#register' do
5
+ RSpec.describe FiniteMachine::Hooks, '#register' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  subject(:hooks) { object.new }
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, ':if, :unless' do
5
+ RSpec.describe FiniteMachine, ':if, :unless' do
6
6
  before(:each) {
7
- Car = Class.new do
7
+ stub_const("Car", Class.new do
8
8
  attr_accessor :engine_on
9
9
 
10
10
  def turn_engine_on
@@ -18,13 +18,13 @@ describe FiniteMachine, ':if, :unless' do
18
18
  def engine_on?
19
19
  !!@engine_on
20
20
  end
21
- end
21
+ end)
22
22
 
23
- class Bug
23
+ stub_const("Bug", Class.new do
24
24
  def pending?
25
25
  false
26
26
  end
27
- end
27
+ end)
28
28
  }
29
29
 
30
30
  it "passes context to conditionals" do
@@ -2,16 +2,16 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'initialize' do
5
+ RSpec.describe FiniteMachine, 'initialize' do
6
6
 
7
7
  before(:each) {
8
- DummyLogger = Class.new do
8
+ stub_const("DummyLogger", Class.new do
9
9
  attr_accessor :level
10
10
 
11
11
  def initialize
12
12
  @level = :pending
13
13
  end
14
- end
14
+ end)
15
15
  }
16
16
 
17
17
  it "defaults initial state to :none" do
@@ -2,8 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, '#inspect' do
6
-
5
+ RSpec.describe FiniteMachine, '#inspect' do
7
6
  it "print useful information about state machine" do
8
7
  fsm = FiniteMachine.define do
9
8
  initial :green
data/spec/unit/is_spec.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'is?' do
5
+ RSpec.describe FiniteMachine, 'is?' do
6
6
 
7
7
  it "allows to check if state is reachable" do
8
8
  fsm = FiniteMachine.define do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'log_transitions' do
5
+ RSpec.describe FiniteMachine, 'log_transitions' do
6
6
  let(:output) { StringIO.new('', 'w+')}
7
7
 
8
8
  before { FiniteMachine.logger = ::Logger.new(output) }
@@ -1,9 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
- require 'logger'
5
4
 
6
- describe FiniteMachine::Logger do
5
+ RSpec.describe FiniteMachine::Logger do
7
6
  let(:message) { 'error' }
8
7
  let(:log) { double }
9
8
 
@@ -2,14 +2,15 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, '#respond_to' do
5
+ RSpec.describe FiniteMachine, '#respond_to' do
6
6
 
7
7
  subject(:fsm) {
8
- Car = Class.new do
8
+ stub_const("Car", Class.new do
9
9
  def engine_on?
10
10
  true
11
11
  end
12
- end
12
+ end)
13
+
13
14
  FiniteMachine.new target: Car.new do
14
15
  initial :green
15
16
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::StateParser, "#inspect" do
5
+ RSpec.describe FiniteMachine::StateParser, "#inspect" do
6
6
  let(:object) { described_class }
7
7
 
8
8
  subject(:parser) { object.new(attrs) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::StateParser, '#inspect' do
5
+ RSpec.describe FiniteMachine::StateParser, '#inspect' do
6
6
  let(:object) { described_class }
7
7
 
8
8
  subject(:parser) { object.new(attrs) }
@@ -2,8 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'states' do
6
-
5
+ RSpec.describe FiniteMachine, 'states' do
7
6
  it "retrieves all available states" do
8
7
  fsm = FiniteMachine.define do
9
8
  initial :green
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Subscribers do
5
+ RSpec.describe FiniteMachine::Subscribers do
6
6
  let(:machine) { double }
7
7
  let(:event) { double }
8
8
  let(:listener) { double }
@@ -2,10 +2,9 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, '#target' do
6
-
5
+ RSpec.describe FiniteMachine, '#target' do
7
6
  it "allows to target external object" do
8
- Car = Class.new do
7
+ stub_const("Car", Class.new do
9
8
  attr_accessor :reverse_lights
10
9
 
11
10
  def turn_reverse_lights_off
@@ -45,7 +44,7 @@ describe FiniteMachine, '#target' do
45
44
  }
46
45
  end
47
46
  end
48
- end
47
+ end)
49
48
  car = Car.new
50
49
  expect(car.reverse_lights?).to be(false)
51
50
  expect(car.engine.current).to eql(:neutral)
@@ -104,7 +103,7 @@ describe FiniteMachine, '#target' do
104
103
  end
105
104
 
106
105
  it "allows context methods take precedence over machine ones" do
107
- Car = Class.new do
106
+ stub_const("Car", Class.new do
108
107
  attr_accessor :reverse_lights
109
108
  attr_accessor :called
110
109
 
@@ -147,7 +146,7 @@ describe FiniteMachine, '#target' do
147
146
  }
148
147
  end
149
148
  end
150
- end
149
+ end)
151
150
 
152
151
  car = Car.new
153
152
  expect(car.reverse_lights?).to be(false)
@@ -185,14 +184,14 @@ describe FiniteMachine, '#target' do
185
184
 
186
185
  it "allows to differentiate between same named methods" do
187
186
  called = []
188
- Car = Class.new do
187
+ stub_const("Car", Class.new do
189
188
  def initialize(called)
190
189
  @called = called
191
190
  end
192
191
  def save
193
192
  @called << 'car save called'
194
193
  end
195
- end
194
+ end)
196
195
 
197
196
  car = Car.new(called)
198
197
  fsm = FiniteMachine.define do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine, 'terminated?' do
5
+ RSpec.describe FiniteMachine, 'terminated?' do
6
6
 
7
7
  it "allows to specify terminal state" do
8
8
  fsm = FiniteMachine.define do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Transition, '#inspect' do
5
+ RSpec.describe FiniteMachine::Transition, '#inspect' do
6
6
  let(:machine) { double(:machine) }
7
7
 
8
8
  subject(:transition) { described_class.new(machine, attrs) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe FiniteMachine::Transition, 'parsed_states' do
5
+ RSpec.describe FiniteMachine::Transition, 'parsed_states' do
6
6
  let(:machine) { double(:machine) }
7
7
 
8
8
  subject(:transition) { described_class.new(machine, attrs) }
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.10.0
4
+ version: 0.10.1
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-11-16 00:00:00.000000000 Z
11
+ date: 2015-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -54,6 +54,7 @@ files:
54
54
  - lib/finite_machine/choice_merger.rb
55
55
  - lib/finite_machine/definition.rb
56
56
  - lib/finite_machine/dsl.rb
57
+ - lib/finite_machine/env.rb
57
58
  - lib/finite_machine/event.rb
58
59
  - lib/finite_machine/event_builder.rb
59
60
  - lib/finite_machine/event_queue.rb