activeinteractor 1.0.2 → 1.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -1
- data/lib/active_interactor.rb +1 -0
- data/lib/active_interactor/context/attributes.rb +2 -10
- data/lib/active_interactor/context/base.rb +1 -0
- data/lib/active_interactor/context/errors.rb +40 -0
- data/lib/active_interactor/context/loader.rb +1 -1
- data/lib/active_interactor/context/status.rb +12 -1
- data/lib/active_interactor/interactor/context.rb +2 -1
- data/lib/active_interactor/models.rb +1 -0
- data/lib/active_interactor/organizer/interactor_interface.rb +1 -1
- data/lib/active_interactor/version.rb +1 -1
- data/lib/rails/generators/templates/organizer.erb +2 -2
- data/spec/active_interactor/base_spec.rb +33 -0
- data/spec/active_interactor/context/base_spec.rb +1 -1
- data/spec/integration/a_basic_organizer_spec.rb +38 -0
- data/spec/spec_helper.rb +13 -15
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb760f4036450f632f5734d8575389462d80019152811ea20479754b04754aa2
|
4
|
+
data.tar.gz: ebc3326b09daec0e2b654a29014794aedf9e3d508d869d3b4aa1e180bf9b2fc8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1358b3923eb46838102b5e5e6c84021465cd3ade38954e9a36432019491e598f1d4b6aa2a1467816d81753a59d47d5205a10f5fa1fad2212110d926266ef20ae
|
7
|
+
data.tar.gz: 6318ca357ceba0628cbc13dec29bfe7971b8c5341a31f11c1b930ba060bc311b79813548fe73b99a4a689bb10019f9b02ea4e2c62d8753e260a47521a57c63f1
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [v1.0.3] - 2020-02-10
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- `ActiveInteractor::Context::Errors`
|
15
|
+
- `ActiveInteractor::Context::Status#resolve`
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- [\#168](https://github.com/aaronmallen/activeinteractor/issues/168) `#classify` is called on const arguments
|
20
|
+
- [\#169](https://github.com/aaronmallen/activeinteractor/issues/169) If some of the interactors of the organizer fail
|
21
|
+
error message is not persisted.
|
22
|
+
|
10
23
|
## [v1.0.2] - 2020-02-04
|
11
24
|
|
12
25
|
### Added
|
@@ -175,7 +188,8 @@ and this project adheres to [Semantic Versioning].
|
|
175
188
|
|
176
189
|
<!-- versions -->
|
177
190
|
|
178
|
-
[Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.
|
191
|
+
[Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.3...HEAD
|
192
|
+
[v1.0.3]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.2...v1.0.3
|
179
193
|
[v1.0.2]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.1...v1.0.2
|
180
194
|
[v1.0.1]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0...v1.0.1
|
181
195
|
[v1.0.0]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.7...v1.0.0
|
data/lib/active_interactor.rb
CHANGED
@@ -50,7 +50,7 @@ module ActiveInteractor
|
|
50
50
|
# @param context [Hash, Base, Class] attributes to assign to the {Base context}
|
51
51
|
# @return [Base] a new instance of {Base}
|
52
52
|
def initialize(context = {})
|
53
|
-
merge_errors!(context
|
53
|
+
merge_errors!(context) if context.respond_to?(:errors)
|
54
54
|
copy_flags!(context)
|
55
55
|
copy_called!(context)
|
56
56
|
context = context_attributes_as_hash(context) || {}
|
@@ -105,7 +105,7 @@ module ActiveInteractor
|
|
105
105
|
# @param context [Class] a {Base context} instance to be merged
|
106
106
|
# @return [self] the {Base context} instance
|
107
107
|
def merge!(context)
|
108
|
-
merge_errors!(context
|
108
|
+
merge_errors!(context) if context.respond_to?(:errors)
|
109
109
|
copy_flags!(context)
|
110
110
|
context.each_pair do |key, value|
|
111
111
|
public_send("#{key}=", value) unless value.nil?
|
@@ -143,14 +143,6 @@ module ActiveInteractor
|
|
143
143
|
public_send("#{key}=", value)
|
144
144
|
end
|
145
145
|
end
|
146
|
-
|
147
|
-
def merge_errors!(errors)
|
148
|
-
if errors.is_a? String
|
149
|
-
self.errors.add(:context, errors)
|
150
|
-
else
|
151
|
-
self.errors.merge!(errors)
|
152
|
-
end
|
153
|
-
end
|
154
146
|
end
|
155
147
|
end
|
156
148
|
end
|
@@ -326,6 +326,7 @@ module ActiveInteractor
|
|
326
326
|
include ActiveModel::Attributes
|
327
327
|
include ActiveModel::Validations
|
328
328
|
include ActiveInteractor::Context::Attributes
|
329
|
+
include ActiveInteractor::Context::Errors
|
329
330
|
include ActiveInteractor::Context::Status
|
330
331
|
end
|
331
332
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
# Context error methods. Because {Errors} is a module classes should include {Errors} rather than
|
6
|
+
# inherit from it.
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
10
|
+
# @since 1.0.3
|
11
|
+
module Errors
|
12
|
+
# Generic errors generated outside of validation.
|
13
|
+
#
|
14
|
+
# @return [ActiveModel::Errors] an instance of `ActiveModel::Errors`
|
15
|
+
def failure_errors
|
16
|
+
@failure_errors ||= ActiveModel::Errors.new(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def handle_errors(errors)
|
22
|
+
if errors.is_a?(String)
|
23
|
+
failure_errors.add(:context, errors)
|
24
|
+
else
|
25
|
+
failure_errors.merge!(errors)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def merge_errors!(other)
|
30
|
+
errors.merge!(other.errors)
|
31
|
+
failure_errors.merge!(other.errors)
|
32
|
+
failure_errors.merge!(other.failure_errors)
|
33
|
+
end
|
34
|
+
|
35
|
+
def resolve_errors
|
36
|
+
errors.merge!(failure_errors)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -22,7 +22,7 @@ module ActiveInteractor
|
|
22
22
|
# @param interactor_class [Const] an {ActiveInteractor::Base interactor} class
|
23
23
|
# @return [Const] a class that inherits from {Base}
|
24
24
|
def self.create(context_class_name, interactor_class)
|
25
|
-
interactor_class.const_set(context_class_name.to_s.
|
25
|
+
interactor_class.const_set(context_class_name.to_s.camelize, Class.new(BASE_CONTEXT))
|
26
26
|
end
|
27
27
|
|
28
28
|
# Find or create a {Base context} class for a given {ActiveInteractor::Base interactor}. If a class exists
|
@@ -37,8 +37,9 @@ module ActiveInteractor
|
|
37
37
|
# @see https://api.rubyonrails.org/classes/ActiveModel/Errors.html ActiveModel::Errors
|
38
38
|
# @raise [Error::ContextFailure]
|
39
39
|
def fail!(errors = nil)
|
40
|
-
|
40
|
+
handle_errors(errors) if errors
|
41
41
|
@_failed = true
|
42
|
+
resolve
|
42
43
|
raise ActiveInteractor::Error::ContextFailure, self
|
43
44
|
end
|
44
45
|
|
@@ -59,6 +60,16 @@ module ActiveInteractor
|
|
59
60
|
end
|
60
61
|
alias fail? failure?
|
61
62
|
|
63
|
+
# Resolve an instance of {Base context}. Called when an interactor
|
64
|
+
# is finished with it's context.
|
65
|
+
#
|
66
|
+
# @since 1.0.3
|
67
|
+
# @return [self] the instance of {Base context}
|
68
|
+
def resolve
|
69
|
+
resolve_errors
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
62
73
|
# {#rollback! Rollback} an instance of {Base context}. Any {ActiveInteractor::Base interactors} the instance has
|
63
74
|
# been passed via the {#called!} method are asked to roll themselves back by invoking their
|
64
75
|
# {Interactor::Perform#rollback #rollback} methods. The instance is also flagged as rolled back.
|
@@ -211,7 +211,7 @@ module ActiveInteractor
|
|
211
211
|
# @return [Const] the {Base interactor} class' {ActiveInteractor::Context::Base context} class
|
212
212
|
def contextualize_with(klass)
|
213
213
|
@context_class = begin
|
214
|
-
context_class = klass.to_s.
|
214
|
+
context_class = klass.to_s.camelize.safe_constantize
|
215
215
|
raise(ActiveInteractor::Error::InvalidContextClass, klass) unless context_class
|
216
216
|
|
217
217
|
context_class
|
@@ -366,6 +366,7 @@ module ActiveInteractor
|
|
366
366
|
# @return [Class] the {ActiveInteractor::Context::Base context} instance
|
367
367
|
def finalize_context!
|
368
368
|
context.called!(self)
|
369
|
+
context.resolve
|
369
370
|
context
|
370
371
|
end
|
371
372
|
|
@@ -40,6 +40,7 @@ module ActiveInteractor
|
|
40
40
|
extend ActiveInteractor::Context::Attributes::ClassMethods
|
41
41
|
|
42
42
|
include ActiveInteractor::Context::Attributes
|
43
|
+
include ActiveInteractor::Context::Errors
|
43
44
|
include ActiveInteractor::Context::Status
|
44
45
|
include ActiveInteractor::Models::InstanceMethods
|
45
46
|
delegate :each_pair, to: :attributes
|
@@ -40,7 +40,7 @@ module ActiveInteractor
|
|
40
40
|
# {Interactor::Perform::ClassMethods#perform .perform}. See {Interactor::Perform::Options}.
|
41
41
|
# @return [InteractorInterface] a new instance of {InteractorInterface}
|
42
42
|
def initialize(interactor_class, options = {})
|
43
|
-
@interactor_class = interactor_class.to_s.
|
43
|
+
@interactor_class = interactor_class.to_s.camelize.safe_constantize
|
44
44
|
@filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
|
45
45
|
@perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) }
|
46
46
|
end
|
@@ -6,8 +6,8 @@ class <%= class_name %> < ApplicationOrganizer
|
|
6
6
|
|
7
7
|
<%- end -%>
|
8
8
|
<%- if interactors.any? -%>
|
9
|
-
organize <%= interactors.
|
9
|
+
organize <%= interactors.join(", ") %>
|
10
10
|
<%- else -%>
|
11
|
-
# organize
|
11
|
+
# organize :interactor_1, :interactor_2
|
12
12
|
<%- end -%>
|
13
13
|
end
|
@@ -27,6 +27,17 @@ RSpec.describe ActiveInteractor::Base do
|
|
27
27
|
subject
|
28
28
|
expect(described_class.context_class).to eq TestContext
|
29
29
|
end
|
30
|
+
|
31
|
+
# https://github.com/aaronmallen/activeinteractor/issues/168
|
32
|
+
context 'when singularized' do
|
33
|
+
let!(:singularized_class) { build_context('PlaceData') }
|
34
|
+
let(:klass) { 'PlaceData' }
|
35
|
+
|
36
|
+
it 'is expected to assign the appropriate context class' do
|
37
|
+
subject
|
38
|
+
expect(described_class.context_class).to eq PlaceData
|
39
|
+
end
|
40
|
+
end
|
30
41
|
end
|
31
42
|
|
32
43
|
context 'when passed as a symbol' do
|
@@ -36,6 +47,17 @@ RSpec.describe ActiveInteractor::Base do
|
|
36
47
|
subject
|
37
48
|
expect(described_class.context_class).to eq TestContext
|
38
49
|
end
|
50
|
+
|
51
|
+
# https://github.com/aaronmallen/activeinteractor/issues/168
|
52
|
+
context 'when singularized' do
|
53
|
+
let!(:singularized_class) { build_context('PlaceData') }
|
54
|
+
let(:klass) { :place_data }
|
55
|
+
|
56
|
+
it 'is expected to assign the appropriate context class' do
|
57
|
+
subject
|
58
|
+
expect(described_class.context_class).to eq PlaceData
|
59
|
+
end
|
60
|
+
end
|
39
61
|
end
|
40
62
|
|
41
63
|
context 'when passed as a constant' do
|
@@ -45,6 +67,17 @@ RSpec.describe ActiveInteractor::Base do
|
|
45
67
|
subject
|
46
68
|
expect(described_class.context_class).to eq TestContext
|
47
69
|
end
|
70
|
+
|
71
|
+
# https://github.com/aaronmallen/activeinteractor/issues/168
|
72
|
+
context 'when singularized' do
|
73
|
+
let!(:singularized_class) { build_context('PlaceData') }
|
74
|
+
let(:klass) { PlaceData }
|
75
|
+
|
76
|
+
it 'is expected to assign the appropriate context class' do
|
77
|
+
subject
|
78
|
+
expect(described_class.context_class).to eq PlaceData
|
79
|
+
end
|
80
|
+
end
|
48
81
|
end
|
49
82
|
end
|
50
83
|
end
|
@@ -127,7 +127,7 @@ RSpec.describe ActiveInteractor::Context::Base do
|
|
127
127
|
it { expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure) }
|
128
128
|
|
129
129
|
it 'is expected not to merge errors' do
|
130
|
-
expect(instance.errors).not_to receive(:merge!)
|
130
|
+
expect(instance.errors).not_to receive(:merge!).with(nil)
|
131
131
|
subject
|
132
132
|
rescue ActiveInteractor::Error::ContextFailure # rubocop:disable Lint/SuppressedException
|
133
133
|
end
|
@@ -69,6 +69,25 @@ RSpec.describe 'A basic organizer', type: :integration do
|
|
69
69
|
expect_any_instance_of(test_interactor_2).not_to receive(:perform!)
|
70
70
|
subject
|
71
71
|
end
|
72
|
+
|
73
|
+
# https://github.com/aaronmallen/activeinteractor/issues/169
|
74
|
+
context 'with error message "something went wrong"' do
|
75
|
+
let!(:test_interactor_1) do
|
76
|
+
build_interactor('TestInteractor1') do
|
77
|
+
def perform
|
78
|
+
context.fail!('something went wrong')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it { expect { subject }.not_to raise_error }
|
84
|
+
it { is_expected.to be_a interactor_class.context_class }
|
85
|
+
it { is_expected.to be_failure }
|
86
|
+
it 'is expected to have errors "something went wrong" on :context' do
|
87
|
+
expect(subject.errors[:context]).not_to be_empty
|
88
|
+
expect(subject.errors[:context]).to include 'something went wrong'
|
89
|
+
end
|
90
|
+
end
|
72
91
|
end
|
73
92
|
end
|
74
93
|
|
@@ -92,6 +111,25 @@ RSpec.describe 'A basic organizer', type: :integration do
|
|
92
111
|
expect_any_instance_of(test_interactor_1).to receive(:rollback)
|
93
112
|
subject
|
94
113
|
end
|
114
|
+
|
115
|
+
# https://github.com/aaronmallen/activeinteractor/issues/169
|
116
|
+
context 'with error message "something went wrong"' do
|
117
|
+
let!(:test_interactor_2) do
|
118
|
+
build_interactor('TestInteractor2') do
|
119
|
+
def perform
|
120
|
+
context.fail!('something went wrong')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it { expect { subject }.not_to raise_error }
|
126
|
+
it { is_expected.to be_a interactor_class.context_class }
|
127
|
+
it { is_expected.to be_failure }
|
128
|
+
it 'is expected to have errors "something went wrong" on :context' do
|
129
|
+
expect(subject.errors[:context]).not_to be_empty
|
130
|
+
expect(subject.errors[:context]).to include 'something went wrong'
|
131
|
+
end
|
132
|
+
end
|
95
133
|
end
|
96
134
|
end
|
97
135
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
begin
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
add_filter '/lib/rails/**/*.rb'
|
18
|
-
track_files '/lib/**/*.rb'
|
4
|
+
if ENV['CODACY_PROJECT_TOKEN']
|
5
|
+
require 'codacy-coverage'
|
6
|
+
|
7
|
+
Codacy::Reporter.start
|
8
|
+
else
|
9
|
+
require 'simplecov'
|
10
|
+
|
11
|
+
SimpleCov.start do
|
12
|
+
enable_coverage :branch
|
13
|
+
add_filter '/spec/'
|
14
|
+
add_filter '/lib/rails/**/*.rb'
|
15
|
+
track_files '/lib/**/*.rb'
|
16
|
+
end
|
19
17
|
end
|
20
18
|
rescue LoadError
|
21
19
|
puts 'Skipping coverage...'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeinteractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Allen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/active_interactor/configurable.rb
|
112
112
|
- lib/active_interactor/context/attributes.rb
|
113
113
|
- lib/active_interactor/context/base.rb
|
114
|
+
- lib/active_interactor/context/errors.rb
|
114
115
|
- lib/active_interactor/context/loader.rb
|
115
116
|
- lib/active_interactor/context/status.rb
|
116
117
|
- lib/active_interactor/error.rb
|
@@ -200,10 +201,10 @@ licenses:
|
|
200
201
|
- MIT
|
201
202
|
metadata:
|
202
203
|
bug_tracker_uri: https://github.com/aaronmallen/activeinteractor/issues
|
203
|
-
changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v1.0.
|
204
|
-
documentation_uri: https://www.rubydoc.info/gems/activeinteractor/1.0.
|
204
|
+
changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v1.0.3/CHANGELOG.md
|
205
|
+
documentation_uri: https://www.rubydoc.info/gems/activeinteractor/1.0.3
|
205
206
|
hompage_uri: https://github.com/aaronmallen/activeinteractor
|
206
|
-
source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.0.
|
207
|
+
source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.0.3
|
207
208
|
wiki_uri: https://github.com/aaronmallen/activeinteractor/wiki
|
208
209
|
post_install_message:
|
209
210
|
rdoc_options: []
|