has_state_machine 0.1.0 → 0.1.1

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
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.