flow_machine 0.2.2 → 0.2.3

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.
@@ -5,44 +5,52 @@ RSpec.describe FlowMachine::Workflow do
5
5
  include FlowMachine::Workflow
6
6
  end
7
7
 
8
- describe '.class_for' do
8
+ describe ".class_for" do
9
9
  subject(:workflow_class) { described_class.class_for(target) }
10
10
 
11
- describe 'with a class' do
11
+ describe "with a class" do
12
12
  let(:target) { TestClass }
13
- it { should eq(TestClassWorkflow) }
13
+
14
+ it { is_expected.to eq(TestClassWorkflow) }
14
15
  end
15
16
 
16
- describe 'with an object' do
17
+ describe "with an object" do
17
18
  let(:target) { TestClass.new }
18
- it { should eq(TestClassWorkflow) }
19
+
20
+ it { is_expected.to eq(TestClassWorkflow) }
19
21
  end
20
22
  end
21
23
 
22
- describe '.for' do
24
+ describe ".for" do
23
25
  subject(:workflow) { described_class.for(target) }
26
+
24
27
  class SomeNewClass; end
25
28
 
26
- describe 'not found' do
29
+ describe "not found" do
27
30
  let(:target) { SomeNewClass.new }
28
- it { should be_nil }
31
+
32
+ it { is_expected.to be_nil }
29
33
  end
30
34
 
31
- describe 'with an object' do
35
+ describe "with an object" do
32
36
  let(:target) { TestClass.new }
33
- it { should be_an_instance_of(TestClassWorkflow) }
34
- its(:object) { should eq(target) }
37
+
38
+ it { is_expected.to be_an_instance_of(TestClassWorkflow) }
39
+ its(:object) { is_expected.to eq(target) }
35
40
  end
36
41
 
37
- describe 'with an array of objects' do
42
+ describe "with an array of objects" do
38
43
  let(:target) { [TestClass.new, TestClass.new] }
39
- it { should match [an_instance_of(TestClassWorkflow), an_instance_of(TestClassWorkflow)] }
44
+
45
+ it { is_expected.to match [an_instance_of(TestClassWorkflow), an_instance_of(TestClassWorkflow)] }
40
46
  end
41
47
  end
42
48
 
43
- describe '.workflow_for_collection' do
49
+ describe ".workflow_for_collection" do
44
50
  subject(:result) { described_class.for_collection(target) }
51
+
45
52
  let(:target) { [TestClass.new, TestClass.new] }
46
- it { should match [an_instance_of(TestClassWorkflow), an_instance_of(TestClassWorkflow)] }
53
+
54
+ it { is_expected.to match [an_instance_of(TestClassWorkflow), an_instance_of(TestClassWorkflow)] }
47
55
  end
48
56
  end
@@ -1,14 +1,18 @@
1
1
  RSpec.describe FlowMachine::Workflow do
2
2
  let(:state_class1) do
3
3
  Class.new(FlowMachine::WorkflowState) do
4
- def self.state_name; :state1; end
4
+ def self.state_name
5
+ :state1
6
+ end
5
7
  event :event1
6
8
  end
7
9
  end
8
10
 
9
11
  let(:state_class2) do
10
12
  Class.new(FlowMachine::WorkflowState) do
11
- def self.state_name; :state2; end
13
+ def self.state_name
14
+ :state2
15
+ end
12
16
  event :event2
13
17
  end
14
18
  end
@@ -23,15 +27,17 @@ RSpec.describe FlowMachine::Workflow do
23
27
  workflow_class2.state state_class2
24
28
  end
25
29
 
26
- context 'class1' do
30
+ context "class1" do
27
31
  subject { workflow_class1.new(double) }
28
- it { should respond_to 'event1' }
29
- it { should_not respond_to 'event2' }
32
+
33
+ it { is_expected.to respond_to "event1" }
34
+ it { is_expected.not_to respond_to "event2" }
30
35
  end
31
36
 
32
- context 'class2' do
37
+ context "class2" do
33
38
  subject { workflow_class2.new(double) }
