statesman 1.3.1 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGELOG.md +45 -19
- data/README.md +20 -11
- data/lib/generators/statesman/templates/active_record_transition_model.rb.erb +10 -0
- data/lib/statesman/adapters/active_record.rb +9 -10
- data/lib/statesman/adapters/active_record_queries.rb +3 -63
- data/lib/statesman/adapters/memory.rb +2 -2
- data/lib/statesman/adapters/mongoid.rb +7 -3
- data/lib/statesman/machine.rb +14 -53
- data/lib/statesman/version.rb +1 -1
- data/spec/spec_helper.rb +18 -11
- data/spec/statesman/adapters/active_record_queries_spec.rb +45 -119
- data/spec/statesman/adapters/active_record_spec.rb +43 -14
- data/spec/statesman/adapters/shared_examples.rb +5 -2
- data/spec/statesman/machine_spec.rb +55 -122
- data/spec/support/active_record.rb +28 -4
- data/statesman.gemspec +1 -1
- metadata +39 -49
- data/circle.yml +0 -9
- data/lib/generators/statesman/add_constraints_to_most_recent_generator.rb +0 -28
- data/lib/generators/statesman/add_most_recent_generator.rb +0 -25
- data/lib/generators/statesman/templates/add_constraints_to_most_recent_migration.rb.erb +0 -19
- data/lib/generators/statesman/templates/add_most_recent_migration.rb.erb +0 -9
- data/lib/statesman/event_transitions.rb +0 -15
- data/spec/generators/statesman/add_constraints_to_most_recent_generator_spec.rb +0 -43
- data/spec/generators/statesman/add_most_recent_generator_spec.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13d0c38a0446c311aa3db3796688736d190a5643
|
4
|
+
data.tar.gz: e13b4b046fe10b8f5dbf07234145b9d75c0b74b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ff647a35fe9d98698eae14af6ea89af302d0766da3e6cc7c0a7d920be59fce95782524f19eb58f534f50d8ce4b734c26213642372b02770984454c85f799d43
|
7
|
+
data.tar.gz: 082b90d40ea27a482654bfd4d57d48ee089d6f26bd92633b594678bfa75ed9e2024e57ed8213714a2a255d3ec231a29e9326d05e2f94013f4b58a881273403dd
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,33 +1,59 @@
|
|
1
|
-
##
|
1
|
+
## v2.0.0.rc1, 23 December 2015
|
2
|
+
|
3
|
+
*Breaking changes*
|
4
|
+
|
5
|
+
- Unset most_recent after before transitions
|
6
|
+
- TL;DR: set `autosave: false` on the `has_many` association between your parent and transition model and this change will almost certainly not affect your integration
|
7
|
+
- Previously the `most_recent` flag would be set to `false` on all transitions during any `before_transition` callbacks
|
8
|
+
- After this change, the `most_recent` flag will still be `true` for the previous transition during these callbacks
|
9
|
+
- Whilst this behaviour is almost certainly what your integration already expected, as a result of it any attempt to save the new, as yet unpersisted, transition during a `before_transition` callback will result in a uniqueness error. In particular, if you have not set `autosave: false` on the `has_many` association between your parent and transition model then any attempt to save the parent model during a `before_transition` will result in an error
|
10
|
+
- Require a most_recent column on transition tables
|
11
|
+
- The `most_recent` column, added in v1.2.0, is now required on all transition tables
|
12
|
+
- This greatly speeds up queries on large tables
|
13
|
+
- A zero-downtime migration path is outlined in the changelog for v1.2.0. You should use that migration path **before** upgrading to v2.0.0
|
14
|
+
- Increase default initial sort key to 10
|
15
|
+
- Drop support for Ruby 1.9.3, which reached end-of-life in February 2015
|
16
|
+
- Move support for events to a companion gem
|
17
|
+
- Previously, Statesman supported the use of "events" to trigger transitions
|
18
|
+
- To keep Statesman lightweight we've moved event functionality into the `statesman-events` gem
|
19
|
+
- If you are using events, add `statesman-events` to your gemfile and include `Statesman::Events` in your state machines
|
20
|
+
|
21
|
+
*Changes*
|
22
|
+
|
23
|
+
- Add after_destroy hook to ActiveRecord transition model templates
|
24
|
+
- Add `in_state?` instance method to `Statesman::Machine`
|
25
|
+
- Add `force_reload` option to `Statesman::Machine#last_transition`
|
26
|
+
|
27
|
+
## v1.3.1, 2 July 2015
|
2
28
|
|
3
29
|
- Fix `in_state` queries with a custom `transition_name` (patch by [0tsuki](https://github.com/0tsuki))
|
4
|
-
- Fix `backfill_most_recent` rake
|
30
|
+
- Fix `backfill_most_recent` rake task for databases that support partial indexes (patch by [greysteil](https://github.com/greysteil))
|
5
31
|
|
6
|
-
## v1.3.0 20 June 2015
|
32
|
+
## v1.3.0, 20 June 2015
|
7
33
|
|
8
34
|
- Rename `last_transition` alias in `ActiveRecordQueries` to `most_recent_#{model_name}`, to allow merging of two such queries (patch by [@isaacseymour](https://github.com/isaacseymour))
|
9
35
|
|
10
|
-
## v1.2.5 17 June 2015
|
36
|
+
## v1.2.5, 17 June 2015
|
11
37
|
|
12
38
|
- Make `backfill_most_recent` rake task db-agnostic (patch by [@timothyp](https://github.com/timothyp))
|
13
39
|
|
14
|
-
## v1.2.4 16 June 2015
|
40
|
+
## v1.2.4, 16 June 2015
|
15
41
|
|
16
42
|
- Clarify error messages when misusing `Statesman::Adapters::ActiveRecordTransition` (patch by [@isaacseymour](https://github.com/isaacseymour))
|
17
43
|
|
18
|
-
## v1.2.3 14 April 2015
|
44
|
+
## v1.2.3, 14 April 2015
|
19
45
|
|
20
46
|
- Fix use of most_recent column in MySQL (partial indexes aren't supported) (patch by [@greysteil](https://github.com/greysteil))
|
21
47
|
|
22
|
-
## v1.2.2 24 March 2015
|
48
|
+
## v1.2.2, 24 March 2015
|
23
49
|
|
24
50
|
- Add support for namespaced transition models (patch by [@DanielWright](https://github.com/DanielWright))
|
25
51
|
|
26
|
-
## v1.2.1 24 March 2015
|
52
|
+
## v1.2.1, 24 March 2015
|
27
53
|
|
28
54
|
- Add support for Postgres 9.4's `jsonb` column type (patch by [@isaacseymour](https://github.com/isaacseymour))
|
29
55
|
|
30
|
-
## v1.2.0 18 March 2015
|
56
|
+
## v1.2.0, 18 March 2015
|
31
57
|
|
32
58
|
*Changes*
|
33
59
|
|
@@ -41,7 +67,7 @@
|
|
41
67
|
- `ActiveRecordQueries.{not_,}in_state` now accepts an array of states.
|
42
68
|
|
43
69
|
|
44
|
-
## v1.1.0 9 December 2014
|
70
|
+
## v1.1.0, 9 December 2014
|
45
71
|
*Fixes*
|
46
72
|
|
47
73
|
- Support for Rails 4.2.0.rc2:
|
@@ -53,16 +79,16 @@
|
|
53
79
|
|
54
80
|
- Transition metadata now defaults to `{}` rather than `nil`. (patch by [@greysteil](https://github.com/greysteil))
|
55
81
|
|
56
|
-
## v1.0.0 21 November 2014
|
82
|
+
## v1.0.0, 21 November 2014
|
57
83
|
|
58
84
|
No changes from v1.0.0.beta2
|
59
85
|
|
60
|
-
## v1.0.0.beta2 10 October 2014
|
86
|
+
## v1.0.0.beta2, 10 October 2014
|
61
87
|
*Breaking changes*
|
62
88
|
|
63
89
|
- Rename `ActiveRecordModel` to `ActiveRecordQueries`, to reflect the fact that it mixes in some helpful scopes, but is not required.
|
64
90
|
|
65
|
-
## v1.0.0.beta1 9 October 2014
|
91
|
+
## v1.0.0.beta1, 9 October 2014
|
66
92
|
*Breaking changes*
|
67
93
|
|
68
94
|
- Classes which include `ActiveRecordModel` must define an `initial_state` class method.
|
@@ -76,33 +102,33 @@ No changes from v1.0.0.beta2
|
|
76
102
|
- Transition tables created by generated migrations have `NOT NULL` constraints on `to_state`, `sort_key` and foreign key columns (patch by [@greysteil](https://github.com/greysteil))
|
77
103
|
- `before_transition` and `after_transition` allow an array of to states (patch by [@isaacseymour](https://github.com/isaacseymour))
|
78
104
|
|
79
|
-
## v0.8.3 2 September 2014
|
105
|
+
## v0.8.3, 2 September 2014
|
80
106
|
*Fixes*
|
81
107
|
|
82
108
|
- Optimisation for Machine#available_events (patch by [@pacso](https://github.com/pacso))
|
83
109
|
|
84
|
-
## v0.8.2 2 September 2014
|
110
|
+
## v0.8.2, 2 September 2014
|
85
111
|
*Fixes*
|
86
112
|
|
87
113
|
- Stop generating a default value for the metadata column if using MySQL.
|
88
114
|
|
89
|
-
## v0.8.1 19 August 2014
|
115
|
+
## v0.8.1, 19 August 2014
|
90
116
|
*Fixes*
|
91
117
|
|
92
118
|
- Adds check in Machine#transition to make sure the 'to' state is not an empty array (patch by [@barisbalic](https://github.com/barisbalic))
|
93
119
|
|
94
|
-
## v0.8.0 29 June 2014
|
120
|
+
## v0.8.0, 29 June 2014
|
95
121
|
*Additions*
|
96
122
|
|
97
123
|
- Events. Machines can now define events as a logical grouping of transitions (patch by [@iurimatias](https://github.com/iurimatias))
|
98
124
|
- Retries. Individual transitions can be executed with a retry policy by wrapping the method call in a `Machine.retry_conflicts {}` block (patch by [@greysteil](https://github.com/greysteil))
|
99
125
|
|
100
|
-
## v0.7.0 25 June 2014
|
126
|
+
## v0.7.0, 25 June 2014
|
101
127
|
*Additions*
|
102
128
|
|
103
129
|
- `Adapters::ActiveRecord` now handles `ActiveRecord::RecordNotUnique` errors explicitly and re-raises with a `Statesman::TransitionConflictError` if it is due to duplicate sort_keys (patch by [@greysteil](https://github.com/greysteil))
|
104
130
|
|
105
|
-
## v0.6.1 21 May 2014
|
131
|
+
## v0.6.1, 21 May 2014
|
106
132
|
*Fixes*
|
107
133
|
- Fixes an issue where the wrong transition was passed to after_transition callbacks for the second and subsequent transition of a given state machine (patch by [@alan](https://github.com/alan))
|
108
134
|
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
![Statesman](http://f.cl.ly/items/410n2A0S3l1W0i3i0o2K/statesman.png)
|
2
2
|
|
3
|
-
A statesmanlike state machine library for Ruby
|
3
|
+
A statesmanlike state machine library for Ruby 2.0.0 and up.
|
4
4
|
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/statesman.png)](http://badge.fury.io/rb/statesman)
|
6
6
|
[![Build Status](https://travis-ci.org/gocardless/statesman.png?branch=master)](https://travis-ci.org/gocardless/statesman)
|
@@ -68,7 +68,7 @@ end
|
|
68
68
|
class Order < ActiveRecord::Base
|
69
69
|
include Statesman::Adapters::ActiveRecordQueries
|
70
70
|
|
71
|
-
has_many :order_transitions
|
71
|
+
has_many :order_transitions, autosave: false
|
72
72
|
|
73
73
|
def state_machine
|
74
74
|
@state_machine ||= OrderStateMachine.new(self, transition_class: OrderTransition)
|
@@ -134,7 +134,7 @@ And add an association from the parent model:
|
|
134
134
|
|
135
135
|
```ruby
|
136
136
|
class Order < ActiveRecord::Base
|
137
|
-
has_many :transitions, class_name: "OrderTransition"
|
137
|
+
has_many :transitions, class_name: "OrderTransition", autosave: false
|
138
138
|
|
139
139
|
# Initialize the state machine
|
140
140
|
def state_machine
|
@@ -255,6 +255,9 @@ number of retry attempts (defaults to 1).
|
|
255
255
|
#### `Machine#current_state`
|
256
256
|
Returns the current state based on existing transition objects.
|
257
257
|
|
258
|
+
### `Machine#in_state?(:state_1, :state_2, ...)`
|
259
|
+
Returns true if the machine is in any of the given states.
|
260
|
+
|
258
261
|
#### `Machine#history`
|
259
262
|
Returns a sorted array of all transition objects.
|
260
263
|
|
@@ -304,7 +307,7 @@ need to define a corresponding `transition_name` class method:
|
|
304
307
|
|
305
308
|
```ruby
|
306
309
|
class Order < ActiveRecord::Base
|
307
|
-
has_many :transitions, class_name: "OrderTransition"
|
310
|
+
has_many :transitions, class_name: "OrderTransition", autosave: false
|
308
311
|
|
309
312
|
private
|
310
313
|
|
@@ -352,15 +355,21 @@ Given a field `foo` that was stored in the metadata, you can access it like so:
|
|
352
355
|
model_instance.last_transition.metadata["foo"]
|
353
356
|
```
|
354
357
|
|
355
|
-
####
|
358
|
+
#### Events
|
356
359
|
|
357
|
-
|
358
|
-
|
360
|
+
Used to using a state machine with "events"? Support for events is provided by
|
361
|
+
the [statesman-events](https://github.com/gocardless/statesman-events) gem. Once
|
362
|
+
that's included in your Gemfile you can include event functionality in your
|
363
|
+
state machine as follows:
|
359
364
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
365
|
+
```ruby
|
366
|
+
class OrderStateMachine
|
367
|
+
include Statesman::Machine
|
368
|
+
include Statesman::Events
|
369
|
+
|
370
|
+
...
|
371
|
+
end
|
372
|
+
```
|
364
373
|
|
365
374
|
## Testing Statesman Implementations
|
366
375
|
|
@@ -5,4 +5,14 @@ class <%= klass %> < ActiveRecord::Base
|
|
5
5
|
attr_accessible :to_state, :metadata, :sort_key
|
6
6
|
<% end %>
|
7
7
|
belongs_to :<%= parent_name %><%= class_name_option %>, inverse_of: :<%= table_name %>
|
8
|
+
|
9
|
+
after_destroy :update_most_recent, if: :most_recent?
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def update_most_recent
|
14
|
+
last_transition = <%= parent_name %>.<%= table_name %>.order(:sort_key).last
|
15
|
+
return unless last_transition.present?
|
16
|
+
last_transition.update_column(:most_recent, true)
|
17
|
+
end
|
8
18
|
end
|
@@ -51,8 +51,12 @@ module Statesman
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
def last
|
55
|
-
|
54
|
+
def last(force_reload: false)
|
55
|
+
if force_reload
|
56
|
+
@last_transition = history.last
|
57
|
+
else
|
58
|
+
@last_transition ||= history.last
|
59
|
+
end
|
56
60
|
end
|
57
61
|
|
58
62
|
private
|
@@ -62,13 +66,13 @@ module Statesman
|
|
62
66
|
sort_key: next_sort_key,
|
63
67
|
metadata: metadata }
|
64
68
|
|
65
|
-
transition_attributes.merge!(most_recent: true)
|
69
|
+
transition_attributes.merge!(most_recent: true)
|
66
70
|
|
67
71
|
transition = transitions_for_parent.build(transition_attributes)
|
68
72
|
|
69
73
|
::ActiveRecord::Base.transaction do
|
70
|
-
unset_old_most_recent
|
71
74
|
@observer.execute(:before, from, to, transition)
|
75
|
+
unset_old_most_recent
|
72
76
|
transition.save!
|
73
77
|
@last_transition = transition
|
74
78
|
@observer.execute(:after, from, to, transition)
|
@@ -83,7 +87,6 @@ module Statesman
|
|
83
87
|
end
|
84
88
|
|
85
89
|
def unset_old_most_recent
|
86
|
-
return unless most_recent_column?
|
87
90
|
# Check whether the `most_recent` column allows null values. If it
|
88
91
|
# doesn't, set old records to `false`, otherwise, set them to `NULL`.
|
89
92
|
#
|
@@ -98,12 +101,8 @@ module Statesman
|
|
98
101
|
end
|
99
102
|
end
|
100
103
|
|
101
|
-
def most_recent_column?
|
102
|
-
transition_class.columns_hash.include?("most_recent")
|
103
|
-
end
|
104
|
-
|
105
104
|
def next_sort_key
|
106
|
-
(last && last.sort_key + 10) ||
|
105
|
+
(last && last.sort_key + 10) || 10
|
107
106
|
end
|
108
107
|
|
109
108
|
def serialized?(transition_class)
|
@@ -9,50 +9,19 @@ module Statesman
|
|
9
9
|
def in_state(*states)
|
10
10
|
states = states.flatten.map(&:to_s)
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
in_state_without_most_recent(states)
|
16
|
-
end
|
12
|
+
joins(most_recent_transition_join).
|
13
|
+
where(states_where(most_recent_transition_alias, states), states)
|
17
14
|
end
|
18
15
|
|
19
16
|
def not_in_state(*states)
|
20
17
|
states = states.flatten.map(&:to_s)
|
21
18
|
|
22
|
-
if use_most_recent_column?
|
23
|
-
not_in_state_with_most_recent(states)
|
24
|
-
else
|
25
|
-
not_in_state_without_most_recent(states)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def in_state_with_most_recent(states)
|
32
|
-
joins(most_recent_transition_join).
|
33
|
-
where(states_where(most_recent_transition_alias, states), states)
|
34
|
-
end
|
35
|
-
|
36
|
-
def not_in_state_with_most_recent(states)
|
37
19
|
joins(most_recent_transition_join).
|
38
20
|
where("NOT (#{states_where(most_recent_transition_alias, states)})",
|
39
21
|
states)
|
40
22
|
end
|
41
23
|
|
42
|
-
|
43
|
-
joins(transition1_join).
|
44
|
-
joins(transition2_join).
|
45
|
-
where(states_where(most_recent_transition_alias, states), states).
|
46
|
-
where("#{other_transition_alias}.id" => nil)
|
47
|
-
end
|
48
|
-
|
49
|
-
def not_in_state_without_most_recent(states)
|
50
|
-
joins(transition1_join).
|
51
|
-
joins(transition2_join).
|
52
|
-
where("NOT (#{states_where(most_recent_transition_alias, states)})",
|
53
|
-
states).
|
54
|
-
where("#{other_transition_alias}.id" => nil)
|
55
|
-
end
|
24
|
+
private
|
56
25
|
|
57
26
|
def transition_class
|
58
27
|
raise NotImplementedError, "A transition_class method should be " \
|
@@ -80,20 +49,6 @@ module Statesman
|
|
80
49
|
transition_reflection.table_name
|
81
50
|
end
|
82
51
|
|
83
|
-
def transition1_join
|
84
|
-
"LEFT OUTER JOIN #{model_table} #{most_recent_transition_alias}
|
85
|
-
ON #{most_recent_transition_alias}.#{model_foreign_key} =
|
86
|
-
#{table_name}.id"
|
87
|
-
end
|
88
|
-
|
89
|
-
def transition2_join
|
90
|
-
"LEFT OUTER JOIN #{model_table} #{other_transition_alias}
|
91
|
-
ON #{other_transition_alias}.#{model_foreign_key} =
|
92
|
-
#{table_name}.id
|
93
|
-
AND #{other_transition_alias}.sort_key >
|
94
|
-
#{most_recent_transition_alias}.sort_key"
|
95
|
-
end
|
96
|
-
|
97
52
|
def most_recent_transition_join
|
98
53
|
"LEFT OUTER JOIN #{model_table} AS #{most_recent_transition_alias}
|
99
54
|
ON #{table_name}.id =
|
@@ -115,24 +70,9 @@ module Statesman
|
|
115
70
|
"most_recent_#{transition_name.to_s.singularize}"
|
116
71
|
end
|
117
72
|
|
118
|
-
def other_transition_alias
|
119
|
-
"other_#{transition_name.to_s.singularize}"
|
120
|
-
end
|
121
|
-
|
122
73
|
def db_true
|
123
74
|
::ActiveRecord::Base.connection.quote(true)
|
124
75
|
end
|
125
|
-
|
126
|
-
# Only use the most_recent column if it has a unique index guaranteeing
|
127
|
-
# it has good data
|
128
|
-
def use_most_recent_column?
|
129
|
-
::ActiveRecord::Base.connection.index_exists?(
|
130
|
-
transition_class.table_name,
|
131
|
-
[model_foreign_key, :most_recent],
|
132
|
-
unique: true,
|
133
|
-
name: "index_#{transition_class.table_name}_parent_most_recent"
|
134
|
-
)
|
135
|
-
end
|
136
76
|
end
|
137
77
|
end
|
138
78
|
end
|
@@ -28,14 +28,14 @@ module Statesman
|
|
28
28
|
transition
|
29
29
|
end
|
30
30
|
|
31
|
-
def last
|
31
|
+
def last(*)
|
32
32
|
@history.sort_by(&:sort_key).last
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
37
|
def next_sort_key
|
38
|
-
(last && last.sort_key + 10) ||
|
38
|
+
(last && last.sort_key + 10) || 10
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -36,8 +36,12 @@ module Statesman
|
|
36
36
|
transitions_for_parent.asc(:sort_key)
|
37
37
|
end
|
38
38
|
|
39
|
-
def last
|
40
|
-
|
39
|
+
def last(force_reload: false)
|
40
|
+
if force_reload
|
41
|
+
@last_transition = history.last
|
42
|
+
else
|
43
|
+
@last_transition ||= history.last
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
43
47
|
private
|
@@ -55,7 +59,7 @@ module Statesman
|
|
55
59
|
end
|
56
60
|
|
57
61
|
def next_sort_key
|
58
|
-
(last && last.sort_key + 10) ||
|
62
|
+
(last && last.sort_key + 10) || 10
|
59
63
|
end
|
60
64
|
end
|
61
65
|
end
|
data/lib/statesman/machine.rb
CHANGED
@@ -2,7 +2,6 @@ require_relative "version"
|
|
2
2
|
require_relative "exceptions"
|
3
3
|
require_relative "guard"
|
4
4
|
require_relative "callback"
|
5
|
-
require_relative "event_transitions"
|
6
5
|
require_relative "adapters/memory_transition"
|
7
6
|
|
8
7
|
module Statesman
|
@@ -32,10 +31,6 @@ module Statesman
|
|
32
31
|
@states ||= []
|
33
32
|
end
|
34
33
|
|
35
|
-
def events
|
36
|
-
@events ||= {}
|
37
|
-
end
|
38
|
-
|
39
34
|
def state(name, options = { initial: false })
|
40
35
|
name = name.to_s
|
41
36
|
if options[:initial]
|
@@ -45,10 +40,6 @@ module Statesman
|
|
45
40
|
states << name
|
46
41
|
end
|
47
42
|
|
48
|
-
def event(name, &block)
|
49
|
-
EventTransitions.new(self, name, &block)
|
50
|
-
end
|
51
|
-
|
52
43
|
def successors
|
53
44
|
@successors ||= {}
|
54
45
|
end
|
@@ -62,9 +53,9 @@ module Statesman
|
|
62
53
|
}
|
63
54
|
end
|
64
55
|
|
65
|
-
def transition(
|
66
|
-
from = to_s_or_nil(
|
67
|
-
to = array_to_s_or_nil(
|
56
|
+
def transition(from: nil, to: nil)
|
57
|
+
from = to_s_or_nil(from)
|
58
|
+
to = array_to_s_or_nil(to)
|
68
59
|
|
69
60
|
raise InvalidStateError, "No to states provided." if to.empty?
|
70
61
|
|
@@ -73,12 +64,6 @@ module Statesman
|
|
73
64
|
([from] + to).each { |state| validate_state(state) }
|
74
65
|
|
75
66
|
successors[from] += to
|
76
|
-
|
77
|
-
if event
|
78
|
-
events[event] ||= {}
|
79
|
-
events[event][from] ||= []
|
80
|
-
events[event][from] += to
|
81
|
-
end
|
82
67
|
end
|
83
68
|
|
84
69
|
def before_transition(options = { from: nil, to: nil }, &block)
|
@@ -177,9 +162,9 @@ module Statesman
|
|
177
162
|
end
|
178
163
|
|
179
164
|
def initialize(object,
|
180
|
-
|
181
|
-
|
182
|
-
|
165
|
+
options = {
|
166
|
+
transition_class: Statesman::Adapters::MemoryTransition
|
167
|
+
})
|
183
168
|
@object = object
|
184
169
|
@transition_class = options[:transition_class]
|
185
170
|
@storage_adapter = adapter_class(@transition_class).new(
|
@@ -187,19 +172,23 @@ module Statesman
|
|
187
172
|
send(:after_initialize) if respond_to? :after_initialize
|
188
173
|
end
|
189
174
|
|
190
|
-
def current_state
|
191
|
-
last_action = last_transition
|
175
|
+
def current_state(force_reload: false)
|
176
|
+
last_action = last_transition(force_reload: force_reload)
|
192
177
|
last_action ? last_action.to_state : self.class.initial_state
|
193
178
|
end
|
194
179
|
|
180
|
+
def in_state?(*states)
|
181
|
+
states.flatten.any? { |state| current_state == state.to_s }
|
182
|
+
end
|
183
|
+
|
195
184
|
def allowed_transitions
|
196
185
|
successors_for(current_state).select do |state|
|
197
186
|
can_transition_to?(state)
|
198
187
|
end
|
199
188
|
end
|
200
189
|
|
201
|
-
def last_transition
|
202
|
-
@storage_adapter.last
|
190
|
+
def last_transition(force_reload: false)
|
191
|
+
@storage_adapter.last(force_reload: force_reload)
|
203
192
|
end
|
204
193
|
|
205
194
|
def can_transition_to?(new_state, metadata = {})
|
@@ -228,21 +217,6 @@ module Statesman
|
|
228
217
|
true
|
229
218
|
end
|
230
219
|
|
231
|
-
def trigger!(event_name, metadata = {})
|
232
|
-
transitions = self.class.events.fetch(event_name) do
|
233
|
-
raise Statesman::TransitionFailedError,
|
234
|
-
"Event #{event_name} not found"
|
235
|
-
end
|
236
|
-
|
237
|
-
new_state = transitions.fetch(current_state) do
|
238
|
-
raise Statesman::TransitionFailedError,
|
239
|
-
"State #{current_state} not found for Event #{event_name}"
|
240
|
-
end
|
241
|
-
|
242
|
-
transition_to!(new_state.first, metadata)
|
243
|
-
true
|
244
|
-
end
|
245
|
-
|
246
220
|
def execute(phase, initial_state, new_state, transition)
|
247
221
|
callbacks = callbacks_for(phase, from: initial_state, to: new_state)
|
248
222
|
callbacks.each { |cb| cb.call(@object, transition) }
|
@@ -254,19 +228,6 @@ module Statesman
|
|
254
228
|
false
|
255
229
|
end
|
256
230
|
|
257
|
-
def trigger(event_name, metadata = {})
|
258
|
-
self.trigger!(event_name, metadata)
|
259
|
-
rescue TransitionFailedError, GuardFailedError
|
260
|
-
false
|
261
|
-
end
|
262
|
-
|
263
|
-
def available_events
|
264
|
-
state = current_state
|
265
|
-
self.class.events.select do |_, transitions|
|
266
|
-
transitions.key?(state)
|
267
|
-
end.map(&:first)
|
268
|
-
end
|
269
|
-
|
270
231
|
private
|
271
232
|
|
272
233
|
def adapter_class(transition_class)
|