has_state_machine 0.1.0 → 0.1.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/README.md +73 -3
- data/lib/has_state_machine/definition.rb +1 -2
- data/lib/has_state_machine/state.rb +8 -6
- data/lib/has_state_machine/state_helpers.rb +10 -5
- data/lib/has_state_machine/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a7e45d8de5f1bfdeb758a8d6b04668cceb84ef0fe41add93277237b48e0a75f
|
4
|
+
data.tar.gz: 1dcb7de655710c843ccd1a8521c7760bcbcde34e0c64324744a5e2dc2a2047d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99bc942766e3741de93c38ba9fdd06300bb70ba688853b171525517a41c7830a56b144c49b31e129f5055dc3cb2b3d11901cf72cddaa0515df0095f973fc5332
|
7
|
+
data.tar.gz: 23a277ebd986ea496608e51a68a60d0696ae0366443605bc936bcce7481b0ff25ab9f66eeb004017d8dc34bbf320de837764482eb413c74acc582c649e06bcf6
|
data/README.md
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
[](https://github.com/bharget/has_state_machine/actions)
|
4
4
|
[](https://github.com/testdouble/standard)
|
5
5
|
|
6
|
-
|
7
|
-
How to use my plugin.
|
6
|
+
HasStateMachine uses ruby classes to make creating a finite state machine for your ActiveRecord models a breeze.
|
8
7
|
|
9
8
|
## Installation
|
10
9
|
Add this line to your application's Gemfile:
|
@@ -23,8 +22,79 @@ Or install it yourself as:
|
|
23
22
|
$ gem install has_state_machine
|
24
23
|
```
|
25
24
|
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
You must first use the `has_state_machine` macro to define your state machine at
|
28
|
+
a high level. This includes defining the possible states for your object as well
|
29
|
+
as some optional configuration should you want to change the default behavior of
|
30
|
+
the state machine.
|
31
|
+
```ruby
|
32
|
+
# By default, it is assumed that the "state" of the object is
|
33
|
+
# stored in a string column named "status".
|
34
|
+
class Post < ApplicationRecord
|
35
|
+
has_state_machine states: %i[draft published archived]
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
Now you must define the classes for the states in your state machine. By default,
|
40
|
+
`HasStateMachine` assumes that these will be under the `Workflow` namespace following
|
41
|
+
the pattern of `Workflow::#{ObjectClass}::#{State}`. The state objects must inherit
|
42
|
+
from `HasStateMachine::State`.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
module Workflow
|
46
|
+
class Post::Draft < HasStateMachine::State
|
47
|
+
# Define the possible transitions from the "draft" state
|
48
|
+
transitions_to %i[published archived]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module Workflow
|
53
|
+
class Post::Published < HasStateMachine::State
|
54
|
+
transitions_to %i[archived]
|
55
|
+
|
56
|
+
# Custom validations can be added to the state to ensure a transition is "valid"
|
57
|
+
validate :title_exists?
|
58
|
+
|
59
|
+
def title_exists?
|
60
|
+
return if object.title.present?
|
61
|
+
|
62
|
+
# Errors get added to the ActiveRecord object
|
63
|
+
errors.add(:title, "can't be blank")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module Workflow
|
69
|
+
class Post::Archived < HasStateMachine::State
|
70
|
+
# There are callbacks for running logic before and after
|
71
|
+
# a transition occurs.
|
72
|
+
before_transition do
|
73
|
+
Rails.logger.info "Post is being archived\n"
|
74
|
+
end
|
75
|
+
|
76
|
+
after_transition do
|
77
|
+
Rails.logger.info "Post has been archived\n"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
Some examples:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
post = Post.create(status: "draft")
|
87
|
+
|
88
|
+
post.status.transition_to(:published) # => false
|
89
|
+
post.status # => "draft"
|
90
|
+
|
91
|
+
post.title = "Foobar"
|
92
|
+
post.status.transition_to(:published) # => true
|
93
|
+
post.status # => "published"
|
94
|
+
```
|
95
|
+
|
26
96
|
## Contributing
|
27
|
-
|
97
|
+
Coming Soon
|
28
98
|
|
29
99
|
## License
|
30
100
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -36,7 +36,6 @@ module HasStateMachine
|
|
36
36
|
def define_helper_methods(states:, options:)
|
37
37
|
##
|
38
38
|
# The list of possible states in the state machine.
|
39
|
-
# Can be overwritten to use a different column name.
|
40
39
|
define_singleton_method "workflow_states" do
|
41
40
|
states
|
42
41
|
end
|
@@ -57,7 +56,7 @@ module HasStateMachine
|
|
57
56
|
|
58
57
|
##
|
59
58
|
# Determines whether or not the state validations should be run
|
60
|
-
# as part of the object validations.
|
59
|
+
# as part of the object validations; they are by default.
|
61
60
|
define_singleton_method "state_validations_on_object?" do
|
62
61
|
return true unless options.key?(:state_validations_on_object)
|
63
62
|
|
@@ -8,7 +8,7 @@ module HasStateMachine
|
|
8
8
|
extend ActiveModel::Callbacks
|
9
9
|
include ActiveModel::Validations
|
10
10
|
|
11
|
-
attr_reader :object, :state
|
11
|
+
attr_reader :object, :state
|
12
12
|
|
13
13
|
##
|
14
14
|
# Defines the before_transition and after_transition callbacks
|
@@ -28,8 +28,7 @@ module HasStateMachine
|
|
28
28
|
# Initializes the HasStateMachine::State instance.
|
29
29
|
#
|
30
30
|
# @example
|
31
|
-
# state =
|
32
|
-
# state.class #=> Workflow::Post::Draft
|
31
|
+
# state = Workflow::Post::Draft.new(post) #=> "draft"
|
33
32
|
def initialize(object)
|
34
33
|
@object = object
|
35
34
|
|
@@ -47,11 +46,15 @@ module HasStateMachine
|
|
47
46
|
#
|
48
47
|
# @return [Boolean] whether or not the transition took place
|
49
48
|
def transition_to(desired_state, **options)
|
49
|
+
transitioned = false
|
50
|
+
|
50
51
|
with_transition_options(options) do
|
51
52
|
return false unless valid_transition?(desired_state.to_s)
|
52
53
|
|
53
|
-
state_instance(desired_state.to_s).perform_transition!
|
54
|
+
transitioned = state_instance(desired_state.to_s).perform_transition!
|
54
55
|
end
|
56
|
+
|
57
|
+
transitioned
|
55
58
|
end
|
56
59
|
|
57
60
|
##
|
@@ -78,7 +81,7 @@ module HasStateMachine
|
|
78
81
|
end
|
79
82
|
|
80
83
|
def valid_transition?(desired_state)
|
81
|
-
return true if
|
84
|
+
return true if object.skip_state_validations
|
82
85
|
|
83
86
|
object.valid? &&
|
84
87
|
can_transition?(desired_state) &&
|
@@ -86,7 +89,6 @@ module HasStateMachine
|
|
86
89
|
end
|
87
90
|
|
88
91
|
def with_transition_options(options, &block)
|
89
|
-
@options = options
|
90
92
|
object.skip_state_validations = options[:skip_validations]
|
91
93
|
yield
|
92
94
|
object.skip_state_validations = false
|
@@ -5,6 +5,10 @@ module HasStateMachine
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
+
##
|
9
|
+
# Sometimes you may want to skip the validations defined on
|
10
|
+
# the state when validating your object; set this accessor
|
11
|
+
# to true to do so.
|
8
12
|
attr_accessor :skip_state_validations
|
9
13
|
|
10
14
|
delegate \
|
@@ -20,8 +24,9 @@ module HasStateMachine
|
|
20
24
|
attribute state_attribute, :string, default: initial_state
|
21
25
|
|
22
26
|
##
|
23
|
-
#
|
24
|
-
#
|
27
|
+
# Validate that the current state is a possible state, that there is a
|
28
|
+
# state class defined for it, and run the validations from the state
|
29
|
+
# class instance if need be.
|
25
30
|
validates state_attribute, inclusion: {in: workflow_states}, presence: true
|
26
31
|
validate :state_class_defined?
|
27
32
|
validate :state_instance_validations, if: :should_validate_state?
|
@@ -44,7 +49,7 @@ module HasStateMachine
|
|
44
49
|
|
45
50
|
workflow_states.each do |state|
|
46
51
|
##
|
47
|
-
# Defines scopes based on the state machine possible states
|
52
|
+
# Defines scopes based on the state machine's possible states
|
48
53
|
#
|
49
54
|
# @return [ActiveRecord_Relation]
|
50
55
|
# @example Retreiving a users published posts
|
@@ -102,8 +107,8 @@ module HasStateMachine
|
|
102
107
|
end
|
103
108
|
|
104
109
|
##
|
105
|
-
#
|
106
|
-
#
|
110
|
+
# Run the validations defined on the current HasStateMachine::State. Errors found there
|
111
|
+
# should be added to this object.
|
107
112
|
def state_instance_validations
|
108
113
|
return unless state_class.present?
|
109
114
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_state_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Hargett
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-10-
|
12
|
+
date: 2020-10-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -133,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
133
|
- !ruby/object:Gem::Version
|
134
134
|
version: '0'
|
135
135
|
requirements: []
|
136
|
-
rubygems_version: 3.
|
136
|
+
rubygems_version: 3.1.4
|
137
137
|
signing_key:
|
138
138
|
specification_version: 4
|
139
139
|
summary: Class based state machine for ActiveRecord models.
|