34
- it { should_not respond_to 'event1' }
35
- it { should respond_to 'event2' }
39
+
40
+ it { is_expected.not_to respond_to "event1" }
41
+ it { is_expected.to respond_to "event2" }
36
42
  end
37
43
  end
@@ -1,4 +1,4 @@
1
- require 'ostruct'
1
+ require "ostruct"
2
2
 
3
3
  RSpec.describe FlowMachine::Workflow::ModelExtension do
4
4
  class Test1State < FlowMachine::WorkflowState
@@ -13,8 +13,8 @@ RSpec.describe FlowMachine::Workflow::ModelExtension do
13
13
  state Test2State
14
14
  end
15
15
 
16
- describe '.create_scopes_on' do
17
- class PersistedModel < Struct.new(:state)
16
+ describe ".create_scopes_on" do
17
+ PersistedModel = Struct.new(:state) do
18
18
  def self.where(opts)
19
19
  [new(opts[:state])]
20
20
  end
@@ -22,33 +22,33 @@ RSpec.describe FlowMachine::Workflow::ModelExtension do
22
22
  TestWorkflow.create_scopes_on(self)
23
23
  end
24
24
 
25
- class UnPersistedModel < Struct.new(:state)
25
+ UnPersistedModel = Struct.new(:state) do
26
26
  TestWorkflow.create_scopes_on(self)
27
27
  end
28
28
 
29
- it 'adds the predicate model for state 1' do
30
- expect(PersistedModel.new('test1')).to be_test1
31
- expect(PersistedModel.new('test2')).not_to be_test1
29
+ it "adds the predicate model for state 1" do
30
+ expect(PersistedModel.new("test1")).to be_test1
31
+ expect(PersistedModel.new("test2")).not_to be_test1
32
32
  end
33
33
 
34
- it 'adds the predicate model for state 2' do
35
- expect(PersistedModel.new('test1')).not_to be_test2
36
- expect(PersistedModel.new('test2')).to be_test2
34
+ it "adds the predicate model for state 2" do
35
+ expect(PersistedModel.new("test1")).not_to be_test2
36
+ expect(PersistedModel.new("test2")).to be_test2
37
37
  end
38
38
 
39
- it 'adds a scope for test1' do
39
+ it "adds a scope for test1" do
40
40
  expect(PersistedModel.test1).to be_an(Array)
41
41
  expect(PersistedModel.test1).to be_one
42
- expect(PersistedModel.test1.first).to eq(PersistedModel.new('test1'))
42
+ expect(PersistedModel.test1.first).to eq(PersistedModel.new("test1"))
43
43
  end
44
44
 
45
- it 'adds a scope for test2' do
45
+ it "adds a scope for test2" do
46
46
  expect(PersistedModel.test2).to be_an(Array)
47
47
  expect(PersistedModel.test2).to be_one
48
- expect(PersistedModel.test2.first).to eq(PersistedModel.new('test2'))
48
+ expect(PersistedModel.test2.first).to eq(PersistedModel.new("test2"))
49
49
  end
50
50
 
51
- it 'does not add scopes if where is not defined' do
51
+ it "does not add scopes if where is not defined" do
52
52
  expect(UnPersistedModel).not_to respond_to(:test1)
53
53
  end
54
54
  end
@@ -1,127 +1,131 @@
1
1
  RSpec.describe FlowMachine::Callback do
2
2
  let(:object) { double }
3
3
 
4
- describe 'callback with method' do
4
+ describe "callback with method" do
5
5
  let(:callback) { described_class.new(:some_method) }
6
6
 
7
- it 'calls the method' do
7
+ it "calls the method" do
8
8
  expect(object).to receive(:some_method)
9
9
  callback.call(object)
10
10
  end
11
11
  end
12
12
 
13
- describe 'callback with block' do
13
+ describe "callback with block" do
14
14
  let(:callback) do
15
15
  described_class.new { some_method }
16
16
  end
17
17
 
18
- it 'calls the method' do
18
+ it "calls the method" do
19
19
  expect(object).to receive(:some_method)
20
20
  callback.call(object)
21
21
  end
22
-
23
22
  end
24
23
 
