activeinteractor 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|