rails_state_machine 1.1.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7405883d16ed97fea524d9e02c5cdb77bbf10f74
4
- data.tar.gz: d89cd3f18ac39922e0967c0ba38954fb344a63fe
2
+ SHA256:
3
+ metadata.gz: d01a1094865abf2d8451c41a75bb4da8b5c1f457d46c88580045cf13ac5af2ea
4
+ data.tar.gz: f7575ce50426110e387c438974a30ed4b3511413506243f50537e15abd1baef6
5
5
  SHA512:
6
- metadata.gz: c5fb9fbf06507497454af5c86b217c2169ce2b43b364af076f2813496b891875ac70c66885fd054fdfc91e4f439ad11553414814f5d8594f86afd18af5f64349
7
- data.tar.gz: 5287318598d58c7725b05be343440a0c39c98f2da735bb7f27a25e6ff3bf8a648f455e4d7dbd3afca69c3e2324364b452566525e35e6b18256bdd2feb9b54dca
6
+ metadata.gz: 50ebcbd93b785b373721dc3d5ae6d84108c2a7d7942ce573f454c17198a63654a0782ea5bd4a797fb5220276af17addee8788d240ec4314df505aeced00dee1a
7
+ data.tar.gz: d28ec9396d3b28a2ba7b4741039e4ff2b9936fec67d0b7f7d3be89e62c4ac68f739871ed422b1b2a1f260f0fb422e55b0bd8b5da8d7cfc6073d973e70a293a90
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: Tests
3
+ 'on':
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ branches:
9
+ - master
10
+ jobs:
11
+ test_pg:
12
+ runs-on: ubuntu-20.04
13
+ services:
14
+ postgres:
15
+ image: postgres:9.3
16
+ env:
17
+ POSTGRES_PASSWORD: postgres
18
+ options: "--health-cmd pg_isready --health-interval 10s --health-timeout 5s
19
+ --health-retries 5"
20
+ ports:
21
+ - 5432:5432
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ include:
26
+ - ruby: 2.3.8
27
+ gemfile: Gemfile.5.1.pg
28
+ - ruby: 2.4.6
29
+ gemfile: Gemfile.5.1.pg
30
+ - ruby: 2.3.8
31
+ gemfile: Gemfile.5.2.pg
32
+ - ruby: 2.4.6
33
+ gemfile: Gemfile.5.2.pg
34
+ - ruby: 2.5.6
35
+ gemfile: Gemfile.5.2.pg
36
+ - ruby: 2.5.6
37
+ gemfile: Gemfile.6.0.pg
38
+ - ruby: 2.6.6
39
+ gemfile: Gemfile.6.0.pg
40
+ - ruby: 2.7.2
41
+ gemfile: Gemfile.6.0.pg
42
+ - ruby: 2.7.2
43
+ gemfile: Gemfile.6.1.pg
44
+ - ruby: 3.0.0
45
+ gemfile: Gemfile.6.1.pg
46
+ env:
47
+ BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
48
+ steps:
49
+ - uses: actions/checkout@v2
50
+ - name: Install ruby
51
+ uses: ruby/setup-ruby@v1
52
+ with:
53
+ ruby-version: "${{ matrix.ruby }}"
54
+ - name: Setup database
55
+ run: |
56
+ sudo apt-get install -y postgresql-client
57
+ PGPASSWORD=postgres psql -c 'create database rails_state_machine_test;' -U postgres -p 5432 -h localhost
58
+ - name: Bundle
59
+ run: |
60
+ gem install bundler:2.1.4
61
+ bundle install --no-deployment
62
+ - name: Run tests
63
+ run: bundle exec rspec
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.4.4
1
+ 2.4.6
data/CHANGELOG.md CHANGED
@@ -3,6 +3,50 @@ All notable changes to this project will be documented in this file.
3
3
 
4
4
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
5
5
 
6
+ ## Unreleased
7
+
8
+ ### Compatible changes
9
+
10
+ ### Breaking changes
11
+
12
+
13
+ ## 2.1.0 2021-03-30
14
+
15
+ ### Compatible changes
16
+
17
+ - Added support for Ruby 3.0.
18
+
19
+ ## 2.0.0 2019-09-30
20
+
21
+ ### Compatible changes
22
+
23
+ - Added: State machine can now use an attribute other than `state` to represent the machine's state.
24
+ - Added: It is now possible to define multiple state machines on the same model. States and event names
25
+ have to differ, though.
26
+
27
+ ### Breaking changes
28
+
29
+ - Removed: Dropped support for adding a state machine to a model without including `RailsStateMachine::Model`.
30
+
31
+
32
+ ## 1.1.3 2019-08-12
33
+
34
+ ### Compatible changes
35
+
36
+ - Fix a bug sometimes causing unsaved changes to be lost on state transitions.
37
+
38
+ ## 1.1.2 2019-03-22
39
+
40
+ ### Compatible changes
41
+
42
+ - Fix bug where state was set to an older state when making a record invalid after successfully transitioning to a new state.
43
+
44
+ ## 1.1.1 2019-03-22
45
+
46
+ ### Compatible changes
47
+
48
+ - Fix bug where state was set to `nil` by calling `valid?` on invalid records without making a state transition.
49
+
6
50
  ## 1.1.0 2019-02-07
7
51
 
8
52
  ### Compatible changes
data/Gemfile.5.1.pg.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_state_machine (1.1.0)
4
+ rails_state_machine (2.1.0)
5
5
  activerecord
6
6
 
7
7
  GEM
@@ -53,7 +53,7 @@ GEM
53
53
  database_cleaner (1.6.2)
54
54
  diff-lcs (1.3)
55
55
  erubi (1.7.0)
56
- gemika (0.3.2)
56
+ gemika (0.5.0)
57
57
  globalid (0.4.1)
58
58
  activesupport (>= 4.2.0)
59
59
  i18n (0.9.1)