25
- describe 'callback with if' do
26
- context 'a single if' do
24
+ describe "callback with if" do
25
+ context "a single if" do
27
26
  let(:callback) { described_class.new(:some_method, if: :if_method?) }
28
27
 
29
- context 'if method returns true' do
28
+ context "if method returns true" do
30
29
  before { allow(object).to receive(:if_method?).and_return true }
31
- it 'calls the method' do
30
+
31
+ it "calls the method" do
32
32
  expect(object).to receive(:some_method)
33
33
  callback.call(object)
34
34
  end
35
35
  end
36
36
 
37
- context 'if method returns false' do
37
+ context "if method returns false" do
38
38
  before { allow(object).to receive(:if_method?).and_return false }
39
- it 'does not call the method' do
39
+
40
+ it "does not call the method" do
40
41
  expect(object).not_to receive(:some_method)
41
42
  callback.call(object)
42
43
  end
43
44
  end
44
45
  end
45
46
 
46
- context 'a lambda for if' do
47
+ context "a lambda for if" do
47
48
  let(:callback) do
48
49
  described_class.new(:some_method, if: -> { if_method? })
49
50
  end
50
51
 
51
- it 'calls the method when true' do
52
+ it "calls the method when true" do
52
53
  allow(object).to receive(:if_method?).and_return true
53
54
  expect(object).to receive(:some_method)
54
55
  callback.call(object)
55
56
  end
56
57
 
57
- it 'does not call the method when false' do
58
+ it "does not call the method when false" do
58
59
  allow(object).to receive(:if_method?).and_return false
59
60
  expect(object).not_to receive(:some_method)
60
61
  callback.call(object)
61
62
  end
62
63
  end
63
64
 
64
- context 'an array of ifs' do
65
- let(:callback) { described_class.new(:some_method, if: [:if_method?, :if2?]) }
66
- context 'both return true' do
67
- before :each do
65
+ context "an array of ifs" do
66
+ let(:callback) { described_class.new(:some_method, if: %i[if_method? if2?]) }
67
+
68
+ context "both return true" do
69
+ before do
68
70
  allow(object).to receive(:if_method?).and_return true
69
71
  allow(object).to receive(:if2?).and_return true
70
72
  end
71
- it 'calls the method' do
73
+
74
+ it "calls the method" do
72
75
  expect(object).to receive(:some_method)
73
76
  callback.call(object)
74
77
  end
75
78
  end
76
79
 
77
- context 'one returns false' do
78
- before :each do
80
+ context "one returns false" do
81
+ before do
79
82
  allow(object).to receive(:if_method?).and_return true
80
83
  allow(object).to receive(:if2?).and_return false
81
84
  end
82
85
 
83
- it 'does not call the method' do
84
- expect(object).to receive(:some_method).never
86
+ it "does not call the method" do
87
+ expect(object).not_to receive(:some_method)
85
88
  callback.call(object)
86
89
  end
87
90
  end
88
91
  end
89
92
  end
90
93
 
91
- describe 'callback with unless' do
92
- context 'a single if' do
94
+ describe "callback with unless" do
95
+ context "a single if" do
93
96
  let(:callback) { described_class.new(:some_method, unless: :unless_method?) }
94
97
 
95
- context 'unless method returns false' do
98
+ context "unless method returns false" do
96
99
  before { allow(object).to receive(:unless_method?).and_return false }
97
100
 
98
- it 'calls the method' do
101
+ it "calls the method" do
99
102
  expect(object).to receive(:some_method)
100
103
  callback.call(object)
101
104
  end
102
105
  end
103
106
 
104
- context 'unless method returns true' do
105
- before { allow(object).to receive(:unless_method?).and_return true }
106
- it 'does not call the method' do
107
- expect(object).to receive(:some_method).never
107
+ context "unless method returns true" do
108
+ before { allow(object).to receive(:unless_method?).and_return true }
109
+
110
+ it "does not call the method" do
111
+ expect(object).not_to receive(:some_method)
108
112
  callback.call(object)
109
113
  end
110
114
  end
111
115
  end
112
116
 
