state_machinable 2.0.0 → 3.0.0.pre.rc0
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 +121 -2
- data/lib/state_machinable/base.rb +0 -1
- data/lib/state_machinable/model.rb +0 -10
- data/lib/state_machinable/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41405511bd178326737846d59454cefb6727cf71
|
4
|
+
data.tar.gz: d5d40aadb0a86ec6a1120a1ddf398c1c2a1fbfa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a88628febd7d3ed64216b5fc864ebca770ca1576e728d09c95d038865ba8174c294a533f214c5b41afcae86059ddf5edc1ef611d295c9e0c41981773d047df87
|
7
|
+
data.tar.gz: 5fdba8bc745a51f3c12db9b05142c323a97dd2fb433d066d18a4180751d36c76a216bad4c0c5c666bc9e82bd4b22f32024685831407ca7f5d11fb6437bce4df3
|
data/README.md
CHANGED
@@ -4,10 +4,11 @@ Adds state machine functionality to `statesman`
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
Add
|
7
|
+
Add these lines to your application's Gemfile:
|
8
8
|
|
9
9
|
```ruby
|
10
10
|
gem 'state_machinable'
|
11
|
+
gem 'statesman'
|
11
12
|
```
|
12
13
|
|
13
14
|
And then execute:
|
@@ -16,11 +17,129 @@ And then execute:
|
|
16
17
|
|
17
18
|
Or install it yourself as:
|
18
19
|
|
20
|
+
$ gem install statesman
|
19
21
|
$ gem install state_machinable
|
20
22
|
|
23
|
+
## Setup
|
24
|
+
|
25
|
+
Generate the transitions for a model, e.g. `Order`
|
26
|
+
|
27
|
+
$ rails g migration CreateOrderTransitions
|
28
|
+
|
29
|
+
The migration will look very similar to if you had generated it with Statesman, but with a `current_state` added
|
30
|
+
|
31
|
+
`rails g statesman:active_record_transition Order OrderTransition`
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class CreateOrderTransitions < ActiveRecord::Migration
|
35
|
+
def change
|
36
|
+
add_column :orders, :current_state, :string # <- ADD THIS LINE
|
37
|
+
create_table :order_transitions do |t|
|
38
|
+
t.string :to_state, null: false
|
39
|
+
t.text :metadata
|
40
|
+
t.integer :sort_key, null: false
|
41
|
+
t.integer :order_id, null: false
|
42
|
+
t.boolean :most_recent
|
43
|
+
t.timestamps null: false
|
44
|
+
end
|
45
|
+
|
46
|
+
add_index(:order_transitions, [:order_id, :sort_key], unique: true, name: "index_order_transitions_parent_sort")
|
47
|
+
add_index(:order_transitions, [:order_id, :most_recent], unique: true, name: "index_order_transitions_parent_most_recent")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
In your model, include this library and transitions:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
class Order < ActiveRecord::Base
|
56
|
+
include StateMachinable::Model
|
57
|
+
has_many :order_transitions, :dependent => :destroy
|
58
|
+
```
|
59
|
+
|
60
|
+
Then set up your state transitions:
|
61
|
+
```ruby
|
62
|
+
# app/state_machines/order_state_machine.rb
|
63
|
+
|
64
|
+
class OrderStateMachine
|
65
|
+
include StateMachinable::Base
|
66
|
+
|
67
|
+
# define your states
|
68
|
+
state :open
|
69
|
+
state :processing
|
70
|
+
state :shipped
|
71
|
+
state :delivered
|
72
|
+
state :cancelled
|
73
|
+
|
74
|
+
# define transitions
|
75
|
+
transition :from => :initial, :to => :open
|
76
|
+
transition :from => :open, :to => [:processing, :cancelled]
|
77
|
+
transition :from => :processing, :to => [:shipped, :cancelled]
|
78
|
+
transition :from => :shipped, :to => [:delivered]
|
79
|
+
|
80
|
+
# define events that may occur
|
81
|
+
EVENTS = [
|
82
|
+
:event_processing,
|
83
|
+
:event_shipped,
|
84
|
+
:event_cancelled,
|
85
|
+
:event_delivered
|
86
|
+
].freeze
|
87
|
+
|
88
|
+
# define a class for each state, with methods for event that may occur within that state
|
89
|
+
class Open
|
90
|
+
def self.event_processing(order)
|
91
|
+
order.transition_to!(:processing)
|
92
|
+
# TODO: send order confirmation email to customer
|
93
|
+
end
|
94
|
+
def self.event_cancelled(order)
|
95
|
+
order.transition_to!(:cancelled)
|
96
|
+
# ...
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Shipped
|
101
|
+
def self.event_delivered(order)
|
102
|
+
order.transition_to!(:delivered)
|
103
|
+
# ...
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
```
|
109
|
+
|
110
|
+
There are also hooks for the state changes that could be used instead of duplicating logic in multiple events that transition to the same state
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
class Cancelled
|
114
|
+
def self.enter(order)
|
115
|
+
# TODO: send email to customer that order is cancelled
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
```
|
120
|
+
|
21
121
|
## Usage
|
122
|
+
When you want to transition from one state to another, call an event:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
order.state_machine.event_shipped
|
126
|
+
```
|
22
127
|
|
23
|
-
|
128
|
+
You may want to use a transaction around the event to ensure that both the current_state and transitions are committed, or to prevent invalid states
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
ActiveRecord::Base.transaction do
|
132
|
+
# without a transaction here then an invoice could be created without the order's state succeeding in transitioning to shipped
|
133
|
+
Order.create_invoice_for_order!(order)
|
134
|
+
order.state_machine.event_shipped
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
You can check the model's state with `#current_state`
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
order.current_state
|
142
|
+
```
|
24
143
|
|
25
144
|
## Development
|
26
145
|
|
@@ -13,8 +13,6 @@ module StateMachinable
|
|
13
13
|
end
|
14
14
|
|
15
15
|
included do
|
16
|
-
before_save :send_ev_before_save, :if => Proc.new { |obj| obj.changed? }
|
17
|
-
after_save :send_ev_after_save, :if => Proc.new { |obj| !obj.id_changed? && obj.changed? }
|
18
16
|
after_save :transition_to_initial_state, :if => Proc.new { |obj| obj.id_changed? }
|
19
17
|
delegate :can_transition_to?, :transition_to!, :transition_to, :to => :state_machine
|
20
18
|
|
@@ -22,14 +20,6 @@ module StateMachinable
|
|
22
20
|
@state_machine ||= self.class.state_machine_class.new(self, :transition_class => self.class.transition_class)
|
23
21
|
end
|
24
22
|
|
25
|
-
def send_ev_before_save
|
26
|
-
self.state_machine.send('ev_before_save')
|
27
|
-
end
|
28
|
-
|
29
|
-
def send_ev_after_save
|
30
|
-
self.state_machine.send('ev_after_save')
|
31
|
-
end
|
32
|
-
|
33
23
|
private def transition_to_initial_state
|
34
24
|
initial_state = self.state_machine.class.successors['initial'].first
|
35
25
|
if (!self.respond_to?(:skip_state_machine?) || !self.skip_state_machine?) && (self.current_state != initial_state)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_machinable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.pre.rc0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Santiago Herrera
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -125,9 +125,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
125
|
version: '0'
|
126
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
|
-
- - "
|
128
|
+
- - ">"
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version:
|
130
|
+
version: 1.3.1
|
131
131
|
requirements: []
|
132
132
|
rubyforge_project:
|
133
133
|
rubygems_version: 2.6.8
|