@@ -146,4 +146,4 @@ DEPENDENCIES
146
146
  rspec (~> 3.5)
147
147
 
148
148
  BUNDLED WITH
149
- 1.17.1
149
+ 2.2.3
data/Gemfile.5.2.pg.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_state_machine (1.1.0)
4
+ rails_state_machine (2.1.0)
5
5
  activerecord
6
6
 
7
7
  GEM
@@ -57,7 +57,7 @@ GEM
57
57
  database_cleaner (1.7.0)
58
58
  diff-lcs (1.3)
59
59
  erubi (1.7.1)
60
- gemika (0.3.4)
60
+ gemika (0.5.0)
61
61
  globalid (0.4.1)
62
62
  activesupport (>= 4.2.0)
63
63
  i18n (1.1.0)
@@ -70,7 +70,9 @@ GEM
70
70
  marcel (0.3.2)
71
71
  mimemagic (~> 0.3.2)
72
72
  method_source (0.9.0)
73
- mimemagic (0.3.2)
73
+ mimemagic (0.3.10)
74
+ nokogiri (~> 1)
75
+ rake
74
76
  mini_mime (1.0.1)
75
77
  mini_portile2 (2.3.0)
76
78
  minitest (5.11.3)
@@ -154,4 +156,4 @@ DEPENDENCIES
154
156
  rspec (~> 3.5)
155
157
 
156
158
  BUNDLED WITH
