statesman 8.0.1 → 9.0.1
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/.circleci/config.yml +100 -160
- data/.github/dependabot.yml +7 -0
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +37 -28
- data/.ruby-version +1 -0
- data/CHANGELOG.md +40 -6
- data/CONTRIBUTING.md +18 -0
- data/Gemfile +0 -3
- data/README.md +69 -3
- data/lib/statesman/adapters/active_record.rb +20 -2
- data/lib/statesman/exceptions.rb +4 -0
- data/lib/statesman/machine.rb +4 -0
- data/lib/statesman/version.rb +1 -1
- data/spec/statesman/adapters/active_record_queries_spec.rb +3 -4
- data/spec/statesman/adapters/active_record_spec.rb +25 -0
- data/spec/statesman/adapters/shared_examples.rb +1 -0
- data/spec/statesman/exceptions_spec.rb +9 -0
- data/spec/statesman/machine_spec.rb +31 -5
- data/spec/support/active_record.rb +6 -6
- data/statesman.gemspec +4 -4
- metadata +16 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 145d2a6b60abe5fb64e8010676cb63b62ba1869daa4343eb538bdf1d261c885e
|
|
4
|
+
data.tar.gz: cbcc8f735327409a89a2b238fefdfb6ef4b9e9595b983f7a648df800ca8c2aed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9eeef7b26150628a370117dccbcde1e40bc1dbd15957fca96f18232e167b5bcca58a42f47a2718a6927bfcb08449b4f7515fa48ef68ed281f79e12fad96d40f2
|
|
7
|
+
data.tar.gz: b793c7af514ce22564326d697880179caceadff2bebc6c03b02aa5a523e040ffd17e5dff8475b9fad7ed567f6f0f8849fe97ddb6745a7b3d86cd7aceb71e0264
|
data/.circleci/config.yml
CHANGED
|
@@ -1,187 +1,127 @@
|
|
|
1
1
|
---
|
|
2
|
-
version: 2
|
|
2
|
+
version: 2.1
|
|
3
3
|
|
|
4
4
|
references:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- run: gem install bundler -v 2.1.4
|
|
16
|
-
|
|
17
|
-
- run: bundle install --path vendor/bundle
|
|
5
|
+
bundle_install: &bundle_install
|
|
6
|
+
run:
|
|
7
|
+
name: Bundle
|
|
8
|
+
command: |
|
|
9
|
+
gem install bundler --no-document && \
|
|
10
|
+
bundle config set no-cache 'true' && \
|
|
11
|
+
bundle config set jobs '4' && \
|
|
12
|
+
bundle config set retry '3' && \
|
|
13
|
+
bundle install
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
cache_bundle: &cache_bundle
|
|
16
|
+
save_cache:
|
|
17
|
+
key: bundle-<< parameters.ruby_version >>-<< parameters.rails_version >>-{{ checksum "statesman.gemspec" }}-{{ checksum "Gemfile" }}
|
|
21
18
|
paths:
|
|
22
19
|
- vendor/bundle
|
|
23
20
|
|
|
24
|
-
|
|
21
|
+
restore_bundle: &restore_bundle
|
|
22
|
+
restore_cache:
|
|
23
|
+
key: bundle-<< parameters.ruby_version >>-<< parameters.rails_version >>-{{ checksum "statesman.gemspec" }}-{{ checksum "Gemfile" }}
|
|
25
24
|
|
|
25
|
+
steps: &steps
|
|
26
|
+
- add_ssh_keys
|
|
27
|
+
- checkout
|
|
28
|
+
- run:
|
|
29
|
+
name: "Add dependencies"
|
|
30
|
+
command: |
|
|
31
|
+
sudo apt-get update && sudo apt-get install -y sqlite3 libsqlite3-dev
|
|
32
|
+
- *restore_bundle
|
|
33
|
+
- *bundle_install
|
|
34
|
+
- *cache_bundle
|
|
26
35
|
- run: dockerize -wait tcp://localhost:$DATABASE_DEPENDENCY_PORT -timeout 1m
|
|
36
|
+
- run:
|
|
37
|
+
name: Run specs
|
|
38
|
+
command: |
|
|
39
|
+
bundle exec rspec $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) --profile --format progress --format RspecJunitFormatter -o /tmp/circle_artifacts/rspec.xml
|
|
40
|
+
- run:
|
|
41
|
+
name: "Rubocop"
|
|
42
|
+
command: bundle exec rubocop --extra-details --display-style-guide --parallel --force-exclusion
|
|
43
|
+
- store_artifacts:
|
|
44
|
+
path: /tmp/circle_artifacts/
|
|
45
|
+
- store_test_results:
|
|
46
|
+
path: /tmp/circle_artifacts/
|
|
27
47
|
|
|
28
|
-
|
|
48
|
+
ruby_versions: &ruby_versions
|
|
49
|
+
- "2.5"
|
|
50
|
+
- "2.6"
|
|
51
|
+
- "2.7"
|
|
52
|
+
- "3.0"
|
|
29
53
|
|
|
30
|
-
|
|
31
|
-
|
|
54
|
+
rails_versions: &rails_versions
|
|
55
|
+
- "5.2.6"
|
|
56
|
+
- "6.0.4"
|
|
57
|
+
- "6.1.4"
|
|
58
|
+
- "main"
|
|
32
59
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
docker:
|
|
36
|
-
- image: circleci/ruby:2.4.9-node
|
|
37
|
-
environment:
|
|
38
|
-
- RAILS_VERSION=5.2.4
|
|
39
|
-
- DATABASE_URL=mysql2://root@127.0.0.1/statesman_test
|
|
40
|
-
- DATABASE_DEPENDENCY_PORT=3306
|
|
41
|
-
- image: circleci/mysql:5.7.18
|
|
42
|
-
environment:
|
|
43
|
-
- MYSQL_ALLOW_EMPTY_PASSWORD=true
|
|
44
|
-
- MYSQL_USER=root
|
|
45
|
-
- MYSQL_PASSWORD=
|
|
46
|
-
- MYSQL_DATABASE=statesman_test
|
|
47
|
-
steps: *steps
|
|
48
|
-
build-ruby249-rails-524-postgres:
|
|
49
|
-
docker:
|
|
50
|
-
- image: circleci/ruby:2.4.9-node
|
|
51
|
-
environment:
|
|
52
|
-
- RAILS_VERSION=5.2.4
|
|
53
|
-
- DATABASE_URL=postgres://postgres@localhost/statesman_test
|
|
54
|
-
- DATABASE_DEPENDENCY_PORT=5432
|
|
55
|
-
- image: circleci/postgres:9.6
|
|
56
|
-
environment:
|
|
57
|
-
- POSTGRES_USER=postgres
|
|
58
|
-
- POSTGRES_DB=statesman_test
|
|
59
|
-
- POSTGRES_PASSWORD=statesman
|
|
60
|
-
steps: *steps
|
|
60
|
+
mysql_versions: &mysql_versions
|
|
61
|
+
- "5.7"
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- image: circleci/ruby:2.6.5-node
|
|
65
|
-
environment:
|
|
66
|
-
- RAILS_VERSION=6.0.2
|
|
67
|
-
- DATABASE_URL=mysql2://root@127.0.0.1/statesman_test
|
|
68
|
-
- DATABASE_DEPENDENCY_PORT=3306
|
|
69
|
-
- image: circleci/mysql:5.7.18
|
|
70
|
-
environment:
|
|
71
|
-
- MYSQL_ALLOW_EMPTY_PASSWORD=true
|
|
72
|
-
- MYSQL_USER=root
|
|
73
|
-
- MYSQL_PASSWORD=
|
|
74
|
-
- MYSQL_DATABASE=statesman_test
|
|
75
|
-
steps: *steps
|
|
76
|
-
build-ruby265-rails-602-postgres:
|
|
77
|
-
docker:
|
|
78
|
-
- image: circleci/ruby:2.6.5-node
|
|
79
|
-
environment:
|
|
80
|
-
- RAILS_VERSION=6.0.2
|
|
81
|
-
- DATABASE_URL=postgres://postgres@localhost/statesman_test
|
|
82
|
-
- DATABASE_DEPENDENCY_PORT=5432
|
|
83
|
-
- image: circleci/postgres:9.6
|
|
84
|
-
environment:
|
|
85
|
-
- POSTGRES_USER=postgres
|
|
86
|
-
- POSTGRES_DB=statesman_test
|
|
87
|
-
- POSTGRES_PASSWORD=statesman
|
|
88
|
-
steps: *steps
|
|
89
|
-
build-ruby265-rails-main-mysql:
|
|
90
|
-
docker:
|
|
91
|
-
- image: circleci/ruby:2.6.5-node
|
|
92
|
-
environment:
|
|
93
|
-
- RAILS_VERSION=main
|
|
94
|
-
- DATABASE_URL=mysql2://root@127.0.0.1/statesman_test
|
|
95
|
-
- DATABASE_DEPENDENCY_PORT=3306
|
|
96
|
-
- image: circleci/mysql:5.7.18
|
|
97
|
-
environment:
|
|
98
|
-
- MYSQL_ALLOW_EMPTY_PASSWORD=true
|
|
99
|
-
- MYSQL_USER=root
|
|
100
|
-
- MYSQL_PASSWORD=
|
|
101
|
-
- MYSQL_DATABASE=statesman_test
|
|
102
|
-
steps: *steps
|
|
103
|
-
build-ruby265-rails-main-postgres:
|
|
104
|
-
docker:
|
|
105
|
-
- image: circleci/ruby:2.6.5-node
|
|
106
|
-
environment:
|
|
107
|
-
- RAILS_VERSION=main
|
|
108
|
-
- DATABASE_URL=postgres://postgres@localhost/statesman_test
|
|
109
|
-
- EXCLUDE_MONGOID=true
|
|
110
|
-
- DATABASE_DEPENDENCY_PORT=5432
|
|
111
|
-
- image: circleci/postgres:9.6
|
|
112
|
-
environment:
|
|
113
|
-
- POSTGRES_USER=postgres
|
|
114
|
-
- POSTGRES_DB=statesman_test
|
|
115
|
-
- POSTGRES_PASSWORD=statesman
|
|
116
|
-
steps: *steps
|
|
63
|
+
psql_versions: &psql_versions
|
|
64
|
+
- "9.6"
|
|
117
65
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
- MYSQL_USER=root
|
|
129
|
-
- MYSQL_PASSWORD=
|
|
130
|
-
- MYSQL_DATABASE=statesman_test
|
|
131
|
-
steps: *steps
|
|
132
|
-
build-ruby270-rails-602-postgres:
|
|
133
|
-
docker:
|
|
134
|
-
- image: circleci/ruby:2.7.0-node
|
|
135
|
-
environment:
|
|
136
|
-
- RAILS_VERSION=6.0.2
|
|
137
|
-
- DATABASE_URL=postgres://postgres@localhost/statesman_test
|
|
138
|
-
- DATABASE_DEPENDENCY_PORT=5432
|
|
139
|
-
- image: circleci/postgres:9.6
|
|
140
|
-
environment:
|
|
141
|
-
- POSTGRES_USER=postgres
|
|
142
|
-
- POSTGRES_DB=statesman_test
|
|
143
|
-
- POSTGRES_PASSWORD=statesman
|
|
144
|
-
steps: *steps
|
|
145
|
-
build-ruby270-rails-main-mysql:
|
|
66
|
+
jobs:
|
|
67
|
+
rspec_mysql:
|
|
68
|
+
working_directory: /mnt/ramdisk
|
|
69
|
+
parameters:
|
|
70
|
+
ruby_version:
|
|
71
|
+
type: string
|
|
72
|
+
rails_version:
|
|
73
|
+
type: string
|
|
74
|
+
mysql_version:
|
|
75
|
+
type: string
|
|
146
76
|
docker:
|
|
147
|
-
- image:
|
|
77
|
+
- image: cimg/ruby:<< parameters.ruby_version >>
|
|
148
78
|
environment:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- image:
|
|
79
|
+
CIRCLE_TEST_REPORTS: /tmp/circle_artifacts/
|
|
80
|
+
DATABASE_URL: mysql2://foobar:password@127.0.0.1/statesman_test
|
|
81
|
+
DATABASE_DEPENDENCY_PORT: "3306"
|
|
82
|
+
- image: cimg/mysql:<< parameters.mysql_version >>
|
|
153
83
|
environment:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
84
|
+
MYSQL_ROOT_PASSWORD: password
|
|
85
|
+
MYSQL_USER: foobar
|
|
86
|
+
MYSQL_PASSWORD: password
|
|
87
|
+
MYSQL_DATABASE: statesman_test
|
|
158
88
|
steps: *steps
|
|
159
|
-
|
|
89
|
+
|
|
90
|
+
rspec_postgres:
|
|
91
|
+
working_directory: /mnt/ramdisk
|
|
92
|
+
parameters:
|
|
93
|
+
ruby_version:
|
|
94
|
+
type: string
|
|
95
|
+
rails_version:
|
|
96
|
+
type: string
|
|
97
|
+
psql_version:
|
|
98
|
+
type: string
|
|
160
99
|
docker:
|
|
161
|
-
- image:
|
|
100
|
+
- image: cimg/ruby:<< parameters.ruby_version >>
|
|
162
101
|
environment:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
- image: circleci/postgres:9.6
|
|
102
|
+
CIRCLE_TEST_REPORTS: /tmp/circle_artifacts/
|
|
103
|
+
DATABASE_URL: postgres://postgres@localhost/statesman_test
|
|
104
|
+
DATABASE_DEPENDENCY_PORT: "5432"
|
|
105
|
+
- image: circleci/postgres:<< parameters.psql_version >>
|
|
168
106
|
environment:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
107
|
+
POSTGRES_USER: postgres
|
|
108
|
+
POSTGRES_DB: statesman_test
|
|
109
|
+
POSTGRES_PASSWORD: statesman
|
|
172
110
|
steps: *steps
|
|
173
111
|
|
|
174
112
|
workflows:
|
|
175
113
|
version: 2
|
|
176
114
|
tests:
|
|
177
115
|
jobs:
|
|
178
|
-
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
116
|
+
- rspec_mysql:
|
|
117
|
+
matrix:
|
|
118
|
+
parameters:
|
|
119
|
+
mysql_version: *mysql_versions
|
|
120
|
+
ruby_version: *ruby_versions
|
|
121
|
+
rails_version: *rails_versions
|
|
122
|
+
- rspec_postgres:
|
|
123
|
+
matrix:
|
|
124
|
+
parameters:
|
|
125
|
+
psql_version: *psql_versions
|
|
126
|
+
ruby_version: *ruby_versions
|
|
127
|
+
rails_version: *rails_versions
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on
|
|
3
|
+
# on 2021-08-09 15:32:40 UTC using RuboCop version 1.18.4.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# Configuration parameters: Include.
|
|
11
|
+
# Include: **/*.gemspec
|
|
9
12
|
Gemspec/RequiredRubyVersion:
|
|
10
|
-
|
|
13
|
+
Exclude:
|
|
14
|
+
- 'statesman.gemspec'
|
|
15
|
+
|
|
16
|
+
# Offense count: 1
|
|
17
|
+
Lint/MissingSuper:
|
|
18
|
+
Exclude:
|
|
19
|
+
- 'lib/statesman/adapters/active_record_queries.rb'
|
|
11
20
|
|
|
12
21
|
# Offense count: 5
|
|
22
|
+
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
|
|
13
23
|
Metrics/AbcSize:
|
|
14
|
-
Max:
|
|
24
|
+
Max: 20
|
|
25
|
+
|
|
26
|
+
# Offense count: 1
|
|
27
|
+
# Configuration parameters: IgnoredMethods.
|
|
28
|
+
Metrics/CyclomaticComplexity:
|
|
29
|
+
Max: 8
|
|
15
30
|
|
|
16
|
-
# Offense count:
|
|
17
|
-
# Configuration parameters: CountComments, ExcludedMethods.
|
|
31
|
+
# Offense count: 3
|
|
32
|
+
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
|
|
18
33
|
Metrics/MethodLength:
|
|
19
34
|
Max: 14
|
|
20
35
|
|
|
21
|
-
# Offense count:
|
|
22
|
-
#
|
|
23
|
-
# Configuration parameters: SkipBlocks, EnforcedStyle.
|
|
24
|
-
# SupportedStyles: described_class, explicit
|
|
25
|
-
RSpec/DescribedClass:
|
|
26
|
-
Exclude:
|
|
27
|
-
- 'spec/statesman/adapters/active_record_queries_spec.rb'
|
|
28
|
-
|
|
29
|
-
# Offense count: 7
|
|
30
|
-
# Configuration parameters: Max.
|
|
36
|
+
# Offense count: 11
|
|
37
|
+
# Configuration parameters: CountAsOne.
|
|
31
38
|
RSpec/ExampleLength:
|
|
32
|
-
|
|
33
|
-
- 'spec/statesman/adapters/active_record_spec.rb'
|
|
34
|
-
- 'spec/statesman/adapters/shared_examples.rb'
|
|
35
|
-
- 'spec/statesman/machine_spec.rb'
|
|
39
|
+
Max: 14
|
|
36
40
|
|
|
37
41
|
# Offense count: 7
|
|
38
42
|
RSpec/ExpectInHook:
|
|
@@ -40,11 +44,12 @@ RSpec/ExpectInHook:
|
|
|
40
44
|
- 'spec/statesman/adapters/active_record_spec.rb'
|
|
41
45
|
- 'spec/statesman/machine_spec.rb'
|
|
42
46
|
|
|
43
|
-
# Offense count:
|
|
44
|
-
|
|
47
|
+
# Offense count: 1
|
|
48
|
+
# Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly.
|
|
49
|
+
# Include: **/*_spec*rb*, **/spec/**/*
|
|
50
|
+
RSpec/FilePath:
|
|
45
51
|
Exclude:
|
|
46
|
-
- 'spec/statesman/
|
|
47
|
-
- 'spec/statesman/adapters/shared_examples.rb'
|
|
52
|
+
- 'spec/statesman/exceptions_spec.rb'
|
|
48
53
|
|
|
49
54
|
# Offense count: 1
|
|
50
55
|
# Configuration parameters: AssignmentOnly.
|
|
@@ -75,23 +80,27 @@ RSpec/MessageSpies:
|
|
|
75
80
|
Exclude:
|
|
76
81
|
- 'spec/statesman/callback_spec.rb'
|
|
77
82
|
|
|
78
|
-
# Offense count:
|
|
79
|
-
# Configuration parameters: AggregateFailuresByDefault.
|
|
83
|
+
# Offense count: 14
|
|
80
84
|
RSpec/MultipleExpectations:
|
|
81
85
|
Max: 3
|
|
82
86
|
|
|
83
|
-
# Offense count:
|
|
87
|
+
# Offense count: 49
|
|
84
88
|
RSpec/NestedGroups:
|
|
85
89
|
Max: 6
|
|
86
90
|
|
|
87
|
-
# Offense count:
|
|
91
|
+
# Offense count: 2
|
|
92
|
+
RSpec/RepeatedExampleGroupBody:
|
|
93
|
+
Exclude:
|
|
94
|
+
- 'spec/statesman/exceptions_spec.rb'
|
|
95
|
+
|
|
96
|
+
# Offense count: 12
|
|
88
97
|
RSpec/ScatteredSetup:
|
|
89
98
|
Exclude:
|
|
90
99
|
- 'spec/statesman/adapters/active_record_spec.rb'
|
|
91
100
|
- 'spec/statesman/adapters/shared_examples.rb'
|
|
92
101
|
- 'spec/statesman/machine_spec.rb'
|
|
93
102
|
|
|
94
|
-
# Offense count:
|
|
103
|
+
# Offense count: 7
|
|
95
104
|
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
|
|
96
105
|
RSpec/VerifiedDoubles:
|
|
97
106
|
Exclude:
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.0.2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
## v9.0.1 4th February 2021
|
|
2
|
+
|
|
3
|
+
### Changed
|
|
4
|
+
- Deprecate `ActiveRecord::Base.default_timezone` in favour of `ActiveRecord.default_timezone` [#446](https://github.com/gocardless/statesman/pull/446)
|
|
5
|
+
|
|
6
|
+
## v9.0.0 9th August 2021
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- Added Ruby 3.0 support
|
|
10
|
+
|
|
11
|
+
### Breaking changes
|
|
12
|
+
|
|
13
|
+
- Removed Ruby 2.4
|
|
14
|
+
|
|
15
|
+
## v8.0.3 8th June 2021
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- Implement `Machine#last_transition_to`, to find the last transition to a given state
|
|
19
|
+
[#438](https://github.com/gocardless/statesman/pull/438)
|
|
20
|
+
|
|
21
|
+
## v8.0.2 30th March 2021
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Fixed a bug where the `history` of a model was left in an incorrect state after a transition
|
|
26
|
+
conflict [#433](https://github.com/gocardless/statesman/pull/433)
|
|
27
|
+
|
|
28
|
+
## v8.0.1 20th January 2021
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Fixed `no implicit conversion of nil into String` error when quoting null values
|
|
33
|
+
[#427](https://github.com/gocardless/statesman/pull/427)
|
|
34
|
+
|
|
1
35
|
## v8.0.0 6th January 2021
|
|
2
36
|
|
|
3
37
|
### Added
|
|
@@ -24,16 +58,16 @@
|
|
|
24
58
|
|
|
25
59
|
### Changed
|
|
26
60
|
|
|
27
|
-
- Use correct Arel for null [#409](https://github.com/gocardless/statesman/pull
|
|
61
|
+
- Use correct Arel for null [#409](https://github.com/gocardless/statesman/pull/409)
|
|
28
62
|
|
|
29
63
|
## v7.2.0, 19th May 2020
|
|
30
64
|
|
|
31
65
|
### Changed
|
|
32
66
|
|
|
33
|
-
- Set non-empty password for postgres tests [#398](https://github.com/gocardless/statesman/pull
|
|
34
|
-
- Handle transitions differently for MySQL [#399](https://github.com/gocardless/statesman/pull
|
|
35
|
-
- pg requirement from >= 0.18, <= 1.1 to >= 0.18, <= 1.3 [#400](https://github.com/gocardless/statesman/pull
|
|
36
|
-
- Lazily enable mysql gaplock protection [#402](https://github.com/gocardless/statesman/pull
|
|
67
|
+
- Set non-empty password for postgres tests [#398](https://github.com/gocardless/statesman/pull/398)
|
|
68
|
+
- Handle transitions differently for MySQL [#399](https://github.com/gocardless/statesman/pull/399)
|
|
69
|
+
- pg requirement from >= 0.18, <= 1.1 to >= 0.18, <= 1.3 [#400](https://github.com/gocardless/statesman/pull/400)
|
|
70
|
+
- Lazily enable mysql gaplock protection [#402](https://github.com/gocardless/statesman/pull/402)
|
|
37
71
|
|
|
38
72
|
## v7.1.0, 10th Feb 2020
|
|
39
73
|
|
|
@@ -86,7 +120,7 @@
|
|
|
86
120
|
to
|
|
87
121
|
```ruby
|
|
88
122
|
include Statesman::Adapters::ActiveRecordQueries[
|
|
89
|
-
initial_state: :
|
|
123
|
+
initial_state: :initial,
|
|
90
124
|
transition_class: MyTransition
|
|
91
125
|
]
|
|
92
126
|
```
|
data/CONTRIBUTING.md
CHANGED
|
@@ -19,3 +19,21 @@ request passes by running `rubocop`.
|
|
|
19
19
|
|
|
20
20
|
Please add a section to the readme for any new feature additions or behaviour
|
|
21
21
|
changes.
|
|
22
|
+
|
|
23
|
+
## Releasing
|
|
24
|
+
|
|
25
|
+
We publish new versions of Stateman using [RubyGems](https://guides.rubygems.org/publishing/). Once
|
|
26
|
+
the relevant changes have been merged and `VERSION` has been appropriately bumped to the new
|
|
27
|
+
version, we run the following command.
|
|
28
|
+
```
|
|
29
|
+
$ gem build statesman.gemspec
|
|
30
|
+
```
|
|
31
|
+
This builds a `.gem` file locally that will be named something like `statesman-X` where `X` is the
|
|
32
|
+
new version. For example, if we are releasing version 9.0.0, the file would be
|
|
33
|
+
`statesman-9.0.0.gem`.
|
|
34
|
+
|
|
35
|
+
To publish, run `gem push` with the new `.gem` file we just generated. This requires a OTP that is currently only available
|
|
36
|
+
to GoCardless engineers. For example, if we were to continue to publish version 9.0.0, we would run:
|
|
37
|
+
```
|
|
38
|
+
$ gem push statesman-9.0.0.gem
|
|
39
|
+
```
|
data/Gemfile
CHANGED
|
@@ -4,14 +4,11 @@ source 'https://rubygems.org'
|
|
|
4
4
|
|
|
5
5
|
gemspec
|
|
6
6
|
|
|
7
|
-
# rubocop:disable Bundler/DuplicatedGem
|
|
8
7
|
if ENV['RAILS_VERSION'] == 'main'
|
|
9
8
|
gem "rails", git: "https://github.com/rails/rails", branch: "main"
|
|
10
9
|
elsif ENV['RAILS_VERSION']
|
|
11
10
|
gem "rails", "~> #{ENV['RAILS_VERSION']}"
|
|
12
11
|
end
|
|
13
|
-
# rubocop:enable Bundler/DuplicatedGem
|
|
14
|
-
|
|
15
12
|
group :development do
|
|
16
13
|
# test/unit is no longer bundled with Ruby 2.2, but required by Rails
|
|
17
14
|
gem "test-unit", "~> 3.3" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.2.0")
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<p align="center"><img src="
|
|
1
|
+
<p align="center"><img src="https://user-images.githubusercontent.com/110275/106792848-96e4ee80-664e-11eb-8fd1-16ff24b41eb2.png" alt="Statesman" width="512"></p>
|
|
2
2
|
|
|
3
3
|
A statesmanlike state machine library.
|
|
4
4
|
|
|
@@ -30,7 +30,7 @@ protection.
|
|
|
30
30
|
To get started, just add Statesman to your `Gemfile`, and then run `bundle`:
|
|
31
31
|
|
|
32
32
|
```ruby
|
|
33
|
-
gem 'statesman', '~>
|
|
33
|
+
gem 'statesman', '~> 8.0.3'
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Usage
|
|
@@ -109,6 +109,8 @@ Order.first.state_machine.allowed_transitions # => ["checking_out", "cancelled"]
|
|
|
109
109
|
Order.first.state_machine.can_transition_to?(:cancelled) # => true/false
|
|
110
110
|
Order.first.state_machine.transition_to(:cancelled, optional: :metadata) # => true/false
|
|
111
111
|
Order.first.state_machine.transition_to!(:cancelled) # => true/exception
|
|
112
|
+
Order.first.state_machine.last_transition # => transition model or nil
|
|
113
|
+
Order.first.state_machine.last_transition_to(:pending) # => transition model or nil
|
|
112
114
|
|
|
113
115
|
Order.in_state(:cancelled) # => [#<Order id: "123">]
|
|
114
116
|
Order.not_in_state(:checking_out) # => [#<Order id: "123">]
|
|
@@ -159,7 +161,8 @@ class Order < ActiveRecord::Base
|
|
|
159
161
|
|
|
160
162
|
# Optionally delegate some methods
|
|
161
163
|
|
|
162
|
-
delegate :can_transition_to?,
|
|
164
|
+
delegate :can_transition_to?,
|
|
165
|
+
:current_state, :history, :last_transition, :last_transition_to,
|
|
163
166
|
:transition_to!, :transition_to, :in_state?, to: :state_machine
|
|
164
167
|
end
|
|
165
168
|
```
|
|
@@ -335,6 +338,9 @@ Returns a sorted array of all transition objects.
|
|
|
335
338
|
#### `Machine#last_transition`
|
|
336
339
|
Returns the most recent transition object.
|
|
337
340
|
|
|
341
|
+
#### `Machine#last_transition_to(:state)`
|
|
342
|
+
Returns the most recent transition object to a given state.
|
|
343
|
+
|
|
338
344
|
#### `Machine#allowed_transitions`
|
|
339
345
|
Returns an array of states you can `transition_to` from current state.
|
|
340
346
|
|
|
@@ -351,6 +357,66 @@ Transition to the passed state, returning `true` on success. Swallows all
|
|
|
351
357
|
Statesman exceptions and returns false on failure. (NB. if your guard or
|
|
352
358
|
callback code throws an exception, it will not be caught.)
|
|
353
359
|
|
|
360
|
+
|
|
361
|
+
## Errors
|
|
362
|
+
|
|
363
|
+
### Initialization errors
|
|
364
|
+
These errors are raised when the Machine and/or Model is initialized. A simple spec like
|
|
365
|
+
```ruby
|
|
366
|
+
expect { OrderStateMachine.new(Order.new, transition_class: OrderTransition) }.to_not raise_error
|
|
367
|
+
```
|
|
368
|
+
will expose these errors as part of your test suite
|
|
369
|
+
|
|
370
|
+
#### InvalidStateError
|
|
371
|
+
Raised if:
|
|
372
|
+
* Attempting to define a transition without a `to` state.
|
|
373
|
+
* Attempting to define a transition with a non-existent state.
|
|
374
|
+
* Attempting to define multiple states as `initial`.
|
|
375
|
+
|
|
376
|
+
#### InvalidTransitionError
|
|
377
|
+
Raised if:
|
|
378
|
+
* Attempting to define a callback `from` a state that has no valid transitions (A terminal state).
|
|
379
|
+
* Attempting to define a callback `to` the `initial` state if that state has no transitions to it.
|
|
380
|
+
* Attempting to define a callback with `from` and `to` where any of the pairs have no transition between them.
|
|
381
|
+
|
|
382
|
+
#### InvalidCallbackError
|
|
383
|
+
Raised if:
|
|
384
|
+
* Attempting to define a callback without a block.
|
|
385
|
+
|
|
386
|
+
#### UnserializedMetadataError
|
|
387
|
+
Raised if:
|
|
388
|
+
* ActiveRecord is configured to not serialize the `metadata` attribute into
|
|
389
|
+
to Database column backing it. See the `Using PostgreSQL JSON column` section.
|
|
390
|
+
|
|
391
|
+
#### IncompatibleSerializationError
|
|
392
|
+
Raised if:
|
|
393
|
+
* There is a mismatch between the column type of the `metadata` in the
|
|
394
|
+
Database and the model. See the `Using PostgreSQL JSON column` section.
|
|
395
|
+
|
|
396
|
+
#### MissingTransitionAssociation
|
|
397
|
+
Raised if:
|
|
398
|
+
* The model that `Statesman::Adapters::ActiveRecordQueries` is included in
|
|
399
|
+
does not have a `has_many` association to the `transition_class`.
|
|
400
|
+
|
|
401
|
+
### Runtime errors
|
|
402
|
+
These errors are raised by `transition_to!`. Using `transition_to` will
|
|
403
|
+
supress `GuardFailedError` and `TransitionFailedError` and return `false` instead.
|
|
404
|
+
|
|
405
|
+
#### GuardFailedError
|
|
406
|
+
Raised if:
|
|
407
|
+
* A guard callback between `from` and `to` state returned a falsey value.
|
|
408
|
+
|
|
409
|
+
#### TransitionFailedError
|
|
410
|
+
Raised if:
|
|
411
|
+
* A transition is attempted but `current_state -> new_state` is not a valid pair.
|
|
412
|
+
|
|
413
|
+
#### TransitionConflictError
|
|
414
|
+
Raised if:
|
|
415
|
+
* A database conflict affecting the `sort_key` or `most_recent` columns occurs
|
|
416
|
+
when attempting a transition.
|
|
417
|
+
Retried automatically if it occurs wrapped in `retry_conflicts`.
|
|
418
|
+
|
|
419
|
+
|
|
354
420
|
## Model scopes
|
|
355
421
|
|
|
356
422
|
A mixin is provided for the ActiveRecord adapter which adds scopes to easily
|
|
@@ -42,7 +42,13 @@ module Statesman
|
|
|
42
42
|
def create(from, to, metadata = {})
|
|
43
43
|
create_transition(from.to_s, to.to_s, metadata)
|
|
44
44
|
rescue ::ActiveRecord::RecordNotUnique => e
|
|
45
|
-
|
|
45
|
+
if transition_conflict_error? e
|
|
46
|
+
# The history has the invalid transition on the end of it, which means
|
|
47
|
+
# `current_state` would then be incorrect. We force a reload of the history to
|
|
48
|
+
# avoid this.
|
|
49
|
+
transitions_for_parent.reload
|
|
50
|
+
raise TransitionConflictError, e.message
|
|
51
|
+
end
|
|
46
52
|
|
|
47
53
|
raise
|
|
48
54
|
ensure
|
|
@@ -59,6 +65,7 @@ module Statesman
|
|
|
59
65
|
end
|
|
60
66
|
end
|
|
61
67
|
|
|
68
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
|
62
69
|
def last(force_reload: false)
|
|
63
70
|
if force_reload
|
|
64
71
|
@last_transition = history(force_reload: true).last
|
|
@@ -66,6 +73,7 @@ module Statesman
|
|
|
66
73
|
@last_transition ||= history.last
|
|
67
74
|
end
|
|
68
75
|
end
|
|
76
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
|
69
77
|
|
|
70
78
|
def reset
|
|
71
79
|
@last_transition = nil
|
|
@@ -296,10 +304,20 @@ module Statesman
|
|
|
296
304
|
return nil if column.nil?
|
|
297
305
|
|
|
298
306
|
[
|
|
299
|
-
column,
|
|
307
|
+
column, default_timezone == :utc ? Time.now.utc : Time.now
|
|
300
308
|
]
|
|
301
309
|
end
|
|
302
310
|
|
|
311
|
+
def default_timezone
|
|
312
|
+
# Rails 7 deprecates ActiveRecord::Base.default_timezone
|
|
313
|
+
# in favour of ActiveRecord.default_timezone
|
|
314
|
+
if ::ActiveRecord.respond_to?(:default_timezone)
|
|
315
|
+
return ::ActiveRecord.default_timezone
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
::ActiveRecord::Base.default_timezone
|
|
319
|
+
end
|
|
320
|
+
|
|
303
321
|
def mysql_gaplock_protection?
|
|
304
322
|
Statesman.mysql_gaplock_protection?
|
|
305
323
|
end
|
data/lib/statesman/exceptions.rb
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Statesman
|
|
4
4
|
class InvalidStateError < StandardError; end
|
|
5
|
+
|
|
5
6
|
class InvalidTransitionError < StandardError; end
|
|
7
|
+
|
|
6
8
|
class InvalidCallbackError < StandardError; end
|
|
9
|
+
|
|
7
10
|
class TransitionConflictError < StandardError; end
|
|
11
|
+
|
|
8
12
|
class MissingTransitionAssociation < StandardError; end
|
|
9
13
|
|
|
10
14
|
class TransitionFailedError < StandardError
|
data/lib/statesman/machine.rb
CHANGED
|
@@ -209,6 +209,10 @@ module Statesman
|
|
|
209
209
|
@storage_adapter.last(force_reload: force_reload)
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
+
def last_transition_to(state)
|
|
213
|
+
history.reverse.find { |transition| transition.to_state.to_sym == state.to_sym }
|
|
214
|
+
end
|
|
215
|
+
|
|
212
216
|
def can_transition_to?(new_state, metadata = {})
|
|
213
217
|
validate_transition(from: current_state,
|
|
214
218
|
to: new_state,
|
data/lib/statesman/version.rb
CHANGED
|
@@ -50,10 +50,11 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
|
50
50
|
|
|
51
51
|
shared_examples "testing methods" do
|
|
52
52
|
before do
|
|
53
|
-
|
|
53
|
+
case config_type
|
|
54
|
+
when :old
|
|
54
55
|
configure_old(MyActiveRecordModel, MyActiveRecordModelTransition)
|
|
55
56
|
configure_old(OtherActiveRecordModel, OtherActiveRecordModelTransition)
|
|
56
|
-
|
|
57
|
+
when :new
|
|
57
58
|
configure_new(MyActiveRecordModel, MyActiveRecordModelTransition)
|
|
58
59
|
configure_new(OtherActiveRecordModel, OtherActiveRecordModelTransition)
|
|
59
60
|
else
|
|
@@ -201,7 +202,6 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
|
201
202
|
MyActiveRecordModel.create
|
|
202
203
|
end
|
|
203
204
|
|
|
204
|
-
# rubocop:disable RSpec/ExampleLength
|
|
205
205
|
it do
|
|
206
206
|
expect do
|
|
207
207
|
ActiveRecord::Base.transaction do
|
|
@@ -210,7 +210,6 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
|
|
|
210
210
|
end
|
|
211
211
|
end.to_not change(MyStateMachine, :after_commit_callback_executed)
|
|
212
212
|
end
|
|
213
|
-
# rubocop:enable RSpec/ExampleLength
|
|
214
213
|
end
|
|
215
214
|
end
|
|
216
215
|
|
|
@@ -130,6 +130,31 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
|
|
|
130
130
|
expect { adapter.create(:y, :z) }.
|
|
131
131
|
to raise_exception(Statesman::TransitionConflictError)
|
|
132
132
|
end
|
|
133
|
+
|
|
134
|
+
it "does not pollute the state when the transition fails" do
|
|
135
|
+
# this increments the sort_key in the database
|
|
136
|
+
adapter.create(:x, :y)
|
|
137
|
+
|
|
138
|
+
# we then pre-load the transitions for efficiency
|
|
139
|
+
preloaded_model = MyActiveRecordModel.
|
|
140
|
+
includes(:my_active_record_model_transitions).
|
|
141
|
+
find(model.id)
|
|
142
|
+
|
|
143
|
+
adapter2 = described_class.
|
|
144
|
+
new(MyActiveRecordModelTransition, preloaded_model, observer)
|
|
145
|
+
|
|
146
|
+
# Now we generate a race
|
|
147
|
+
adapter.create(:y, :z)
|
|
148
|
+
expect { adapter2.create(:y, :a) }.
|
|
149
|
+
to raise_error(Statesman::TransitionConflictError)
|
|
150
|
+
|
|
151
|
+
# The preloaded adapter should discard the preloaded info
|
|
152
|
+
expect(adapter2.last).to have_attributes(to_state: "z")
|
|
153
|
+
expect(adapter2.history).to contain_exactly(
|
|
154
|
+
have_attributes(to_state: "y"),
|
|
155
|
+
have_attributes(to_state: "z"),
|
|
156
|
+
)
|
|
157
|
+
end
|
|
133
158
|
end
|
|
134
159
|
|
|
135
160
|
context "when other exceptions occur" do
|
|
@@ -128,6 +128,7 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
|
|
|
128
128
|
|
|
129
129
|
it { is_expected.to be_a(transition_class) }
|
|
130
130
|
specify { expect(adapter.last.to_state.to_sym).to eq(:z) }
|
|
131
|
+
|
|
131
132
|
specify do
|
|
132
133
|
expect(adapter.last(force_reload: true).to_state.to_sym).to eq(:z)
|
|
133
134
|
end
|
|
@@ -7,6 +7,7 @@ describe Statesman do
|
|
|
7
7
|
subject(:error) { Statesman::InvalidStateError.new }
|
|
8
8
|
|
|
9
9
|
its(:message) { is_expected.to eq("Statesman::InvalidStateError") }
|
|
10
|
+
|
|
10
11
|
its "string matches its message" do
|
|
11
12
|
expect(error.to_s).to eq(error.message)
|
|
12
13
|
end
|
|
@@ -16,6 +17,7 @@ describe Statesman do
|
|
|
16
17
|
subject(:error) { Statesman::InvalidTransitionError.new }
|
|
17
18
|
|
|
18
19
|
its(:message) { is_expected.to eq("Statesman::InvalidTransitionError") }
|
|
20
|
+
|
|
19
21
|
its "string matches its message" do
|
|
20
22
|
expect(error.to_s).to eq(error.message)
|
|
21
23
|
end
|
|
@@ -25,6 +27,7 @@ describe Statesman do
|
|
|
25
27
|
subject(:error) { Statesman::InvalidTransitionError.new }
|
|
26
28
|
|
|
27
29
|
its(:message) { is_expected.to eq("Statesman::InvalidTransitionError") }
|
|
30
|
+
|
|
28
31
|
its "string matches its message" do
|
|
29
32
|
expect(error.to_s).to eq(error.message)
|
|
30
33
|
end
|
|
@@ -34,6 +37,7 @@ describe Statesman do
|
|
|
34
37
|
subject(:error) { Statesman::TransitionConflictError.new }
|
|
35
38
|
|
|
36
39
|
its(:message) { is_expected.to eq("Statesman::TransitionConflictError") }
|
|
40
|
+
|
|
37
41
|
its "string matches its message" do
|
|
38
42
|
expect(error.to_s).to eq(error.message)
|
|
39
43
|
end
|
|
@@ -43,6 +47,7 @@ describe Statesman do
|
|
|
43
47
|
subject(:error) { Statesman::MissingTransitionAssociation.new }
|
|
44
48
|
|
|
45
49
|
its(:message) { is_expected.to eq("Statesman::MissingTransitionAssociation") }
|
|
50
|
+
|
|
46
51
|
its "string matches its message" do
|
|
47
52
|
expect(error.to_s).to eq(error.message)
|
|
48
53
|
end
|
|
@@ -52,6 +57,7 @@ describe Statesman do
|
|
|
52
57
|
subject(:error) { Statesman::TransitionFailedError.new("from", "to") }
|
|
53
58
|
|
|
54
59
|
its(:message) { is_expected.to eq("Cannot transition from 'from' to 'to'") }
|
|
60
|
+
|
|
55
61
|
its "string matches its message" do
|
|
56
62
|
expect(error.to_s).to eq(error.message)
|
|
57
63
|
end
|
|
@@ -63,6 +69,7 @@ describe Statesman do
|
|
|
63
69
|
its(:message) do
|
|
64
70
|
is_expected.to eq("Guard on transition from: 'from' to 'to' returned false")
|
|
65
71
|
end
|
|
72
|
+
|
|
66
73
|
its "string matches its message" do
|
|
67
74
|
expect(error.to_s).to eq(error.message)
|
|
68
75
|
end
|
|
@@ -72,6 +79,7 @@ describe Statesman do
|
|
|
72
79
|
subject(:error) { Statesman::UnserializedMetadataError.new("foo") }
|
|
73
80
|
|
|
74
81
|
its(:message) { is_expected.to match(/foo#metadata is not serialized/) }
|
|
82
|
+
|
|
75
83
|
its "string matches its message" do
|
|
76
84
|
expect(error.to_s).to eq(error.message)
|
|
77
85
|
end
|
|
@@ -81,6 +89,7 @@ describe Statesman do
|
|
|
81
89
|
subject(:error) { Statesman::IncompatibleSerializationError.new("foo") }
|
|
82
90
|
|
|
83
91
|
its(:message) { is_expected.to match(/foo#metadata column type cannot be json/) }
|
|
92
|
+
|
|
84
93
|
its "string matches its message" do
|
|
85
94
|
expect(error.to_s).to eq(error.message)
|
|
86
95
|
end
|
|
@@ -234,11 +234,9 @@ describe Statesman::Machine do
|
|
|
234
234
|
|
|
235
235
|
it "does not add a callback" do
|
|
236
236
|
expect do
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
nil
|
|
241
|
-
end
|
|
237
|
+
set_callback
|
|
238
|
+
rescue error_type
|
|
239
|
+
nil
|
|
242
240
|
end.to_not change(machine.callbacks[callback_store], :count)
|
|
243
241
|
end
|
|
244
242
|
end
|
|
@@ -537,6 +535,34 @@ describe Statesman::Machine do
|
|
|
537
535
|
end
|
|
538
536
|
end
|
|
539
537
|
|
|
538
|
+
describe "#last_transition_to" do
|
|
539
|
+
subject { instance.last_transition_to(:y) }
|
|
540
|
+
|
|
541
|
+
before do
|
|
542
|
+
machine.class_eval do
|
|
543
|
+
state :x, initial: true
|
|
544
|
+
state :y
|
|
545
|
+
state :z
|
|
546
|
+
transition from: :x, to: :y
|
|
547
|
+
transition from: :y, to: :z
|
|
548
|
+
transition from: :z, to: :y
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
instance.transition_to!(:y)
|
|
552
|
+
instance.transition_to!(:z)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
let(:instance) { machine.new(my_model) }
|
|
556
|
+
|
|
557
|
+
it { is_expected.to have_attributes(to_state: "y") }
|
|
558
|
+
|
|
559
|
+
context "when there are 2 transitions to the state" do
|
|
560
|
+
before { instance.transition_to!(:y) }
|
|
561
|
+
|
|
562
|
+
it { is_expected.to eq(instance.last_transition) }
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
540
566
|
describe "#can_transition_to?" do
|
|
541
567
|
subject(:can_transition_to?) { instance.can_transition_to?(new_state, metadata) }
|
|
542
568
|
|
|
@@ -64,7 +64,7 @@ class CreateMyActiveRecordModelMigration < MIGRATION_CLASS
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
# TODO: make this a module we can extend from the app? Or a generator?
|
|
67
|
-
# rubocop:disable
|
|
67
|
+
# rubocop:disable Metrics/MethodLength
|
|
68
68
|
class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
69
69
|
def change
|
|
70
70
|
create_table :my_active_record_model_transitions do |t|
|
|
@@ -110,7 +110,7 @@ class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
end
|
|
113
|
-
# rubocop:enable
|
|
113
|
+
# rubocop:enable Metrics/MethodLength
|
|
114
114
|
|
|
115
115
|
class OtherActiveRecordModel < ActiveRecord::Base
|
|
116
116
|
has_many :other_active_record_model_transitions, autosave: false
|
|
@@ -144,7 +144,7 @@ class CreateOtherActiveRecordModelMigration < MIGRATION_CLASS
|
|
|
144
144
|
end
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
-
# rubocop:disable MethodLength
|
|
147
|
+
# rubocop:disable Metrics/MethodLength
|
|
148
148
|
class CreateOtherActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
149
149
|
def change
|
|
150
150
|
create_table :other_active_record_model_transitions do |t|
|
|
@@ -188,7 +188,7 @@ class CreateOtherActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
|
188
188
|
end
|
|
189
189
|
end
|
|
190
190
|
end
|
|
191
|
-
# rubocop:enable MethodLength
|
|
191
|
+
# rubocop:enable Metrics/MethodLength
|
|
192
192
|
|
|
193
193
|
class DropMostRecentColumn < MIGRATION_CLASS
|
|
194
194
|
def change
|
|
@@ -242,7 +242,7 @@ class CreateNamespacedARModelMigration < MIGRATION_CLASS
|
|
|
242
242
|
end
|
|
243
243
|
end
|
|
244
244
|
|
|
245
|
-
# rubocop:disable MethodLength
|
|
245
|
+
# rubocop:disable Metrics/MethodLength
|
|
246
246
|
class CreateNamespacedARModelTransitionMigration < MIGRATION_CLASS
|
|
247
247
|
def change
|
|
248
248
|
create_table :my_namespace_my_active_record_model_transitions do |t|
|
|
@@ -282,5 +282,5 @@ class CreateNamespacedARModelTransitionMigration < MIGRATION_CLASS
|
|
|
282
282
|
name: "index_namespace_model_transitions_parent_latest"
|
|
283
283
|
end
|
|
284
284
|
end
|
|
285
|
-
# rubocop:enable MethodLength
|
|
285
|
+
# rubocop:enable Metrics/MethodLength
|
|
286
286
|
end
|
data/statesman.gemspec
CHANGED
|
@@ -21,11 +21,11 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
22
22
|
spec.require_paths = ["lib"]
|
|
23
23
|
|
|
24
|
-
spec.required_ruby_version = ">= 2.
|
|
24
|
+
spec.required_ruby_version = ">= 2.5"
|
|
25
25
|
|
|
26
26
|
spec.add_development_dependency "ammeter", "~> 1.1"
|
|
27
|
-
spec.add_development_dependency "bundler", "~> 2
|
|
28
|
-
spec.add_development_dependency "gc_ruboconfig", "~> 2.
|
|
27
|
+
spec.add_development_dependency "bundler", "~> 2"
|
|
28
|
+
spec.add_development_dependency "gc_ruboconfig", "~> 2.26.0"
|
|
29
29
|
spec.add_development_dependency "mysql2", ">= 0.4", "< 0.6"
|
|
30
30
|
spec.add_development_dependency "pg", ">= 0.18", "<= 1.3"
|
|
31
31
|
spec.add_development_dependency "pry"
|
|
@@ -33,8 +33,8 @@ Gem::Specification.new do |spec|
|
|
|
33
33
|
spec.add_development_dependency "rake", "~> 13.0.0"
|
|
34
34
|
spec.add_development_dependency "rspec", "~> 3.1"
|
|
35
35
|
spec.add_development_dependency "rspec-its", "~> 1.1"
|
|
36
|
-
spec.add_development_dependency "rspec-rails", "~> 3.1"
|
|
37
36
|
spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.0"
|
|
37
|
+
spec.add_development_dependency "rspec-rails", "~> 3.1"
|
|
38
38
|
spec.add_development_dependency "sqlite3", "~> 1.4.2"
|
|
39
39
|
spec.add_development_dependency "timecop", "~> 0.9.1"
|
|
40
40
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: statesman
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 9.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GoCardless
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-02-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ammeter
|
|
@@ -30,28 +30,28 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 2
|
|
33
|
+
version: '2'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 2
|
|
40
|
+
version: '2'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: gc_ruboconfig
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 2.
|
|
47
|
+
version: 2.26.0
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 2.
|
|
54
|
+
version: 2.26.0
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: mysql2
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -163,33 +163,33 @@ dependencies:
|
|
|
163
163
|
- !ruby/object:Gem::Version
|
|
164
164
|
version: '1.1'
|
|
165
165
|
- !ruby/object:Gem::Dependency
|
|
166
|
-
name:
|
|
166
|
+
name: rspec_junit_formatter
|
|
167
167
|
requirement: !ruby/object:Gem::Requirement
|
|
168
168
|
requirements:
|
|
169
169
|
- - "~>"
|
|
170
170
|
- !ruby/object:Gem::Version
|
|
171
|
-
version:
|
|
171
|
+
version: 0.4.0
|
|
172
172
|
type: :development
|
|
173
173
|
prerelease: false
|
|
174
174
|
version_requirements: !ruby/object:Gem::Requirement
|
|
175
175
|
requirements:
|
|
176
176
|
- - "~>"
|
|
177
177
|
- !ruby/object:Gem::Version
|
|
178
|
-
version:
|
|
178
|
+
version: 0.4.0
|
|
179
179
|
- !ruby/object:Gem::Dependency
|
|
180
|
-
name:
|
|
180
|
+
name: rspec-rails
|
|
181
181
|
requirement: !ruby/object:Gem::Requirement
|
|
182
182
|
requirements:
|
|
183
183
|
- - "~>"
|
|
184
184
|
- !ruby/object:Gem::Version
|
|
185
|
-
version:
|
|
185
|
+
version: '3.1'
|
|
186
186
|
type: :development
|
|
187
187
|
prerelease: false
|
|
188
188
|
version_requirements: !ruby/object:Gem::Requirement
|
|
189
189
|
requirements:
|
|
190
190
|
- - "~>"
|
|
191
191
|
- !ruby/object:Gem::Version
|
|
192
|
-
version:
|
|
192
|
+
version: '3.1'
|
|
193
193
|
- !ruby/object:Gem::Dependency
|
|
194
194
|
name: sqlite3
|
|
195
195
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -226,9 +226,11 @@ extensions: []
|
|
|
226
226
|
extra_rdoc_files: []
|
|
227
227
|
files:
|
|
228
228
|
- ".circleci/config.yml"
|
|
229
|
+
- ".github/dependabot.yml"
|
|
229
230
|
- ".gitignore"
|
|
230
231
|
- ".rubocop.yml"
|
|
231
232
|
- ".rubocop_todo.yml"
|
|
233
|
+
- ".ruby-version"
|
|
232
234
|
- CHANGELOG.md
|
|
233
235
|
- CONTRIBUTING.md
|
|
234
236
|
- Gemfile
|
|
@@ -296,14 +298,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
296
298
|
requirements:
|
|
297
299
|
- - ">="
|
|
298
300
|
- !ruby/object:Gem::Version
|
|
299
|
-
version: '2.
|
|
301
|
+
version: '2.5'
|
|
300
302
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
301
303
|
requirements:
|
|
302
304
|
- - ">="
|
|
303
305
|
- !ruby/object:Gem::Version
|
|
304
306
|
version: '0'
|
|
305
307
|
requirements: []
|
|
306
|
-
rubygems_version: 3.
|
|
308
|
+
rubygems_version: 3.2.22
|
|
307
309
|
signing_key:
|
|
308
310
|
specification_version: 4
|
|
309
311
|
summary: A statesman-like state machine library
|