113
- context 'a lambda for unless' do
117
+ context "a lambda for unless" do
114
118
  let(:callback) do
115
119
  described_class.new(:some_method, unless: -> { unless_method? })
116
120
  end
117
121
 
118
- it 'calls the method when false' do
122
+ it "calls the method when false" do
119
123
  allow(object).to receive(:unless_method?).and_return false
120
124
  expect(object).to receive(:some_method)
121
125
  callback.call(object)
122
126
  end
123
127
 
124
- it 'does not call the method when true' do
128
+ it "does not call the method when true" do
125
129
  allow(object).to receive(:unless_method?).and_return true
126
130
  expect(object).not_to receive(:some_method)
127
131
  callback.call(object)
@@ -1,25 +1,28 @@
1
1
  RSpec.describe FlowMachine::ChangeCallback do
2
2
  subject(:callback) { described_class.new(:field, :method, if: :condition?) }
3
3
 
4
+ before { allow(object).to receive(:run_workflow_method) { |m| object.send(m) } }
5
+
6
+ let(:object) { double(condition?: true) }
7
+
4
8
  specify { expect(callback.field).to eq(:field) }
5
9
  specify { expect(callback.method).to eq(:method) }
6
- specify { expect(callback.options).to eq({ if: :condition? }) }
10
+ specify { expect(callback.options).to eq(if: :condition?) }
7
11
 
8
- let(:object) { double(condition?: true) }
9
- before { allow(object).to receive(:run_workflow_method) { |m| object.send(m) } }
12
+ context "the field changes" do
13
+ let(:changes) { { "field" => %i[old new] } }
10
14
 
11
- context 'the field changes' do
12
- let(:changes) { { 'field' => [:old, :new] } }
13
- it 'calls the method' do
15
+ it "calls the method" do
14
16
  expect(object).to receive(:method)
15
17
  callback.call(object, changes)
16
18
  end
17
19
  end
18
20
 
19
- context 'the field does not change' do
20
- let(:changes) { { 'other_field' => [:old, :new] } }
21
- it 'does not call the method' do
22
- expect(object).to receive(:method).never
21
+ context "the field does not change" do
22
+ let(:changes) { { "other_field" => %i[old new] } }
23
+
24
+ it "does not call the method" do
25
+ expect(object).not_to receive(:method)
23
26
  callback.call(object, changes)
24
27
  end
25
28
  end
@@ -1,4 +1,4 @@
1
- require 'ostruct'
1
+ require "ostruct"
2
2
 
3
3
  RSpec.describe FlowMachine::Workflow do
4
4
  class Test1State < FlowMachine::WorkflowState
@@ -17,179 +17,189 @@ RSpec.describe FlowMachine::Workflow do
17
17
  after_save :after_save_callback
18
18
  after_transition :after_transition_callback
19
19
  def workflow_method; end
20
+
20
21
  def before_save_callback; end
22
+
21
23
  def after_save_callback; end
24
+
22
25
  def after_transition_callback; end
23
26
  end
24
27
 
25
- describe 'state_names' do
26
- it 'has the state names' do
27
- expect(TestWorkflow.state_names).to eq(['test1', 'test2'])
28
+ describe "state_names" do
29
+ it "has the state names" do
30
+ expect(TestWorkflow.state_names).to eq(%w[test1 test2])
28
31
  end
29
32
 
30
- it 'has the states in a hash keyed by names' do
31
- expect(TestWorkflow.states).to eq({ test1: Test1State, test2: Test2State })
33
+ it "has the states in a hash keyed by names" do
34
+ expect(TestWorkflow.states).to eq(test1: Test1State, test2: Test2State)
32
35
  end
33
36
  end
34
37
 
35
- describe 'reading initial state' do
38
+ describe "reading initial state" do
36
39
  subject(:workflow) { TestWorkflow.new(object) }
37
- context 'default state field' do
40
+
41
+ context "default state field" do
38
42
  let(:object) { double(state: :test1) }
39
- it 'has the state' do
43
+
44
+ it "has the state" do
40
45
  expect(workflow.current_state_name).to eq(:test1)
41
46
  end
42
47
  end
