statesman 1.3.1 → 2.0.0.rc1
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 +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
|

|
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
|
[](http://badge.fury.io/rb/statesman)
|
6
6
|
[](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)
|