157
- 1.17.1
159
+ 2.2.15
data/Gemfile.6.0.pg ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Runtime dependencies
4
+ gem 'rails', '~>6.0.0'
5
+ gem 'pg'
6
+
7
+ # Development dependencies
8
+ gem 'rspec', '~>3.5'
9
+ gem 'rake'
10
+ gem 'pry-byebug'
11
+ gem 'gemika'
12
+ gem 'database_cleaner'
13
+
14
+ # Gem under test
15
+ gem 'rails_state_machine', :path => '.'
@@ -0,0 +1,175 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rails_state_machine (2.1.0)
5
+ activerecord
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actioncable (6.0.0)
11
+ actionpack (= 6.0.0)
12
+ nio4r (~> 2.0)
13
+ websocket-driver (>= 0.6.1)
14
+ actionmailbox (6.0.0)
15
+ actionpack (= 6.0.0)
16
+ activejob (= 6.0.0)
17
+ activerecord (= 6.0.0)
18
+ activestorage (= 6.0.0)
19
+ activesupport (= 6.0.0)
20
+ mail (>= 2.7.1)
21
+ actionmailer (6.0.0)
22
+ actionpack (= 6.0.0)
23
+ actionview (= 6.0.0)
24
+ activejob (= 6.0.0)
25
+ mail (~> 2.5, >= 2.5.4)
26
+ rails-dom-testing (~> 2.0)
27
+ actionpack (6.0.0)
28
+ actionview (= 6.0.0)
29
+ activesupport (= 6.0.0)
30
+ rack (~> 2.0)
31
+ rack-test (>= 0.6.3)
32
+ rails-dom-testing (~> 2.0)
33
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
34
+ actiontext (6.0.0)
35
+ actionpack (= 6.0.0)
36
+ activerecord (= 6.0.0)
37
+ activestorage (= 6.0.0)
38
+ activesupport (= 6.0.0)
39
+ nokogiri (>= 1.8.5)
40
+ actionview (6.0.0)
41
+ activesupport (= 6.0.0)
42
+ builder (~> 3.1)
43
+ erubi (~> 1.4)
44
+ rails-dom-testing (~> 2.0)
45
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
46
+ activejob (6.0.0)
47
+ activesupport (= 6.0.0)
48
+ globalid (>= 0.3.6)
49
+ activemodel (6.0.0)
50
+ activesupport (= 6.0.0)
51
+ activerecord (6.0.0)
52
+ activemodel (= 6.0.0)
53
+ activesupport (= 6.0.0)
54
+ activestorage (6.0.0)
55
+ actionpack (= 6.0.0)
56
+ activejob (= 6.0.0)
57
+ activerecord (= 6.0.0)
58
+ marcel (~> 0.3.1)
59
+ activesupport (6.0.0)
60
+ concurrent-ruby (~> 1.0, >= 1.0.2)
61
+ i18n (>= 0.7, < 2)
62
+ minitest (~> 5.1)
63
+ tzinfo (~> 1.1)
64
+ zeitwerk (~> 2.1, >= 2.1.8)
65
+ builder (3.2.3)
66
+ byebug (10.0.2)
67
+ coderay (1.1.2)
68
+ concurrent-ruby (1.1.5)
69
+ crass (1.0.4)
70
+ database_cleaner (1.7.0)
71
+ diff-lcs (1.3)
72
+ erubi (1.9.0)
73
+ gemika (0.5.0)
74
+ globalid (0.4.2)
75
+ activesupport (>= 4.2.0)
76
+ i18n (1.6.0)
77
+ concurrent-ruby (~> 1.0)
78
+ loofah (2.3.0)
79
+ crass (~> 1.0.2)
80
+ nokogiri (>= 1.5.9)
81
+ mail (2.7.1)
82
+ mini_mime (>= 0.1.1)
83
+ marcel (0.3.3)
84
+ mimemagic (~> 0.3.2)
85
+ method_source (0.9.2)
86
+ mimemagic (0.3.10)
87
+ nokogiri (~> 1)
88
+ rake
89
+ mini_mime (1.0.2)
90
+ mini_portile2 (2.4.0)
91
+ minitest (5.12.2)
92
+ nio4r (2.5.2)
93
+ nokogiri (1.10.4)
94
+ mini_portile2 (~> 2.4.0)
95
+ pg (1.1.2)
96
+ pry (0.11.3)
97
+ coderay (~> 1.1.0)
98
+ method_source (~> 0.9.0)
99
+ pry-byebug (3.6.0)
100
+ byebug (~> 10.0)
101
+ pry (~> 0.10)
102
+ rack (2.0.7)
103
+ rack-test (1.1.0)
104
+ rack (>= 1.0, < 3)
105
+ rails (6.0.0)
106
+ actioncable (= 6.0.0)
107
+ actionmailbox (= 6.0.0)
108
+ actionmailer (= 6.0.0)
109
+ actionpack (= 6.0.0)
110
+ actiontext (= 6.0.0)
111
+ actionview (= 6.0.0)
112
+ activejob (= 6.0.0)
113
+ activemodel (= 6.0.0)
114
+ activerecord (= 6.0.0)
115
+ activestorage (= 6.0.0)
116
+ activesupport (= 6.0.0)
117
+ bundler (>= 1.3.0)
118
+ railties (= 6.0.0)
119
+ sprockets-rails (>= 2.0.0)
120
+ rails-dom-testing (2.0.3)
121
+ activesupport (>= 4.2.0)
122
+ nokogiri (>= 1.6)
123
+ rails-html-sanitizer (1.2.0)
124
+ loofah (~> 2.2, >= 2.2.2)
125
+ railties (6.0.0)
126
+ actionpack (= 6.0.0)
127
+ activesupport (= 6.0.0)
128
+ method_source
129
+ rake (>= 0.8.7)
130
+ thor (>= 0.20.3, < 2.0)
131
+ rake (13.0.0)
132
+ rspec (3.8.0)
133
+ rspec-core (~> 3.8.0)
134
+ rspec-expectations (~> 3.8.0)
135
+ rspec-mocks (~> 3.8.0)
136
+ rspec-core (3.8.0)
137
+ rspec-support (~> 3.8.0)
138
+ rspec-expectations (3.8.1)
139
+ diff-lcs (>= 1.2.0, < 2.0)
140
+ rspec-support (~> 3.8.0)
141
+ rspec-mocks (3.8.0)
142
+ diff-lcs (>= 1.2.0, < 2.0)
143
+ rspec-support (~> 3.8.0)
144
+ rspec-support (3.8.0)
145
+ sprockets (3.7.2)
146
+ concurrent-ruby (~> 1.0)
147
+ rack (> 1, < 3)
148
+ sprockets-rails (3.2.1)
149
+ actionpack (>= 4.0)
150
+ activesupport (>= 4.0)
151
+ sprockets (>= 3.0.0)
152
+ thor (0.20.3)
153
+ thread_safe (0.3.6)
154
+ tzinfo (1.2.5)
155
+ thread_safe (~> 0.1)
156
+ websocket-driver (0.7.1)
157
+ websocket-extensions (>= 0.1.0)
158
+ websocket-extensions (0.1.4)
159
+ zeitwerk (2.1.10)
160
+
161
+ PLATFORMS
162
+ ruby
163
+
164
+ DEPENDENCIES
165
+ database_cleaner
166
+ gemika
167
+ pg
168
+ pry-byebug
169
+ rails (~> 6.0.0)
170
+ rails_state_machine!
171
+ rake
172
+ rspec (~> 3.5)
173
+
174
+ BUNDLED WITH
175
+ 2.1.4
data/Gemfile.6.1.pg ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Runtime dependencies
4
+ gem 'rails', '~>6.1.0'
5
+ gem 'pg'
6
+
7
+ # Development dependencies
8
+ gem 'rspec', '~>3.5'
9
+ gem 'rake'
10
+ gem 'pry-byebug'
11
+ gem 'gemika'
12
+ gem 'database_cleaner'
13
+
14
+ # Gem under test
15
+ gem 'rails_state_machine', :path => '.'
@@ -0,0 +1,181 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rails_state_machine (2.1.0)
5
+ activerecord
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actioncable (6.1.3.1)
11
+ actionpack (= 6.1.3.1)
12
+ activesupport (= 6.1.3.1)
13
+ nio4r (~> 2.0)
14
+ websocket-driver (>= 0.6.1)
15
+ actionmailbox (6.1.3.1)
16
+ actionpack (= 6.1.3.1)
17
+ activejob (= 6.1.3.1)
18
+ activerecord (= 6.1.3.1)
19
+ activestorage (= 6.1.3.1)
20
+ activesupport (= 6.1.3.1)
21
+ mail (>= 2.7.1)
22
+ actionmailer (6.1.3.1)
23
+ actionpack (= 6.1.3.1)
24
+ actionview (= 6.1.3.1)
25
+ activejob (= 6.1.3.1)
26
+ activesupport (= 6.1.3.1)
27
+ mail (~> 2.5, >= 2.5.4)
28
+ rails-dom-testing (~> 2.0)
29
+ actionpack (6.1.3.1)
30
+ actionview (= 6.1.3.1)
31
+ activesupport (= 6.1.3.1)
32
+ rack (~> 2.0, >= 2.0.9)
33
+ rack-test (>= 0.6.3)
34
+ rails-dom-testing (~> 2.0)
35
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
36
+ actiontext (6.1.3.1)
37
+ actionpack (= 6.1.3.1)
38
+ activerecord (= 6.1.3.1)
39
+ activestorage (= 6.1.3.1)
40
+ activesupport (= 6.1.3.1)
41
+ nokogiri (>= 1.8.5)
42
+ actionview (6.1.3.1)
43
+ activesupport (= 6.1.3.1)
44
+ builder (~> 3.1)
45
+ erubi (~> 1.4)
46
+ rails-dom-testing (~> 2.0)
47
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
48
+ activejob (6.1.3.1)
49
+ activesupport (= 6.1.3.1)
50
+ globalid (>= 0.3.6)
51
+ activemodel (6.1.3.1)
52
+ activesupport (= 6.1.3.1)
53
+ activerecord (6.1.3.1)
54
+ activemodel (= 6.1.3.1)
55
+ activesupport (= 6.1.3.1)
56
+ activestorage (6.1.3.1)
57
+ actionpack (= 6.1.3.1)
58
+ activejob (= 6.1.3.1)
59
+ activerecord (= 6.1.3.1)
60
+ activesupport (= 6.1.3.1)
61
+ marcel (~> 1.0.0)
62
+ mini_mime (~> 1.0.2)
63
+ activesupport (6.1.3.1)
64
+ concurrent-ruby (~> 1.0, >= 1.0.2)
65
+ i18n (>= 1.6, < 2)
66
+ minitest (>= 5.1)
67
+ tzinfo (~> 2.0)
68
+ zeitwerk (~> 2.3)
69
+ builder (3.2.4)
70
+ byebug (11.1.3)
71
+ coderay (1.1.3)
72
+ concurrent-ruby (1.1.8)
73
+ crass (1.0.6)
74
+ database_cleaner (2.0.1)
75
+ database_cleaner-active_record (~> 2.0.0)
76
+ database_cleaner-active_record (2.0.0)
77
+ activerecord (>= 5.a)
78
+ database_cleaner-core (~> 2.0.0)
79
+ database_cleaner-core (2.0.1)
80
+ diff-lcs (1.4.4)
81
+ erubi (1.10.0)
82
+ gemika (0.5.0)
83
+ globalid (0.4.2)
84
+ activesupport (>= 4.2.0)
85
+ i18n (1.8.9)
86
+ concurrent-ruby (~> 1.0)
87
+ loofah (2.9.0)
88
+ crass (~> 1.0.2)
89
+ nokogiri (>= 1.5.9)
90
+ mail (2.7.1)
91
+ mini_mime (>= 0.1.1)
92
+ marcel (1.0.0)
93
+ method_source (1.0.0)
94
+ mini_mime (1.0.3)
95
+ mini_portile2 (2.5.0)
96
+ minitest (5.14.4)
97
+ nio4r (2.5.7)
98
+ nokogiri (1.11.2)
99
+ mini_portile2 (~> 2.5.0)
100
+ racc (~> 1.4)
101
+ pg (1.2.3)
102
+ pry (0.13.1)
103
+ coderay (~> 1.1)
104
+ method_source (~> 1.0)
105
+ pry-byebug (3.9.0)
106
+ byebug (~> 11.0)
107
+ pry (~> 0.13.0)
108
+ racc (1.5.2)
109
+ rack (2.2.3)
110
+ rack-test (1.1.0)
111
+ rack (>= 1.0, < 3)
112
+ rails (6.1.3.1)
113
+ actioncable (= 6.1.3.1)
114
+ actionmailbox (= 6.1.3.1)
115
+ actionmailer (= 6.1.3.1)
116
+ actionpack (= 6.1.3.1)
117
+ actiontext (= 6.1.3.1)
118
+ actionview (= 6.1.3.1)
119
+ activejob (= 6.1.3.1)
120
+ activemodel (= 6.1.3.1)
121
+ activerecord (= 6.1.3.1)
122
+ activestorage (= 6.1.3.1)
123
+ activesupport (= 6.1.3.1)
124
+ bundler (>= 1.15.0)
125
+ railties (= 6.1.3.1)
126
+ sprockets-rails (>= 2.0.0)
127
+ rails-dom-testing (2.0.3)
128
+ activesupport (>= 4.2.0)
129
+ nokogiri (>= 1.6)
130
+ rails-html-sanitizer (1.3.0)
131
+ loofah (~> 2.3)
132
+ railties (6.1.3.1)
133
+ actionpack (= 6.1.3.1)
134
+ activesupport (= 6.1.3.1)
135
+ method_source
136
+ rake (>= 0.8.7)
137
+ thor (~> 1.0)
138
+ rake (13.0.3)
139
+ rspec (3.10.0)
140
+ rspec-core (~> 3.10.0)
141
+ rspec-expectations (~> 3.10.0)
142
+ rspec-mocks (~> 3.10.0)
143
+ rspec-core (3.10.1)
144
+ rspec-support (~> 3.10.0)
145
+ rspec-expectations (3.10.1)
146
+ diff-lcs (>= 1.2.0, < 2.0)
147
+ rspec-support (~> 3.10.0)
148
+ rspec-mocks (3.10.2)
149
+ diff-lcs (>= 1.2.0, < 2.0)
150
+ rspec-support (~> 3.10.0)
151
+ rspec-support (3.10.2)
152
+ sprockets (4.0.2)
153
+ concurrent-ruby (~> 1.0)
154
+ rack (> 1, < 3)
155
+ sprockets-rails (3.2.2)
156
+ actionpack (>= 4.0)
157
+ activesupport (>= 4.0)
158
+ sprockets (>= 3.0.0)
159
+ thor (1.1.0)
160
+ tzinfo (2.0.4)
161
+ concurrent-ruby (~> 1.0)
162
+ websocket-driver (0.7.3)
163
+ websocket-extensions (>= 0.1.0)
164
+ websocket-extensions (0.1.5)
165
+ zeitwerk (2.4.2)
166
+
167
+ PLATFORMS
168
+ ruby
169
+
170
+ DEPENDENCIES
171
+ database_cleaner
172
+ gemika
173
+ pg
174
+ pry-byebug
175
+ rails (~> 6.1.0)
176
+ rails_state_machine!
177
+ rake
178
+ rspec (~> 3.5)
179
+
180
+ BUNDLED WITH
181
+ 2.2.3
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
- # Rails State Machine
2
- [![Build Status](https://travis-ci.org/makandra/rails_state_machine.svg?branch=master)](https://travis-ci.org/makandra/rails_state_machine)
1
+ # Rails State Machine [![Tests](https://github.com/makandra/rails_state_machine/workflows/Tests/badge.svg)](https://github.com/makandra/rails_state_machine/actions?query=branch:master)
3
2
 
4
3
  Rails State Machine is a ActiveRecord-bound state machine.
5
4
 
@@ -71,39 +70,6 @@ event :request_feedback do
71
70
  end
72
71
  ```
73
72
 
74
- As an alternative to using `RailsStateMachine::Model` and `state_machine do`, configure the state machine manually. This only adds the `state_machine` to your model, but no `states` or `state_events`.
75
-
76
- ```ruby
77
- class YourModel < ApplicationRecord
78
- RailsStateMachine::StateMachine.new(self).configure do
79
- state :draft, initial: true
80
- state :review_pending
81
- state :approved
82
- state :rejected
83
-
84
- event :request_review do
85
- transitions from: [:draft, :rejected], to: :review_pending
86
- end
87
-
88
- event :approve do
89
- transitions from: :review_pending, to: :approved
90
- end
91
-
92
- event :reject do
93
- transitions from: :review_pending, to: :rejected
94
- end
95
- end
96
-
97
- def self.states
98
- state_machine.state_names
99
- end
100
-
101
- def self.state_events
102
- state_machine.event_names
103
- end
104
- end
105
- ```
106
-
107
73
  ## Event callbacks
108
74
 
109
75
  Here is a list with all the available callbacks, listed in the same order in which they will get called during the respective operations. The callbacks are chained with the existing active record callbacks on the model.
@@ -137,19 +103,60 @@ event :request_review do
137
103
  end
138
104
  ```
139
105
 
106
+ ## Other state attributes and multiple state machines on the same model
107
+
108
+ To use a state attribute other than the default `state`, pass it to the `.state_machine` method:
109
+
110
+ ```
111
+ state_machine :review_state do
112
+ # ...
113
+ end
114
+ ```
115
+
116
+ This also allows you to define multiple state machines on the same model. Note that event
117
+ and state names still have to be unique for the whole model.
118
+
119
+
120
+ ## Taking multiple transitions
121
+
122
+ You can safely take a second transition inside an after_save callback. All relevant
123
+ callbacks will be run.
124
+
125
+ ```
126
+ state_machine do
127
+ state :draft, initial: true
128
+ state :review_pending
129
+ state :approved
130
+
131
+ event :request_review do
132
+ transitions from: [:draft, :rejected], to: :review_pending
133
+
134
+ after_save do
135
+ if auto_approve?
136
+ approve
137
+ end
138
+ end
139
+ end
140
+
141
+ event :approve do
142
+ transitions from: :review_pending, to: :approved
143
+ end
144
+ end
145
+ ```
146
+
140
147
  ## Development
141
148
 
142
149
  There are tests in `spec`. We only accept PRs with tests. To run tests:
143
150
 
144
- - Install Ruby 2.4.4
151
+ - Install Ruby 2.4.6
145
152
  - Copy the file `spec/support/database.sample.yml` to `spec/support/database.yml` and enter your PostgreSQL credentials. You can create the database afterwards with `createdb rails_state_machine_test`.
146
153
  - Run `bin/setup` to install development dependencies.
147
154
  - Run tests using `bundle exec rspec`
148
155
 
149
- We recommend to test large changes against multiple versions of Ruby and multiple dependency sets. Supported combinations are configured in `.travis.yml`. We provide some rake tasks to help with this:
156
+ We recommend to test large changes against multiple versions of Ruby and multiple dependency sets. Supported combinations are configured in `.github/workflows/test.yml`. We provide some rake tasks to help with this:
150
157
 
151
- - Install development dependencies using `bundle matrix:install`
152
- - Run tests using `bundle matrix:spec`
158
+ - Install development dependencies using `rake matrix:install`
159
+ - Run tests using `rake matrix:spec`
153
160
 
154
161
  You can also run `bin/console` for an interactive prompt that will allow you to experiment.
155
162
 
@@ -167,7 +174,7 @@ If you would like to contribute:
167
174
 
168
175
  We want to keep this gem leightweight and on topic. If you are unsure whether a change would make it into the gem, open an issue and discuss.
169
176
 
170
- Note that we have configured Travis CI to automatically run tests in all supported Ruby versions and dependency sets after each push. We will only merge pull requests after a green Travis build.
177
+ Note that we have configured GitHub Actions to automatically run tests in all supported Ruby versions and dependency sets after each push. We will only merge pull requests after a green workflow build.
171
178
 
172
179
  ## License
173
180
 
@@ -175,4 +182,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
175
182
 
176
183
  ## Credits
177
184
 
178
- Arne Hartherz and Emanuel Denzel from [makandra](https://makandra.de/).
185
+ Arne Hartherz, Emanuel Denzel, Tobias Kraze from [makandra](https://makandra.de/).
@@ -1,5 +1,7 @@
1
1
  require 'rails_state_machine/version'
2
2
  require 'rails_state_machine/state'
3
3
  require 'rails_state_machine/event'
4
+ require 'rails_state_machine/callbacks'
4
5
  require 'rails_state_machine/state_machine'
6
+ require 'rails_state_machine/state_manager'
5
7
  require 'rails_state_machine/model'
@@ -0,0 +1,68 @@
1
+ module RailsStateMachine
2
+ module Callbacks
3
+ class << self
4
+ def included(model)
5
+ register_callbacks(model)
6
+ register_validations(model)
7
+ end
8
+
9
+ private
10
+
11
+ def register_callbacks(model)
12
+ model.class_eval do
13
+ before_validation :run_state_events_before_validation
14
+ before_save :register_state_events_for_callbacks
15
+ before_save { flush_state_event_callbacks(:before_save) }
16
+ after_save { flush_state_event_callbacks(:after_save) }
17
+ after_commit { flush_state_event_callbacks(:after_commit) }
18
+ end
19
+ end
20
+
21
+ def register_validations(model)
22
+ model.class_eval do
23
+ after_validation :revert_states, if: -> { errors.any? }
24
+ end
25
+ end
26
+ end
27
+
28
+ def run_state_events_before_validation
29
+ # Since validations may be skipped, we will not register validation callbacks in @state_event_callbacks,
30
+ # but call them explicitly when before_validation callbacks are triggered.
31
+ state_machine_state_managers.each do |state_manager|
32
+ state_manager.next_event&.run_before_validation(self)
33
+ end
34
+ end
35
+
36
+ def register_state_events_for_callbacks
37
+ @state_event_callbacks ||= {
38
+ before_save: [],
39
+ after_save: [],
40
+ after_commit: []
41
+ }
42
+ state_machine_state_managers.each do |state_manager|
43
+ if (next_event = state_manager.next_event)
44
+ @state_event_callbacks[:before_save] << next_event
45
+ @state_event_callbacks[:after_save] << next_event
46
+ @state_event_callbacks[:after_commit] << next_event
47
+ state_manager.next_event = nil
48
+ end
49
+ end
50
+
51
+ true
52
+ end
53
+
54
+ def flush_state_event_callbacks(name)
55
+ if @state_event_callbacks
56
+ while (event = @state_event_callbacks[name].shift)
57
+ event.public_send("run_#{name}", self)
58
+ end
59
+ end
60
+ end
61
+
62
+ def revert_states
63
+ state_machine_state_managers.each do |state_manager|
64
+ state_manager.revert
65
+ end
66
+ end
67
+ end
68
+ end
@@ -26,7 +26,7 @@ module RailsStateMachine
26
26
 
27
27
  def transitions(**options)
28
28
  if options.present?
29
- add_transitions(options)
29
+ add_transitions(**options)
30
30
  else
31
31
  @transitions_by_state_name.values
32
32
  end
@@ -1,21 +1,71 @@
1
1
  module RailsStateMachine
2
+ DEFAULT_STATE_ATTRIBUTE = :state
3
+
2
4
  module Model
3
5
  def self.included(base)
4
- base.extend ClassMethods
6
+ base.class_eval do
7
+ extend ClassMethods
8
+
9
+ cattr_accessor :state_machines
10
+ self.state_machines = {}
11
+
12
+ delegate :state_machine, to: :class
13
+ end
5
14
  end
6
15
 
7
16
  module ClassMethods
8
- def state_machine(&block)
9
- StateMachine.new(self).configure(&block)
17
+ def state_machine(state_attribute = DEFAULT_STATE_ATTRIBUTE, &block)
18
+ state_machine = state_machines[state_attribute] ||= StateMachine.new(self, state_attribute)
19
+ if block
20
+ include(Callbacks) unless self < Callbacks
21
+ state_machine.configure(&block)
22
+ end
23
+ state_machine
24
+ end
25
+
26
+ def states(state_attribute = DEFAULT_STATE_ATTRIBUTE)
27
+ state_machine(state_attribute).state_names
28
+ end
29
+
30
+ def state_events(state_attribute = DEFAULT_STATE_ATTRIBUTE)
31
+ state_machine(state_attribute).event_names
10
32
  end
33
+ end
34
+
35
+
36
+ private
11
37
 
12
- def states
13
- state_machine.state_names
38
+ def state_machine_state_manager(state_attribute)
39
+ @state_machine_state_managers ||= {}
40
+ @state_machine_state_managers[state_attribute] ||= StateManager.new(self, state_machine(state_attribute), state_attribute)
41
+ end
42
+
43
+ def state_machine_state_managers
44
+ self.state_machines.keys.collect do |state_attribute|
45
+ state_machine_state_manager(state_attribute)
14
46
  end
47
+ end
15
48
 
16
- def state_events
17
- state_machine.event_names
49
+ def prepare_state_event_change(attributes)
50
+ if ActiveRecord::VERSION::STRING < '5.2' && saved_changes?
51
+ # After calling `save`, ActiveRecord 5.1 will flag the changes that it just stored as saved.
52
+ # https://github.com/rails/rails/blob/v5.1.4/activerecord/lib/active_record/attribute_methods/dirty.rb#L33-L46
53
+ #
54
+ # When taking multiple state events (e.g. a second event called inside an `after_save` callback) and thus
55
+ # saving after other changes were just saved, we need to mimic that behavior. Otherwise, ActiveRecord will
56
+ # print deprecation warnings like these:
57
+ #
58
+ # DEPRECATION WARNING: The behavior of `attribute_was` inside of after callbacks will be changing in the
59
+ # next version of Rails. The new return value will reflect the behavior of calling the method after
60
+ # `save` returned (e.g. the opposite of what it returns now). To maintain the current behavior, use
61
+ # `attribute_before_last_save` instead.
62
+ #
63
+ # These actually originate from ActiveRecord internals which try to determine the changes that should be
64
+ # stored for the second save. It is probably a shortcoming of ActiveRecord 5.1.x that will be fixed, but
65
+ # since the current/previous save was already successful, the right action is to just call `changes_applied`.
66
+ changes_applied
18
67
  end
68
+ self.attributes = attributes
19
69
  end
20
70
  end
21
71
  end
@@ -1,13 +1,13 @@
1
1
  module RailsStateMachine
2
2
  class StateMachine
3
- def initialize(model)
4
- @model = model
5
-
6
- model_constant('StateMachineMethods', Module.new)
7
- @model.include(@model::StateMachineMethods)
3
+ attr_reader :model
8
4
 
5
+ def initialize(model, state_attribute)
6
+ @model = model
7
+ @state_attribute = state_attribute
9
8
  @states_by_name = {}
10
9
  @events_by_name = {}
10
+ build_model_module
11
11
  end
12
12
 
13
13
  def configure(&block)
@@ -18,11 +18,6 @@ module RailsStateMachine
18
18
  register_initial_state
19
19
 
20
20
  define_event_methods
21
-
22
- register_callbacks
23
- register_validations
24
- register_state_machine
25
-
26
21
  define_model_methods
27
22
  end
28
23
 
@@ -53,25 +48,13 @@ module RailsStateMachine
53
48
  private
54
49
 
55
50
  def state(name, **options)
56
- @states_by_name[name] = State.new(name, options)
51
+ @states_by_name[name] = State.new(name, **options)
57
52
  end
58
53
 
59
54
  def event(name, &block)
60
55
  event = Event.new(name, self)
61
56
  event.configure(&block)
62
57
 
63
- model_methods do
64
- define_method "#{event.name}" do |**attributes|
65
- prepare_state_event_change(attributes.merge(state_event: event.name))
66
- save
67
- end
68
-
69
- define_method "#{event.name}!" do |**attributes|
70
- prepare_state_event_change(attributes.merge(state_event: event.name))
71
- save!
72
- end
73
- end
74
-
75
58
  @events_by_name[name] = event
76
59
  end
77
60
 
@@ -79,18 +62,24 @@ module RailsStateMachine
79
62
  @model.const_set(name, value)
80
63
  end
81
64
 
82
- def model_methods(&block)
65
+ def build_model_module
83
66
  # Using a state machine defines several methods on the model.
84
67
  # The model should be able to re-define them and `super` into the original method, if necessary.
85
68
  # For that, we use a module to store all methods. The module is loaded into the model class.
86
- @model::StateMachineMethods.module_eval(&block)
69
+ @model_module = Module.new
70
+ @model.include(@model_module)
71
+ end
72
+
73
+ def model_module_eval(&block)
74
+ @model_module.module_eval(&block)
87
75
  end
88
76
 
89
77
  def define_state_methods
78
+ state_attribute = @state_attribute
90
79
  state_names.each do |state_name|
91
- model_methods do
80
+ model_module_eval do
92
81
  define_method "#{state_name}?" do
93
- self.state.to_s == state_name.to_s
82
+ state_machine_state_manager(state_attribute).state == state_name.to_s
94
83
  end
95
84
  end
96
85
  end
@@ -103,130 +92,49 @@ module RailsStateMachine
103
92
  end
104
93
 
105
94
  def register_initial_state
106
- initial_state = states.detect(&:initial?)
107
- return unless initial_state
95
+ state_attribute = @state_attribute
96
+ initial_state_name = states.detect(&:initial?)&.name
97
+ return unless initial_state_name
108
98
 
109
99
  @model.after_initialize do
110
- self.state ||= initial_state.name if new_record?
100
+ manager = state_machine_state_manager(state_attribute)
101
+ if new_record? && !manager.state
102
+ manager.state = initial_state_name
103
+ end
111
104
  end
112
105
  end
113
106
 
114
107
  def define_event_methods
108
+ state_attribute = @state_attribute
115
109
  event_names.each do |event_name, event|
116
- model_methods do
117
- define_method "may_#{event_name}?" do
118
- state_machine.find_event(event_name).allowed_from?(source_state)
110
+ model_module_eval do
111
+ define_method "#{event_name}" do |**attributes|
112
+ prepare_state_event_change(attributes.merge("#{state_attribute}_event": event_name))
113
+ save
119
114
  end
120
- end
121
- end
122
- end
123
-
124
- def register_callbacks
125
- @model.class_eval do
126
- before_validation :run_state_event_before_validation
127
- before_save :register_state_events_for_callbacks
128
- before_save { flush_state_event_callbacks(:before_save) }
129
- after_save { flush_state_event_callbacks(:after_save) }
130
- after_commit { flush_state_event_callbacks(:after_commit) }
131
- end
132
- end
133
-
134
- def register_validations
135
- @model.class_eval do
136
- after_validation :revert_state, if: -> { errors.any? }
137
- end
138
- end
139
115
 
140
- def register_state_machine
141
- @model.class_eval do
142
- cattr_accessor :state_machine
143
- delegate :state_machine, to: :class
144
- end
145
-
146
- @model.state_machine = self
147
- end
148
-
149
- def define_model_methods
150
- model_methods do
151
- def state_event=(event_name)
152
- @next_state_machine_event = state_machine.find_event(event_name)
153
- @state_before_state_event = source_state
154
-
155
- # If the event can not transition from source_state, a TransitionNotFoundError will be raised
156
- self.state = @next_state_machine_event.future_state_name(source_state).to_s
157
- end
158
-
159
- def state_event
160
- @next_state_machine_event&.name
161
- end
162
-
163
- def source_state
164
- if new_record?
165
- state
166
- else
167
- state_in_database
116
+ define_method "#{event_name}!" do |**attributes|
117
+ prepare_state_event_change(attributes.merge("#{state_attribute}_event": event_name))
118
+ save!
168
119
  end
169
- end
170
-
171
- private
172
120
 
173
- def run_state_event_before_validation
174
- # Since validations may be skipped, we will not register validation callbacks in @state_event_callbacks,
175
- # but call them explicitly when before_validation callbacks are triggered.
176
- @next_state_machine_event&.run_before_validation(self)
177
- end
178
-
179
- def register_state_events_for_callbacks
180
- @state_event_callbacks ||= {
181
- before_save: [],
182
- after_save: [],
183
- after_commit: []
184
- }
185
- if @next_state_machine_event
186
- @state_event_callbacks[:before_save] << @next_state_machine_event
187
- @state_event_callbacks[:after_save] << @next_state_machine_event
188
- @state_event_callbacks[:after_commit] << @next_state_machine_event
189
- end
190
-
191
- true
192
- end
193
-
194
- def flush_state_event_callbacks(name)
195
- if @state_event_callbacks
196
- while (event = @state_event_callbacks[name].shift)
197
- event.public_send("run_#{name}", self)
198
- end
121
+ define_method "may_#{event_name}?" do
122
+ state_machine_state_manager(state_attribute).transition_allowed_for?(event_name)
199
123
  end
200
124
  end
125
+ end
126
+ end
201
127
 
202
- def unset_next_state_machine_event
203
- @next_state_machine_event = nil
204
- end
128
+ def define_model_methods
129
+ state_attribute = @state_attribute
205
130
 
206
- def revert_state
207
- self.state = @state_before_state_event
131
+ model_module_eval do
132
+ define_method :"#{state_attribute}_event=" do |event_name|
133
+ state_machine_state_manager(state_attribute).transition_to(event_name)
208
134
  end
209
135
 
210
- def prepare_state_event_change(attributes)
211
- if saved_changes?
212
- # After calling `save`, ActiveRecord will flag the changes that it just stored as saved.
213
- # https://github.com/rails/rails/blob/v5.1.4/activerecord/lib/active_record/attribute_methods/dirty.rb#L33-L46
214
- #
215
- # When taking multiple state events (e.g. a second event called inside an `after_save` callback) and thus
216
- # saving after other changes were just saved, we need to mimic that behavior. Otherwise, ActiveRecord will
217
- # print deprecation warnings like these:
218
- #
219
- # DEPRECATION WARNING: The behavior of `attribute_was` inside of after callbacks will be changing in the
220
- # next version of Rails. The new return value will reflect the behavior of calling the method after
221
- # `save` returned (e.g. the opposite of what it returns now). To maintain the current behavior, use
222
- # `attribute_before_last_save` instead.
223
- #
224
- # These actually originate from ActiveRecord internals which try to determine the changes that should be
225
- # stored for the second save. It is probably a shortcoming of ActiveRecord 5.1.x that will be fixed, but
226
- # since the current/previous save was already successful, the right action is to just call `changes_applied`.
227
- changes_applied
228
- end
229
- self.attributes = attributes
136
+ define_method :"#{state_attribute}_event" do
137
+ state_machine_state_manager(state_attribute).next_event&.name
230
138
  end
231
139
  end
232
140
  end
@@ -0,0 +1,47 @@
1
+ module RailsStateMachine
2
+ class StateManager
3
+ attr_accessor :next_event, :state_before_state_event
4
+
5
+ def initialize(record, state_machine, state_attribute)
6
+ @record = record
7
+ @state_machine = state_machine
8
+ @state_attribute = state_attribute
9
+ end
10
+
11
+ def state
12
+ @record.public_send(@state_attribute)
13
+ end
14
+
15
+ def state_in_database
16
+ @record.public_send(:"#{@state_attribute}_in_database").to_s
17
+ end
18
+
19
+ def state=(value)
20
+ @record.public_send(:"#{@state_attribute}=", value)
21
+ end
22
+
23
+ def revert
24
+ self.state = @state_before_state_event if @next_event
25
+ end
26
+
27
+ def source_state
28
+ if @record.new_record?
29
+ state
30
+ else
31
+ state_in_database
32
+ end
33
+ end
34
+
35
+ def transition_to(event_name)
36
+ @next_event = @state_machine.find_event(event_name)
37
+ @state_before_state_event = source_state
38
+
39
+ # If the event can not transition from source_state, a TransitionNotFoundError will be raised
40
+ self.state = @next_event.future_state_name(source_state).to_s
41
+ end
42
+
43
+ def transition_allowed_for?(event_name)
44
+ @state_machine.find_event(event_name).allowed_from?(source_state)
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsStateMachine
2
- VERSION = '1.1.0'
2
+ VERSION = '2.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_state_machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arne Hartherz
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-02-07 00:00:00.000000000 Z
12
+ date: 2021-03-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -74,16 +74,20 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
+ - ".github/workflows/test.yml"
77
78
  - ".gitignore"
78
79
  - ".rspec"
79
80
  - ".ruby-version"
80
- - ".travis.yml"
81
81
  - CHANGELOG.md
82
82
  - Gemfile
83
83
  - Gemfile.5.1.pg
84
84
  - Gemfile.5.1.pg.lock
85
85
  - Gemfile.5.2.pg
86
86
  - Gemfile.5.2.pg.lock
87
+ - Gemfile.6.0.pg
88
+ - Gemfile.6.0.pg.lock
89
+ - Gemfile.6.1.pg
90
+ - Gemfile.6.1.pg.lock
87
91
  - Gemfile.lock
88
92
  - LICENSE
89
93
  - LICENSE.txt
@@ -92,10 +96,12 @@ files:
92
96
  - bin/console
93
97
  - bin/setup
94
98
  - lib/rails_state_machine.rb
99
+ - lib/rails_state_machine/callbacks.rb
95
100
  - lib/rails_state_machine/event.rb
96
101
  - lib/rails_state_machine/model.rb
97
102
  - lib/rails_state_machine/state.rb
98
103
  - lib/rails_state_machine/state_machine.rb
104
+ - lib/rails_state_machine/state_manager.rb
99
105
  - lib/rails_state_machine/version.rb
100
106
  - rails_state_machine.gemspec
101
107
  homepage: https://github.com/makandra/rails_state_machine
@@ -117,8 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
123
  - !ruby/object:Gem::Version
118
124
  version: '0'
119
125
  requirements: []
120
- rubyforge_project:
121
- rubygems_version: 2.6.14.1
126
+ rubygems_version: 3.2.3
122
127
  signing_key:
123
128
  specification_version: 4
124
129
  summary: ActiveRecord-bound state machine
data/.travis.yml DELETED
@@ -1,27 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- cache: bundler
4
-
5
- before_script:
6
- - psql -c 'create database rails_state_machine_test;' -U postgres
7
- - mysql -e 'create database IF NOT EXISTS rails_state_machine_test;'
8
-
9
- notifications:
10
- email:
11
- - fail@makandra.de
12
-
13
- install:
14
- # Replace default Travis CI bundler script with a version that doesn't
15
- # explode when lockfile doesn't match recently bumped version
16
- - bundle install --no-deployment --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
17
-
18
- script: bundle exec rake current_rspec
19
-
20
- rvm:
21
- - 2.3.7
22
- - 2.4.4
23
- - 2.5.1
24
-
25
- gemfile:
26
- - Gemfile.5.1.pg
27
- - Gemfile.5.2.pg