rails_state_machine 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +27 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +1 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +173 -0
- data/Rakefile +9 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/gemfiles/Gemfile.5.1.pg +15 -0
- data/gemfiles/Gemfile.5.1.pg.lock +149 -0
- data/gemfiles/Gemfile.5.2.pg +15 -0
- data/gemfiles/Gemfile.5.2.pg.lock +157 -0
- data/lib/rails_state_machine/event.rb +104 -0
- data/lib/rails_state_machine/model.rb +21 -0
- data/lib/rails_state_machine/state.rb +14 -0
- data/lib/rails_state_machine/state_machine.rb +229 -0
- data/lib/rails_state_machine/version.rb +3 -0
- data/lib/rails_state_machine.rb +5 -0
- data/rails_state_machine.gemspec +29 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a43d6bb47ef3e0965611b3bbeff34ab781a7ca117009a94175635f4e0e4c3cb5
|
4
|
+
data.tar.gz: 4f4d100446619829d4dacad6318c97bd80a0ea3be6116036efa0d3afffd21cf2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 510c5ac997b6481843a51f5f4a07433ac00c09ee5cd59c87e99793882fa6c3d9cc24bea5d70082336589c35fe39b6b468bc404dfae74dd5fa51c7ac85638d3d5
|
7
|
+
data.tar.gz: f8fa237d649a5ed98fc5e0a721493e4546f5d8b7f72e2d72ecb1bb291df23ff459ff398d9e6e13fdd340324a617f125d5c00c5d8ca67f1aad6b9cb9d36bce089
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.4
|
data/.travis.yml
ADDED
@@ -0,0 +1,27 @@
|
|
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
|
+
- gemfiles/Gemfile.5.1.pg
|
27
|
+
- gemfiles/Gemfile.5.2.pg
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
./gemfiles/Gemfile.5.1.pg
|
data/Gemfile.lock
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
./gemfiles/Gemfile.5.1.pg.lock
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 makandra
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 makandra
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,173 @@
|
|
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)
|
3
|
+
|
4
|
+
Rails State Machine is a ActiveRecord-bound state machine.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'rails_state_machine'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install rails_state_machine
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Your model needs a `state` attribute. You can then simply define your state machine as follows.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
class YourModel < ApplicationRecord
|
28
|
+
include RailsStateMachine::Model
|
29
|
+
|
30
|
+
state_machine do
|
31
|
+
state :draft, initial: true
|
32
|
+
state :review_pending
|
33
|
+
state :approved
|
34
|
+
state :rejected
|
35
|
+
|
36
|
+
event :request_review do
|
37
|
+
transitions from: [:draft, :rejected], to: :review_pending
|
38
|
+
end
|
39
|
+
|
40
|
+
event :approve do
|
41
|
+
transitions from: :review_pending, to: :approved
|
42
|
+
end
|
43
|
+
|
44
|
+
event :reject do
|
45
|
+
transitions from: :review_pending, to: :rejected
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
This will define instance methods with the names of those events, and constants like `STATE_DRAFT` on the model.
|
52
|
+
If a state is configured as `initial: true`, new instances will be assigned this state.
|
53
|
+
|
54
|
+
A model instance offers these state machine methods:
|
55
|
+
|
56
|
+
- `<state_name>?` to find out if this is the current state.
|
57
|
+
- `<event_name>` call an event and transition into a new state. The record will be `save`d, if valid.
|
58
|
+
- `<event_name>!` call an event and transition into a new state. Calls `save!` to save the record.
|
59
|
+
- `may_<event_name>?` to find out if an event transition could be taken. Note that this will not validate if the model is valid afterwards.
|
60
|
+
- `state_event=` to take a state event, but not save yet. Commonly used for forms where the controller takes a "state_event" param and saves.
|
61
|
+
- `state_event` to get the name of the event that will be called
|
62
|
+
|
63
|
+
Should you ever need to query the state machine for its states or events, it is accessible via `state_machine` class or instance methods on the model. This is mostly helpful in tests.
|
64
|
+
|
65
|
+
If you want an event to be available for a different edge in your graph, you may define multiple `transitions` per event:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
event :request_feedback do
|
69
|
+
transitions from: :draft, to: :draft
|
70
|
+
transitions from: :review_pending, to: :review_pending
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
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
|
+
## Event callbacks
|
108
|
+
|
109
|
+
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.
|
110
|
+
|
111
|
+
* `before_validation`
|
112
|
+
* `before_save`
|
113
|
+
* `after_save`
|
114
|
+
|
115
|
+
Example:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
event :request_review do
|
119
|
+
transitions from: [:draft, :rejected], to: :review_pending
|
120
|
+
|
121
|
+
before_validation do
|
122
|
+
# this callback is chained with existing `before_validation` callbacks of the model
|
123
|
+
end
|
124
|
+
|
125
|
+
before_save do
|
126
|
+
# this callback is chained with existing `before_save` callbacks of the model
|
127
|
+
end
|
128
|
+
|
129
|
+
after_save do
|
130
|
+
# this callback is chained with existing `after_save` callbacks of the model
|
131
|
+
end
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
## Development
|
136
|
+
|
137
|
+
There are tests in `spec`. We only accept PRs with tests. To run tests:
|
138
|
+
|
139
|
+
- Install Ruby 2.4.4
|
140
|
+
- 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`.
|
141
|
+
- Run `bin/setup` to install development dependencies.
|
142
|
+
- Run tests using `bundle exec rspec`
|
143
|
+
|
144
|
+
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:
|
145
|
+
|
146
|
+
- Install development dependencies using `bundle matrix:install`
|
147
|
+
- Run tests using `bundle matrix:spec`
|
148
|
+
|
149
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
150
|
+
|
151
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
152
|
+
|
153
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
154
|
+
|
155
|
+
## Contributing
|
156
|
+
|
157
|
+
If you would like to contribute:
|
158
|
+
|
159
|
+
- Fork the repository.
|
160
|
+
- Push your changes **with passing specs**.
|
161
|
+
- Send us a pull request.
|
162
|
+
|
163
|
+
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.
|
164
|
+
|
165
|
+
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.
|
166
|
+
|
167
|
+
## License
|
168
|
+
|
169
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
170
|
+
|
171
|
+
## Credits
|
172
|
+
|
173
|
+
Arne Hartherz and Emanuel Denzel from [makandra](https://makandra.de/).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'rails_state_machine'
|
5
|
+
require 'pry-byebug'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Runtime dependencies
|
4
|
+
gem 'rails', '~>5.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,149 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
rails_state_machine (1.0.0)
|
5
|
+
activerecord
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
actioncable (5.1.4)
|
11
|
+
actionpack (= 5.1.4)
|
12
|
+
nio4r (~> 2.0)
|
13
|
+
websocket-driver (~> 0.6.1)
|
14
|
+
actionmailer (5.1.4)
|
15
|
+
actionpack (= 5.1.4)
|
16
|
+
actionview (= 5.1.4)
|
17
|
+
activejob (= 5.1.4)
|
18
|
+
mail (~> 2.5, >= 2.5.4)
|
19
|
+
rails-dom-testing (~> 2.0)
|
20
|
+
actionpack (5.1.4)
|
21
|
+
actionview (= 5.1.4)
|
22
|
+
activesupport (= 5.1.4)
|
23
|
+
rack (~> 2.0)
|
24
|
+
rack-test (>= 0.6.3)
|
25
|
+
rails-dom-testing (~> 2.0)
|
26
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
27
|
+
actionview (5.1.4)
|
28
|
+
activesupport (= 5.1.4)
|
29
|
+
builder (~> 3.1)
|
30
|
+
erubi (~> 1.4)
|
31
|
+
rails-dom-testing (~> 2.0)
|
32
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
33
|
+
activejob (5.1.4)
|
34
|
+
activesupport (= 5.1.4)
|
35
|
+
globalid (>= 0.3.6)
|
36
|
+
activemodel (5.1.4)
|
37
|
+
activesupport (= 5.1.4)
|
38
|
+
activerecord (5.1.4)
|
39
|
+
activemodel (= 5.1.4)
|
40
|
+
activesupport (= 5.1.4)
|
41
|
+
arel (~> 8.0)
|
42
|
+
activesupport (5.1.4)
|
43
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
44
|
+
i18n (~> 0.7)
|
45
|
+
minitest (~> 5.1)
|
46
|
+
tzinfo (~> 1.1)
|
47
|
+
arel (8.0.0)
|
48
|
+
builder (3.2.3)
|
49
|
+
byebug (9.1.0)
|
50
|
+
coderay (1.1.2)
|
51
|
+
concurrent-ruby (1.0.5)
|
52
|
+
crass (1.0.3)
|
53
|
+
database_cleaner (1.6.2)
|
54
|
+
diff-lcs (1.3)
|
55
|
+
erubi (1.7.0)
|
56
|
+
gemika (0.3.2)
|
57
|
+
globalid (0.4.1)
|
58
|
+
activesupport (>= 4.2.0)
|
59
|
+
i18n (0.9.1)
|
60
|
+
concurrent-ruby (~> 1.0)
|
61
|
+
loofah (2.1.1)
|
62
|
+
crass (~> 1.0.2)
|
63
|
+
nokogiri (>= 1.5.9)
|
64
|
+
mail (2.7.0)
|
65
|
+
mini_mime (>= 0.1.1)
|
66
|
+
method_source (0.9.0)
|
67
|
+
mini_mime (1.0.0)
|
68
|
+
mini_portile2 (2.3.0)
|
69
|
+
minitest (5.10.3)
|
70
|
+
nio4r (2.1.0)
|
71
|
+
nokogiri (1.8.1)
|
72
|
+
mini_portile2 (~> 2.3.0)
|
73
|
+
pg (0.21.0)
|
74
|
+
pry (0.11.3)
|
75
|
+
coderay (~> 1.1.0)
|
76
|
+
method_source (~> 0.9.0)
|
77
|
+
pry-byebug (3.5.0)
|
78
|
+
byebug (~> 9.1)
|
79
|
+
pry (~> 0.10)
|
80
|
+
rack (2.0.3)
|
81
|
+
rack-test (0.7.0)
|
82
|
+
rack (>= 1.0, < 3)
|
83
|
+
rails (5.1.4)
|
84
|
+
actioncable (= 5.1.4)
|
85
|
+
actionmailer (= 5.1.4)
|
86
|
+
actionpack (= 5.1.4)
|
87
|
+
actionview (= 5.1.4)
|
88
|
+
activejob (= 5.1.4)
|
89
|
+
activemodel (= 5.1.4)
|
90
|
+
activerecord (= 5.1.4)
|
91
|
+
activesupport (= 5.1.4)
|
92
|
+
bundler (>= 1.3.0)
|
93
|
+
railties (= 5.1.4)
|
94
|
+
sprockets-rails (>= 2.0.0)
|
95
|
+
rails-dom-testing (2.0.3)
|
96
|
+
activesupport (>= 4.2.0)
|
97
|
+
nokogiri (>= 1.6)
|
98
|
+
rails-html-sanitizer (1.0.3)
|
99
|
+
loofah (~> 2.0)
|
100
|
+
railties (5.1.4)
|
101
|
+
actionpack (= 5.1.4)
|
102
|
+
activesupport (= 5.1.4)
|
103
|
+
method_source
|
104
|
+
rake (>= 0.8.7)
|
105
|
+
thor (>= 0.18.1, < 2.0)
|
106
|
+
rake (12.2.1)
|
107
|
+
rspec (3.7.0)
|
108
|
+
rspec-core (~> 3.7.0)
|
109
|
+
rspec-expectations (~> 3.7.0)
|
110
|
+
rspec-mocks (~> 3.7.0)
|
111
|
+
rspec-core (3.7.0)
|
112
|
+
rspec-support (~> 3.7.0)
|
113
|
+
rspec-expectations (3.7.0)
|
114
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
115
|
+
rspec-support (~> 3.7.0)
|
116
|
+
rspec-mocks (3.7.0)
|
117
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
118
|
+
rspec-support (~> 3.7.0)
|
119
|
+
rspec-support (3.7.0)
|
120
|
+
sprockets (3.7.1)
|
121
|
+
concurrent-ruby (~> 1.0)
|
122
|
+
rack (> 1, < 3)
|
123
|
+
sprockets-rails (3.2.1)
|
124
|
+
actionpack (>= 4.0)
|
125
|
+
activesupport (>= 4.0)
|
126
|
+
sprockets (>= 3.0.0)
|
127
|
+
thor (0.20.0)
|
128
|
+
thread_safe (0.3.6)
|
129
|
+
tzinfo (1.2.4)
|
130
|
+
thread_safe (~> 0.1)
|
131
|
+
websocket-driver (0.6.5)
|
132
|
+
websocket-extensions (>= 0.1.0)
|
133
|
+
websocket-extensions (0.1.3)
|
134
|
+
|
135
|
+
PLATFORMS
|
136
|
+
ruby
|
137
|
+
|
138
|
+
DEPENDENCIES
|
139
|
+
database_cleaner
|
140
|
+
gemika
|
141
|
+
pg
|
142
|
+
pry-byebug
|
143
|
+
rails (~> 5.1.0)
|
144
|
+
rails_state_machine!
|
145
|
+
rake
|
146
|
+
rspec (~> 3.5)
|
147
|
+
|
148
|
+
BUNDLED WITH
|
149
|
+
1.16.4
|
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Runtime dependencies
|
4
|
+
gem 'rails', '~>5.2.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,157 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
rails_state_machine (0.1.0)
|
5
|
+
activerecord
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
actioncable (5.2.1)
|
11
|
+
actionpack (= 5.2.1)
|
12
|
+
nio4r (~> 2.0)
|
13
|
+
websocket-driver (>= 0.6.1)
|
14
|
+
actionmailer (5.2.1)
|
15
|
+
actionpack (= 5.2.1)
|
16
|
+
actionview (= 5.2.1)
|
17
|
+
activejob (= 5.2.1)
|
18
|
+
mail (~> 2.5, >= 2.5.4)
|
19
|
+
rails-dom-testing (~> 2.0)
|
20
|
+
actionpack (5.2.1)
|
21
|
+
actionview (= 5.2.1)
|
22
|
+
activesupport (= 5.2.1)
|
23
|
+
rack (~> 2.0)
|
24
|
+
rack-test (>= 0.6.3)
|
25
|
+
rails-dom-testing (~> 2.0)
|
26
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
27
|
+
actionview (5.2.1)
|
28
|
+
activesupport (= 5.2.1)
|
29
|
+
builder (~> 3.1)
|
30
|
+
erubi (~> 1.4)
|
31
|
+
rails-dom-testing (~> 2.0)
|
32
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
33
|
+
activejob (5.2.1)
|
34
|
+
activesupport (= 5.2.1)
|
35
|
+
globalid (>= 0.3.6)
|
36
|
+
activemodel (5.2.1)
|
37
|
+
activesupport (= 5.2.1)
|
38
|
+
activerecord (5.2.1)
|
39
|
+
activemodel (= 5.2.1)
|
40
|
+
activesupport (= 5.2.1)
|
41
|
+
arel (>= 9.0)
|
42
|
+
activestorage (5.2.1)
|
43
|
+
actionpack (= 5.2.1)
|
44
|
+
activerecord (= 5.2.1)
|
45
|
+
marcel (~> 0.3.1)
|
46
|
+
activesupport (5.2.1)
|
47
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
48
|
+
i18n (>= 0.7, < 2)
|
49
|
+
minitest (~> 5.1)
|
50
|
+
tzinfo (~> 1.1)
|
51
|
+
arel (9.0.0)
|
52
|
+
builder (3.2.3)
|
53
|
+
byebug (10.0.2)
|
54
|
+
coderay (1.1.2)
|
55
|
+
concurrent-ruby (1.0.5)
|
56
|
+
crass (1.0.4)
|
57
|
+
database_cleaner (1.7.0)
|
58
|
+
diff-lcs (1.3)
|
59
|
+
erubi (1.7.1)
|
60
|
+
gemika (0.3.4)
|
61
|
+
globalid (0.4.1)
|
62
|
+
activesupport (>= 4.2.0)
|
63
|
+
i18n (1.1.0)
|
64
|
+
concurrent-ruby (~> 1.0)
|
65
|
+
loofah (2.2.2)
|
66
|
+
crass (~> 1.0.2)
|
67
|
+
nokogiri (>= 1.5.9)
|
68
|
+
mail (2.7.0)
|
69
|
+
mini_mime (>= 0.1.1)
|
70
|
+
marcel (0.3.2)
|
71
|
+
mimemagic (~> 0.3.2)
|
72
|
+
method_source (0.9.0)
|
73
|
+
mimemagic (0.3.2)
|
74
|
+
mini_mime (1.0.1)
|
75
|
+
mini_portile2 (2.3.0)
|
76
|
+
minitest (5.11.3)
|
77
|
+
nio4r (2.3.1)
|
78
|
+
nokogiri (1.8.4)
|
79
|
+
mini_portile2 (~> 2.3.0)
|
80
|
+
pg (1.1.2)
|
81
|
+
pry (0.11.3)
|
82
|
+
coderay (~> 1.1.0)
|
83
|
+
method_source (~> 0.9.0)
|
84
|
+
pry-byebug (3.6.0)
|
85
|
+
byebug (~> 10.0)
|
86
|
+
pry (~> 0.10)
|
87
|
+
rack (2.0.5)
|
88
|
+
rack-test (1.1.0)
|
89
|
+
rack (>= 1.0, < 3)
|
90
|
+
rails (5.2.1)
|
91
|
+
actioncable (= 5.2.1)
|
92
|
+
actionmailer (= 5.2.1)
|
93
|
+
actionpack (= 5.2.1)
|
94
|
+
actionview (= 5.2.1)
|
95
|
+
activejob (= 5.2.1)
|
96
|
+
activemodel (= 5.2.1)
|
97
|
+
activerecord (= 5.2.1)
|
98
|
+
activestorage (= 5.2.1)
|
99
|
+
activesupport (= 5.2.1)
|
100
|
+
bundler (>= 1.3.0)
|
101
|
+
railties (= 5.2.1)
|
102
|
+
sprockets-rails (>= 2.0.0)
|
103
|
+
rails-dom-testing (2.0.3)
|
104
|
+
activesupport (>= 4.2.0)
|
105
|
+
nokogiri (>= 1.6)
|
106
|
+
rails-html-sanitizer (1.0.4)
|
107
|
+
loofah (~> 2.2, >= 2.2.2)
|
108
|
+
railties (5.2.1)
|
109
|
+
actionpack (= 5.2.1)
|
110
|
+
activesupport (= 5.2.1)
|
111
|
+
method_source
|
112
|
+
rake (>= 0.8.7)
|
113
|
+
thor (>= 0.19.0, < 2.0)
|
114
|
+
rake (12.3.1)
|
115
|
+
rspec (3.8.0)
|
116
|
+
rspec-core (~> 3.8.0)
|
117
|
+
rspec-expectations (~> 3.8.0)
|
118
|
+
rspec-mocks (~> 3.8.0)
|
119
|
+
rspec-core (3.8.0)
|
120
|
+
rspec-support (~> 3.8.0)
|
121
|
+
rspec-expectations (3.8.1)
|
122
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
123
|
+
rspec-support (~> 3.8.0)
|
124
|
+
rspec-mocks (3.8.0)
|
125
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
126
|
+
rspec-support (~> 3.8.0)
|
127
|
+
rspec-support (3.8.0)
|
128
|
+
sprockets (3.7.2)
|
129
|
+
concurrent-ruby (~> 1.0)
|
130
|
+
rack (> 1, < 3)
|
131
|
+
sprockets-rails (3.2.1)
|
132
|
+
actionpack (>= 4.0)
|
133
|
+
activesupport (>= 4.0)
|
134
|
+
sprockets (>= 3.0.0)
|
135
|
+
thor (0.20.0)
|
136
|
+
thread_safe (0.3.6)
|
137
|
+
tzinfo (1.2.5)
|
138
|
+
thread_safe (~> 0.1)
|
139
|
+
websocket-driver (0.7.0)
|
140
|
+
websocket-extensions (>= 0.1.0)
|
141
|
+
websocket-extensions (0.1.3)
|
142
|
+
|
143
|
+
PLATFORMS
|
144
|
+
ruby
|
145
|
+
|
146
|
+
DEPENDENCIES
|
147
|
+
database_cleaner
|
148
|
+
gemika
|
149
|
+
pg
|
150
|
+
pry-byebug
|
151
|
+
rails (~> 5.2.0)
|
152
|
+
rails_state_machine!
|
153
|
+
rake
|
154
|
+
rspec (~> 3.5)
|
155
|
+
|
156
|
+
BUNDLED WITH
|
157
|
+
1.16.4
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module RailsStateMachine
|
2
|
+
class Event
|
3
|
+
Transition = Struct.new(:from, :to)
|
4
|
+
|
5
|
+
UndefinedStateError = Class.new(StandardError)
|
6
|
+
TransitionNotFoundError = Class.new(StandardError)
|
7
|
+
ExistingTransitionError = Class.new(StandardError)
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
def initialize(name, state_machine)
|
12
|
+
@name = name
|
13
|
+
@state_machine = state_machine
|
14
|
+
|
15
|
+
@before_validation = []
|
16
|
+
@before_save = []
|
17
|
+
@after_save = []
|
18
|
+
@after_commit = []
|
19
|
+
|
20
|
+
@transitions_by_state_name = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def configure(&block)
|
24
|
+
instance_eval(&block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def transitions(**options)
|
28
|
+
if options.present?
|
29
|
+
add_transitions(options)
|
30
|
+
else
|
31
|
+
@transitions_by_state_name.values
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def run_before_validation(record)
|
36
|
+
@before_validation.each do |block|
|
37
|
+
record.instance_eval(&block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_before_save(record)
|
42
|
+
@before_save.each do |block|
|
43
|
+
record.instance_eval(&block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_after_save(record)
|
48
|
+
@after_save.each do |block|
|
49
|
+
record.instance_eval(&block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def run_after_commit(record)
|
54
|
+
@after_commit.each do |block|
|
55
|
+
record.instance_eval(&block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_transition_from(state_name)
|
60
|
+
@transitions_by_state_name[state_name&.to_sym] || raise(TransitionNotFoundError, "#{name} does not transition from #{state_name}; defined are #{transitions}")
|
61
|
+
end
|
62
|
+
|
63
|
+
def allowed_from?(state_name)
|
64
|
+
@transitions_by_state_name.key?(state_name&.to_sym)
|
65
|
+
end
|
66
|
+
|
67
|
+
def future_state_name(state_name)
|
68
|
+
find_transition_from(state_name).to
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def add_transitions(from:, to:)
|
74
|
+
froms = Array(from)
|
75
|
+
froms.each { |from| add_transition(from, to) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_transition(from, to)
|
79
|
+
if !@state_machine.has_state?(from)
|
80
|
+
raise UndefinedStateError, "#{from} is not a valid state in the state machine of #{@state_machine.model}"
|
81
|
+
elsif allowed_from?(from)
|
82
|
+
raise ExistingTransitionError, "#{name} already defines a transition from #{from} (to #{future_state_name(from)})"
|
83
|
+
else
|
84
|
+
@transitions_by_state_name[from] = Transition.new(from, to)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def before_validation(&block)
|
89
|
+
@before_validation << block
|
90
|
+
end
|
91
|
+
|
92
|
+
def before_save(&block)
|
93
|
+
@before_save << block
|
94
|
+
end
|
95
|
+
|
96
|
+
def after_save(&block)
|
97
|
+
@after_save << block
|
98
|
+
end
|
99
|
+
|
100
|
+
def after_commit(&block)
|
101
|
+
@after_commit << block
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RailsStateMachine
|
2
|
+
module Model
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def state_machine(&block)
|
9
|
+
StateMachine.new(self).configure(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def states
|
13
|
+
state_machine.state_names
|
14
|
+
end
|
15
|
+
|
16
|
+
def state_events
|
17
|
+
state_machine.event_names
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
module RailsStateMachine
|
2
|
+
class StateMachine
|
3
|
+
def initialize(model)
|
4
|
+
@model = model
|
5
|
+
|
6
|
+
model_constant('StateMachineMethods', Module.new)
|
7
|
+
@model.include(@model::StateMachineMethods)
|
8
|
+
|
9
|
+
@states_by_name = {}
|
10
|
+
@events_by_name = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def configure(&block)
|
14
|
+
instance_eval(&block)
|
15
|
+
|
16
|
+
define_state_methods
|
17
|
+
define_state_constants
|
18
|
+
register_initial_state
|
19
|
+
|
20
|
+
define_event_methods
|
21
|
+
|
22
|
+
register_callbacks
|
23
|
+
register_validations
|
24
|
+
register_state_machine
|
25
|
+
|
26
|
+
define_model_methods
|
27
|
+
end
|
28
|
+
|
29
|
+
def states
|
30
|
+
@states_by_name.values
|
31
|
+
end
|
32
|
+
|
33
|
+
def state_names
|
34
|
+
@states_by_name.keys
|
35
|
+
end
|
36
|
+
|
37
|
+
def events
|
38
|
+
@events_by_name.values
|
39
|
+
end
|
40
|
+
|
41
|
+
def event_names
|
42
|
+
@events_by_name.keys
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_event(name)
|
46
|
+
@events_by_name.fetch(name.to_sym)
|
47
|
+
end
|
48
|
+
|
49
|
+
def has_state?(name)
|
50
|
+
@states_by_name.key?(name.to_sym)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def state(name, **options)
|
56
|
+
@states_by_name[name] = State.new(name, options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def event(name, &block)
|
60
|
+
event = Event.new(name, self)
|
61
|
+
event.configure(&block)
|
62
|
+
|
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
|
+
@events_by_name[name] = event
|
76
|
+
end
|
77
|
+
|
78
|
+
def model_constant(name, value)
|
79
|
+
@model.const_set(name, value)
|
80
|
+
end
|
81
|
+
|
82
|
+
def model_methods(&block)
|
83
|
+
# Using a state machine defines several methods on the model.
|
84
|
+
# The model should be able to re-define them and `super` into the original method, if necessary.
|
85
|
+
# For that, we use a module to store all methods. The module is loaded into the model class.
|
86
|
+
@model::StateMachineMethods.module_eval(&block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def define_state_methods
|
90
|
+
state_names.each do |state_name|
|
91
|
+
model_methods do
|
92
|
+
define_method "#{state_name}?" do
|
93
|
+
self.state.to_s == state_name.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def define_state_constants
|
100
|
+
state_names.each do |state_name|
|
101
|
+
model_constant("STATE_#{state_name.upcase}", state_name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def register_initial_state
|
106
|
+
initial_state = states.detect(&:initial?)
|
107
|
+
return unless initial_state
|
108
|
+
|
109
|
+
@model.after_initialize do
|
110
|
+
self.state ||= initial_state.name if new_record?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def define_event_methods
|
115
|
+
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)
|
119
|
+
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
|
+
|
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
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
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
|
+
@state_event_callbacks[:before_save] << @next_state_machine_event
|
186
|
+
@state_event_callbacks[:after_save] << @next_state_machine_event
|
187
|
+
@state_event_callbacks[:after_commit] << @next_state_machine_event
|
188
|
+
true
|
189
|
+
end
|
190
|
+
|
191
|
+
def flush_state_event_callbacks(name)
|
192
|
+
while (event = @state_event_callbacks[name].shift)
|
193
|
+
event.public_send("run_#{name}", self)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def unset_next_state_machine_event
|
198
|
+
@next_state_machine_event = nil
|
199
|
+
end
|
200
|
+
|
201
|
+
def revert_state
|
202
|
+
self.state = @state_before_state_event
|
203
|
+
end
|
204
|
+
|
205
|
+
def prepare_state_event_change(attributes)
|
206
|
+
if saved_changes?
|
207
|
+
# After calling `save`, ActiveRecord will flag the changes that it just stored as saved.
|
208
|
+
# https://github.com/rails/rails/blob/v5.1.4/activerecord/lib/active_record/attribute_methods/dirty.rb#L33-L46
|
209
|
+
#
|
210
|
+
# When taking multiple state events (e.g. a second event called inside an `after_save` callback) and thus
|
211
|
+
# saving after other changes were just saved, we need to mimic that behavior. Otherwise, ActiveRecord will
|
212
|
+
# print deprecation warnings like these:
|
213
|
+
#
|
214
|
+
# DEPRECATION WARNING: The behavior of `attribute_was` inside of after callbacks will be changing in the
|
215
|
+
# next version of Rails. The new return value will reflect the behavior of calling the method after
|
216
|
+
# `save` returned (e.g. the opposite of what it returns now). To maintain the current behavior, use
|
217
|
+
# `attribute_before_last_save` instead.
|
218
|
+
#
|
219
|
+
# These actually originate from ActiveRecord internals which try to determine the changes that should be
|
220
|
+
# stored for the second save. It is probably a shortcoming of ActiveRecord 5.1.x that will be fixed, but
|
221
|
+
# since the current/previous save was already successful, the right action is to just call `changes_applied`.
|
222
|
+
changes_applied
|
223
|
+
end
|
224
|
+
self.attributes = attributes
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'rails_state_machine/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'rails_state_machine'
|
7
|
+
spec.version = RailsStateMachine::VERSION
|
8
|
+
spec.authors = ['Arne Hartherz', 'Emanuel Denzel']
|
9
|
+
spec.email = ['arne.hartherz@makandra.de']
|
10
|
+
|
11
|
+
spec.summary = %q{ActiveRecord-bound state machine}
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = 'https://github.com/makandra/rails_state_machine'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
|
20
|
+
spec.bindir = 'exe'
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_dependency 'activerecord'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.5'
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rails_state_machine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Arne Hartherz
|
8
|
+
- Emanuel Denzel
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2018-09-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.16'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.16'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '10.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '10.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: pry-byebug
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.5'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.5'
|
70
|
+
description: ActiveRecord-bound state machine
|
71
|
+
email:
|
72
|
+
- arne.hartherz@makandra.de
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".ruby-version"
|
80
|
+
- ".travis.yml"
|
81
|
+
- CHANGELOG.md
|
82
|
+
- Gemfile
|
83
|
+
- Gemfile.lock
|
84
|
+
- LICENSE
|
85
|
+
- LICENSE.txt
|
86
|
+
- README.md
|
87
|
+
- Rakefile
|
88
|
+
- bin/console
|
89
|
+
- bin/setup
|
90
|
+
- gemfiles/Gemfile.5.1.pg
|
91
|
+
- gemfiles/Gemfile.5.1.pg.lock
|
92
|
+
- gemfiles/Gemfile.5.2.pg
|
93
|
+
- gemfiles/Gemfile.5.2.pg.lock
|
94
|
+
- lib/rails_state_machine.rb
|
95
|
+
- lib/rails_state_machine/event.rb
|
96
|
+
- lib/rails_state_machine/model.rb
|
97
|
+
- lib/rails_state_machine/state.rb
|
98
|
+
- lib/rails_state_machine/state_machine.rb
|
99
|
+
- lib/rails_state_machine/version.rb
|
100
|
+
- rails_state_machine.gemspec
|
101
|
+
homepage: https://github.com/makandra/rails_state_machine
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.7.6
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: ActiveRecord-bound state machine
|
125
|
+
test_files: []
|