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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 14cbdf576bdb9760f0da81d5b53accb8c73a048e
4
- data.tar.gz: fca5149485432751a7ecd18c4f21ab1ccf633f69
3
+ metadata.gz: 41405511bd178326737846d59454cefb6727cf71
4
+ data.tar.gz: d5d40aadb0a86ec6a1120a1ddf398c1c2a1fbfa7
5
5
  SHA512:
6
- metadata.gz: 016b0c5f2b755cc4e89328b118e7b01152b6b83d5330bdb8474166a2c8e20587359bab329a2f7de23d17608f2a86006cf3d77af52947654642ced2afbc895bbc
7
- data.tar.gz: a0df1e3bac12a44e72d3d7d3b1bad100b66936d9013202b3f3a3defce63a10ee083467b09c6e717c4176b8ac00ad604570aa75a788efc678259b41638d2ff792
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 this line to your application's Gemfile:
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
- TODO
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
 
@@ -38,7 +38,6 @@ module StateMachinable
38
38
  events = []
39
39
  end
40
40
 
41
- events.concat([:ev_before_save, :ev_after_save]).uniq
42
41
  clean_name = name.to_s.chomp('!').to_sym
43
42
 
44
43
  if events.include?(clean_name)
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module StateMachinable
2
- VERSION = "2.0.0"
2
+ VERSION = "3.0.0-rc0"
3
3
  end
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: 2.0.0
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: 2017-07-18 00:00:00.000000000 Z
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: '0'
130
+ version: 1.3.1
131
131
  requirements: []
132
132
  rubyforge_project:
133
133
  rubygems_version: 2.6.8