43
48
 
44
- context 'with a different state field on the object' do
49
+ context "with a different state field on the object" do
45
50
  before { TestWorkflow.send(:state_attribute, :status) }
46
51
  # return to default
52
+
47
53
  after { TestWorkflow.send(:state_attribute, :state) }
48
54
 
49
55
  let(:object) { double(status: :test2) }
50
- it 'has the state' do
56
+
57
+ it "has the state" do
51
58
  expect(workflow.current_state_name).to eq(:test2)
52
59
  end
53
60
  end
54
61
  end
55
62
 
56
- describe '#transition' do
63
+ describe "#transition" do
57
64
  subject(:workflow) { TestWorkflow.new(object) }
65
+
58
66
  let(:object) { double(state: :test1) }
59
67
 
60
- it 'errors on an invalid state' do
68
+ it "errors on an invalid state" do
61
69
  expect { workflow.transition to: :invalid }.to raise_error(ArgumentError)
62
70
  end
63
71
 
64
- it 'changes the state of the object' do
65
- expect(object).to receive(:state=).with('test2')
72
+ it "changes the state of the object" do
73
+ expect(object).to receive(:state=).with("test2")
66
74
  workflow.transition to: :test2
67
75
  end
68
76
 
69
- it 'leaves the state if transitions to itself' do
77
+ it "leaves the state if transitions to itself" do
70
78
  workflow.transition
71
79
  expect(workflow.current_state_name).to eq(:test1)
72
80
  expect(object.state).to eq(:test1)
73
81
  end
74
82
  end
75
83
 
76
- describe 'transition :after hooks' do
84
+ describe "transition :after hooks" do
77
85
  subject(:workflow) { TestWorkflow.new(object) }
86
+
78
87
  let(:object) { OpenStruct.new(state: :test1, changes: {}, save: true, object_method: true) }
79
88
 
80
- it 'does not call the :after hook before saving' do
89
+ it "does not call the :after hook before saving" do
81
90
  expect(workflow).not_to receive(:workflow_method)
82
91
  workflow.transition to: :test2, after: :workflow_method
83
92
  end
84
93
 
85
- it 'does not calls the :after hook on failure' do
94
+ it "does not calls the :after hook on failure" do
86
95
  expect(workflow).not_to receive(:workflow_method)
87
96
  workflow.transition to: :test1
88
97
  workflow.save
89
98
  end
90
99
 
91
- it 'calls the :after hook on a state method' do
100
+ it "calls the :after hook on a state method" do
92
101
  expect_any_instance_of(Test1State).to receive(:state_method)
93
102
  expect_any_instance_of(Test2State).not_to receive(:state_method)
94
103
  workflow.transition to: :test2, after: :state_method
95
104
  workflow.save
96
105
  end
97
106
 
98
- it 'calls the :after hook on a workflow method' do
107
+ it "calls the :after hook on a workflow method" do
99
108
  expect(workflow).to receive(:workflow_method)
100
109
  workflow.transition to: :test2, after: :workflow_method
101
110
  workflow.save
102
111
  end
103
112
 
104
- it 'calls the :after hook on an object method' do
113
+ it "calls the :after hook on an object method" do
105
114
  expect(object).to receive(:object_method)
106
115
  workflow.transition to: :test2, after: :object_method
107
116
  workflow.save
108
117
  end
109
118
 
110
- it 'allows a lambda' do
119
+ it "allows a lambda" do
111
120
  expect_any_instance_of(Test1State).to receive(:state_method)
112
- workflow.transition to: :test2, after: ->{ state_method }
121
+ workflow.transition to: :test2, after: -> { state_method }
113
122
  workflow.save
114
123
  end
115
124
 
116
- describe 'after_transition hook' do
117
- it 'calls the hook on transition' do
125
+ describe "after_transition hook" do
126
+ it "calls the hook on transition" do
118
127
  expect(workflow).to receive(:after_transition_callback)
119
128
  workflow.transition to: :test2
120
129
  end
121
130
 
122
- it 'does not call for invalid states' do
131
+ it "does not call for invalid states" do
123
132
  expect(workflow).not_to receive(:after_transition_callback)
