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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 180ea0ce6e3e597405acc08441fe8ee1c0f530ccfd176950e8683196e9232695
4
- data.tar.gz: 97944638a358883f302463d830d506149fe169d9cf3a3c20d7ccd615724a4932
3
+ metadata.gz: 7a7e45d8de5f1bfdeb758a8d6b04668cceb84ef0fe41add93277237b48e0a75f
4
+ data.tar.gz: 1dcb7de655710c843ccd1a8521c7760bcbcde34e0c64324744a5e2dc2a2047d7
5
5
  SHA512:
6
- metadata.gz: c4e20717ca8de688ea7c766da83412b7bf0121d06d2cace551dfd1b5210632fd9840ca34d7293381431b2ff4afc27459a33bfd2711ef537ee3ca39c8598d8098
7
- data.tar.gz: 973704bfb4403dae0b5ff00a3fe3b2d0d6d84f96a5e706bd0dea8cda113bd7dbfc7bac97ce84ae310b4fb6613f287f257a1dfedea41794e06f7afbd4b5af3834
6
+ metadata.gz: 99bc942766e3741de93c38ba9fdd06300bb70ba688853b171525517a41c7830a56b144c49b31e129f5055dc3cb2b3d11901cf72cddaa0515df0095f973fc5332
7
+ data.tar.gz: 23a277ebd986ea496608e51a68a60d0696ae0366443605bc936bcce7481b0ff25ab9f66eeb004017d8dc34bbf320de837764482eb413c74acc582c649e06bcf6
data/README.md CHANGED
@@ -3,8 +3,7 @@
3
3
  [![Build Status](https://github.com/bharget/has_state_machine/workflows/Tests/badge.svg)](https://github.com/bharget/has_state_machine/actions)
4
4
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
5
5
 
6
- ## Usage
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
- Contribution directions go here.
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, :options
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 = HasStateMachine::State.new(post) #=> "draft"
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 options[:skip_validations]
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
- # Validating any changes to the status attribute are represented by
24
- # classes within the state machine and have a valid HasStateMachine::State class.
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
- # Runs the validations defined on the current HasStateMachine::State when calling
106
- # model.valid?
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HasStateMachine
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
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.0
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-22 00:00:00.000000000 Z
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.0.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.