interaktor 0.5.1 → 0.6.0.pre
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 +79 -69
- data/interaktor.gemspec +2 -2
- data/lib/interaktor/attributes.rb +24 -0
- data/lib/interaktor/callable.rb +42 -262
- data/lib/interaktor/error/attribute_error.rb +2 -2
- data/lib/interaktor/error/attribute_validation_error.rb +20 -0
- data/lib/interaktor/error/missing_explicit_success_error.rb +7 -2
- data/lib/interaktor/error/organizer_missing_passed_attribute_error.rb +7 -7
- data/lib/interaktor/error/organizer_success_attribute_missing_error.rb +4 -4
- data/lib/interaktor/error/unknown_attribute_error.rb +4 -4
- data/lib/interaktor/interaction.rb +83 -29
- data/lib/interaktor/organizer.rb +7 -35
- data/lib/interaktor.rb +2 -18
- data/spec/interaktor/hooks_spec.rb +357 -363
- data/spec/interaktor/organizer_spec.rb +57 -48
- data/spec/support/helpers.rb +13 -2
- data/spec/support/lint.rb +219 -271
- metadata +11 -11
- data/lib/interaktor/error/attribute_schema_validation_error.rb +0 -54
- data/spec/interaktor/context_spec.rb +0 -187
metadata
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: interaktor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0.pre
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Taylor Thurlow
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: activemodel
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 7.0.9
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 7.0.9
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: zeitwerk
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -75,9 +75,10 @@ files:
|
|
|
75
75
|
- bin/standardrb
|
|
76
76
|
- interaktor.gemspec
|
|
77
77
|
- lib/interaktor.rb
|
|
78
|
+
- lib/interaktor/attributes.rb
|
|
78
79
|
- lib/interaktor/callable.rb
|
|
79
80
|
- lib/interaktor/error/attribute_error.rb
|
|
80
|
-
- lib/interaktor/error/
|
|
81
|
+
- lib/interaktor/error/attribute_validation_error.rb
|
|
81
82
|
- lib/interaktor/error/base.rb
|
|
82
83
|
- lib/interaktor/error/invalid_method_for_state_error.rb
|
|
83
84
|
- lib/interaktor/error/missing_explicit_success_error.rb
|
|
@@ -89,7 +90,6 @@ files:
|
|
|
89
90
|
- lib/interaktor/interaction.rb
|
|
90
91
|
- lib/interaktor/organizer.rb
|
|
91
92
|
- spec/integration_spec.rb
|
|
92
|
-
- spec/interaktor/context_spec.rb
|
|
93
93
|
- spec/interaktor/hooks_spec.rb
|
|
94
94
|
- spec/interaktor/organizer_spec.rb
|
|
95
95
|
- spec/interaktor_spec.rb
|
|
@@ -111,9 +111,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
111
111
|
version: '3.0'
|
|
112
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
113
|
requirements:
|
|
114
|
-
- - "
|
|
114
|
+
- - ">"
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
|
-
version:
|
|
116
|
+
version: 1.3.1
|
|
117
117
|
requirements: []
|
|
118
118
|
rubygems_version: 3.4.19
|
|
119
119
|
signing_key:
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
class Interaktor::Error::AttributeSchemaValidationError < Interaktor::Error::Base
|
|
2
|
-
# @return [Hash{Symbol=>Array<String>}]
|
|
3
|
-
attr_reader :validation_errors
|
|
4
|
-
|
|
5
|
-
# @param interaktor [Class]
|
|
6
|
-
# @param validation_errors [Hash{Symbol=>Array<String>}]
|
|
7
|
-
def initialize(interaktor, validation_errors)
|
|
8
|
-
super(interaktor)
|
|
9
|
-
|
|
10
|
-
@validation_errors = validation_errors
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# @return [String]
|
|
14
|
-
# @abstract
|
|
15
|
-
def message
|
|
16
|
-
"Interaktor attribute schema failed validation:\n #{error_list}"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
# @return [String]
|
|
22
|
-
def error_list
|
|
23
|
-
result = ""
|
|
24
|
-
|
|
25
|
-
validation_errors.each do |attribute, errors|
|
|
26
|
-
result << error_entry(attribute, errors)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
result
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def error_entry(key, value, depth = 0)
|
|
33
|
-
result = " " * depth * 2
|
|
34
|
-
|
|
35
|
-
case value
|
|
36
|
-
when Hash
|
|
37
|
-
result << "#{key}:\n"
|
|
38
|
-
value.each do |sub_key, sub_value|
|
|
39
|
-
result << " "
|
|
40
|
-
result << error_entry(sub_key, sub_value, depth + 1)
|
|
41
|
-
end
|
|
42
|
-
when Array
|
|
43
|
-
result << "#{key}:\n"
|
|
44
|
-
value.each do |error_message|
|
|
45
|
-
result << " "
|
|
46
|
-
result << error_entry(nil, error_message, depth + 1)
|
|
47
|
-
end
|
|
48
|
-
else
|
|
49
|
-
result << "- #{value}\n"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
result
|
|
53
|
-
end
|
|
54
|
-
end
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
module Interaktor
|
|
2
|
-
# RSpec.describe Context do
|
|
3
|
-
# describe ".build" do
|
|
4
|
-
# it "converts the given hash to a context" do
|
|
5
|
-
# context = described_class.build(foo: "bar")
|
|
6
|
-
|
|
7
|
-
# expect(context).to be_a(described_class)
|
|
8
|
-
# expect(context.foo).to eq("bar")
|
|
9
|
-
# end
|
|
10
|
-
|
|
11
|
-
# it "builds an empty context if no hash is given" do
|
|
12
|
-
# context = described_class.build
|
|
13
|
-
|
|
14
|
-
# expect(context).to be_a(described_class)
|
|
15
|
-
# expect(context.send(:table)).to eq({})
|
|
16
|
-
# end
|
|
17
|
-
|
|
18
|
-
# it "doesn't affect the original hash" do
|
|
19
|
-
# hash = {foo: "bar"}
|
|
20
|
-
# context = described_class.build(hash)
|
|
21
|
-
|
|
22
|
-
# expect(context).to be_a(described_class)
|
|
23
|
-
# expect {
|
|
24
|
-
# context.foo = "baz"
|
|
25
|
-
# }.not_to(change {
|
|
26
|
-
# hash[:foo]
|
|
27
|
-
# })
|
|
28
|
-
# end
|
|
29
|
-
|
|
30
|
-
# it "preserves an already built context" do
|
|
31
|
-
# context1 = described_class.build(foo: "bar")
|
|
32
|
-
# context2 = described_class.build(context1)
|
|
33
|
-
|
|
34
|
-
# expect(context2).to be_a(described_class)
|
|
35
|
-
# expect {
|
|
36
|
-
# context2.foo = "baz"
|
|
37
|
-
# }.to change {
|
|
38
|
-
# context1.foo
|
|
39
|
-
# }.from("bar").to("baz")
|
|
40
|
-
# end
|
|
41
|
-
# end
|
|
42
|
-
|
|
43
|
-
# describe "#success?" do
|
|
44
|
-
# let(:context) { described_class.build }
|
|
45
|
-
|
|
46
|
-
# it "is true by default" do
|
|
47
|
-
# expect(context.success?).to eq(true)
|
|
48
|
-
# end
|
|
49
|
-
# end
|
|
50
|
-
|
|
51
|
-
# describe "#failure?" do
|
|
52
|
-
# let(:context) { described_class.build }
|
|
53
|
-
|
|
54
|
-
# it "is false by default" do
|
|
55
|
-
# expect(context.failure?).to eq(false)
|
|
56
|
-
# end
|
|
57
|
-
# end
|
|
58
|
-
|
|
59
|
-
# describe "#fail!" do
|
|
60
|
-
# let(:context) { described_class.build(foo: "bar") }
|
|
61
|
-
|
|
62
|
-
# it "sets success to false" do
|
|
63
|
-
# expect {
|
|
64
|
-
# begin
|
|
65
|
-
# context.fail!
|
|
66
|
-
# rescue
|
|
67
|
-
# nil
|
|
68
|
-
# end
|
|
69
|
-
# }.to change(context, :success?).from(true).to(false)
|
|
70
|
-
# end
|
|
71
|
-
|
|
72
|
-
# it "sets failure to true" do
|
|
73
|
-
# expect {
|
|
74
|
-
# begin
|
|
75
|
-
# context.fail!
|
|
76
|
-
# rescue
|
|
77
|
-
# nil
|
|
78
|
-
# end
|
|
79
|
-
# }.to change(context, :failure?).from(false).to(true)
|
|
80
|
-
# end
|
|
81
|
-
|
|
82
|
-
# it "preserves failure" do
|
|
83
|
-
# begin
|
|
84
|
-
# context.fail!
|
|
85
|
-
# rescue
|
|
86
|
-
# nil
|
|
87
|
-
# end
|
|
88
|
-
|
|
89
|
-
# expect {
|
|
90
|
-
# begin
|
|
91
|
-
# context.fail!
|
|
92
|
-
# rescue
|
|
93
|
-
# nil
|
|
94
|
-
# end
|
|
95
|
-
# }.not_to change(context, :failure?)
|
|
96
|
-
# end
|
|
97
|
-
|
|
98
|
-
# it "preserves the context" do
|
|
99
|
-
# expect {
|
|
100
|
-
# begin
|
|
101
|
-
# context.fail!
|
|
102
|
-
# rescue
|
|
103
|
-
# nil
|
|
104
|
-
# end
|
|
105
|
-
# }.not_to change(context, :foo)
|
|
106
|
-
# end
|
|
107
|
-
|
|
108
|
-
# it "updates the context" do
|
|
109
|
-
# expect {
|
|
110
|
-
# begin
|
|
111
|
-
# context.fail!(foo: "baz")
|
|
112
|
-
# rescue
|
|
113
|
-
# nil
|
|
114
|
-
# end
|
|
115
|
-
# }.to change(context, :foo).from("bar").to("baz")
|
|
116
|
-
# end
|
|
117
|
-
|
|
118
|
-
# it "updates the context with a string key" do
|
|
119
|
-
# expect {
|
|
120
|
-
# begin
|
|
121
|
-
# context.fail!("foo" => "baz")
|
|
122
|
-
# rescue
|
|
123
|
-
# nil
|
|
124
|
-
# end
|
|
125
|
-
# }.to change(context, :foo).from("bar").to("baz")
|
|
126
|
-
# end
|
|
127
|
-
|
|
128
|
-
# it "raises failure" do
|
|
129
|
-
# expect {
|
|
130
|
-
# context.fail!
|
|
131
|
-
# }.to raise_error(Failure)
|
|
132
|
-
# end
|
|
133
|
-
|
|
134
|
-
# it "makes the context available from the failure" do
|
|
135
|
-
# context.fail!
|
|
136
|
-
# rescue Failure => e
|
|
137
|
-
# expect(e.context).to eq(context)
|
|
138
|
-
# end
|
|
139
|
-
# end
|
|
140
|
-
|
|
141
|
-
# describe "#called!" do
|
|
142
|
-
# let(:context) { described_class.build }
|
|
143
|
-
# let(:instance1) { instance_double(Interaktor) }
|
|
144
|
-
# let(:instance2) { instance_double(Interaktor) }
|
|
145
|
-
|
|
146
|
-
# it "appends to the internal list of called instances" do
|
|
147
|
-
# expect {
|
|
148
|
-
# context.called!(instance1)
|
|
149
|
-
# context.called!(instance2)
|
|
150
|
-
# }.to change(context, :_called).from([]).to([instance1, instance2])
|
|
151
|
-
# end
|
|
152
|
-
# end
|
|
153
|
-
|
|
154
|
-
# describe "#rollback!" do
|
|
155
|
-
# let(:context) { described_class.build }
|
|
156
|
-
# let(:instance1) { instance_double(Interaktor) }
|
|
157
|
-
# let(:instance2) { instance_double(Interaktor) }
|
|
158
|
-
|
|
159
|
-
# before do
|
|
160
|
-
# allow(context).to receive(:_called) { [instance1, instance2] }
|
|
161
|
-
# end
|
|
162
|
-
|
|
163
|
-
# it "rolls back each instance in reverse order" do
|
|
164
|
-
# expect(instance2).to receive(:rollback).once.with(no_args).ordered
|
|
165
|
-
# expect(instance1).to receive(:rollback).once.with(no_args).ordered
|
|
166
|
-
|
|
167
|
-
# context.rollback!
|
|
168
|
-
# end
|
|
169
|
-
|
|
170
|
-
# it "ignores subsequent attempts" do
|
|
171
|
-
# expect(instance2).to receive(:rollback).once
|
|
172
|
-
# expect(instance1).to receive(:rollback).once
|
|
173
|
-
|
|
174
|
-
# context.rollback!
|
|
175
|
-
# context.rollback!
|
|
176
|
-
# end
|
|
177
|
-
# end
|
|
178
|
-
|
|
179
|
-
# describe "#_called" do
|
|
180
|
-
# let(:context) { described_class.build }
|
|
181
|
-
|
|
182
|
-
# it "is empty by default" do
|
|
183
|
-
# expect(context._called).to eq([])
|
|
184
|
-
# end
|
|
185
|
-
# end
|
|
186
|
-
# end
|
|
187
|
-
end
|