124
133
  expect { workflow.transition to: :invalid_state }.to raise_error(ArgumentError)
125
134
  end
126
135
 
127
- it 'does not call for ending in the same state' do
136
+ it "does not call for ending in the same state" do
128
137
  expect(workflow).not_to receive(:after_transition_callback)
129
138
  workflow.transition to: :test1
130
139
  end
131
140
  end
132
141
  end
133
142
 
134
- describe '#persist' do
143
+ describe "#persist" do
135
144
  subject(:workflow) { TestWorkflow.new(object) }
145
+
136
146
  let(:object) { OpenStruct.new(state: :test1, changes: {}, save: true) }
137
147
 
138
- context 'success' do
139
- it 'saves the object' do
148
+ context "success" do
149
+ it "saves the object" do
140
150
  expect(workflow.persist).to be true
141
151
  end
142
152
 
143
- it 'runs before and after_change hooks' do
153
+ it "runs before and after_change hooks" do
144
154
  expect(workflow.current_state).to receive(:fire_callbacks).with(:before_change, {})
145
155
  expect(workflow.current_state).to receive(:fire_callbacks).with(:after_change, {})
146
156
  expect(workflow.persist).to be true
147
157
  end
148
158
 
149
159
  it "runs after_enter hooks if it's in a new state" do
150
- allow(object).to receive(:changes).and_return({'state' => ['test1', 'test2']})
151
- expect(workflow.current_state).to receive(:fire_callbacks).with(:before_change, { 'state' => ['test1', 'test2'] })
152
- expect(workflow.current_state).to receive(:fire_callbacks).with(:after_change, { 'state' => ['test1', 'test2'] })
153
- expect(workflow.current_state).to receive(:fire_callbacks).with(:after_enter, { 'state' => ['test1', 'test2'] })
160
+ allow(object).to receive(:changes).and_return("state" => %w[test1 test2])
161
+ expect(workflow.current_state).to receive(:fire_callbacks).with(:before_change, "state" => %w[test1 test2])
162
+ expect(workflow.current_state).to receive(:fire_callbacks).with(:after_change, "state" => %w[test1 test2])
163
+ expect(workflow.current_state).to receive(:fire_callbacks).with(:after_enter, "state" => %w[test1 test2])
154
164
  expect(workflow.persist).to be true
155
165
  end
156
166
 
157
- it 'runs the before_save callback' do
167
+ it "runs the before_save callback" do
158
168
  expect(workflow).to receive(:before_save_callback)
159
169
  workflow.persist
160
170
  end
161
171
 
162
- it 'runs the after_save callback' do
172
+ it "runs the after_save callback" do
163
173
  expect(workflow).to receive(:after_save_callback)
164
174
  workflow.persist
165
175
  end
166
176
  end
167
177
 
168
- context 'failure' do
178
+ context "failure" do
169
179
  before do
170
180
  expect(object).to receive(:save).and_return false
171
181
  end
172
182
 
173
- it 'does not save the object' do
183
+ it "does not save the object" do
174
184
  expect(workflow.persist).to be false
175
185
  end
176
186
 
177
- it 'runs the before_change callback' do
187
+ it "runs the before_change callback" do
178
188
  expect(workflow.current_state).to receive(:fire_callbacks).with(:before_change, {})
179
189
  expect(workflow.persist).to be false
180
190
  end
181
191
 
182
- it 'runs the before_save callback' do
192
+ it "runs the before_save callback" do
183
193
  expect(workflow).to receive(:before_save_callback)
184
194
  workflow.persist
185
195
  end
186
196
 
187
- it 'does not run the after_save callback' do
188
- expect(workflow).to_not receive(:after_save_callback)
197
+ it "does not run the after_save callback" do
198
+ expect(workflow).not_to receive(:after_save_callback)
189
199
  workflow.persist
190
200
  end
191
201
 
192
- it 'reverts to the old state' do
202
+ it "reverts to the old state" do
193
203
  expect(workflow).to be_test1
194
204
  workflow.transition to: :test2
195
205
  expect(workflow).to be_test2