activeinteractor 1.0.1 → 1.0.2

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
  SHA256:
3
- metadata.gz: 91b9f4936670919fb0f3f1bda4f9320a3abd439adef16b7bae4d8cf14d3fb6da
4
- data.tar.gz: 725547555164c173ab870afafb3f8ee43b6e355c3fcab3732b5a457d66e4f468
3
+ metadata.gz: f83ff894cc3ce150f3a97ab2b006035acf9f27c181040f02c04e0058b3d3dd49
4
+ data.tar.gz: fd8d75ec724d1b35eec4b7cd2017c74a9fb61c54209f58830a7ffd5b780b5ba8
5
5
  SHA512:
6
- metadata.gz: bfd019dc0f1b7c86a7de23cca6c663b8be68c6ed5d1e4bb11aa6a09101e72537dab5f06f985b1ee38b5f3cd4b763615473031525227d75f14e70bfa48a33f0f2
7
- data.tar.gz: 3c1e0a9d3340ec4362de5232fad83172537819b034fc891b5a1ac74f83f079c0ef03a9f2e6eace44125d1546a315ab4818c8989a4c3c931c050480ee1e82e65e
6
+ metadata.gz: '085c0039e71216c6c3dc734a4aad4bb30fc0bf5fa5babe8a9b72e2b961c5066732c5bdfbc5eb1566ababc42cbcf38e1b5e3d87e61a94251e08eec2c13a99c524'
7
+ data.tar.gz: fa572ba8068e8856bfbc405500cffd4b398f47c67d7b665a02ead9a5d701cdb62983f17e6eb6df7c13f7b29b981c58054a7613b6eb4970a488c45d15acc7bc40
data/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning].
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [v1.0.2] - 2020-02-04
11
+
12
+ ### Added
13
+
14
+ - Support for `Dynamoid` ORM
15
+ - Support for `Mongoid` ORM
16
+
17
+ ### Changed
18
+
19
+ - `ActiveInteractor::Models#acts_as_context` no longer includes `ActiveModel::Validations`
20
+ - `ActiveInteractor::Models#acts_as_context` now includes `ActiveInteractor::Context::Attributes`
21
+
22
+ ### Removed
23
+
24
+ - `ActiveInteractor::Models::InstanceMethods#merge!`
25
+
10
26
  ## [v1.0.1] - 2020-01-28
11
27
 
12
28
  ### Added
@@ -159,7 +175,8 @@ and this project adheres to [Semantic Versioning].
159
175
 
160
176
  <!-- versions -->
161
177
 
162
- [Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.1...HEAD
178
+ [Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.2...HEAD
179
+ [v1.0.2]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.1...v1.0.2
163
180
  [v1.0.1]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0...v1.0.1
164
181
  [v1.0.0]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.7...v1.0.0
165
182
  [v0.1.7]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.6...v0.1.7
data/README.md CHANGED
@@ -1,17 +1,28 @@
1
1
  # ActiveInteractor
2
2
 
3
3
  [![Version](https://img.shields.io/gem/v/activeinteractor.svg?logo=ruby)](https://rubygems.org/gems/activeinteractor)
4
- [![License](https://img.shields.io/github/license/aaronmallen/activeinteractor.svg?maxAge=300)](https://github.com/aaronmallen/activeinteractor/blob/master/LICENSE)
5
- [![Dependencies](https://img.shields.io/depfu/aaronmallen/activeinteractor.svg?maxAge=300)](https://depfu.com/github/aaronmallen/activeinteractor)
6
-
7
4
  [![Build Status](https://github.com/aaronmallen/activeinteractor/workflows/Build/badge.svg)](https://github.com/aaronmallen/activeinteractor/actions)
8
5
  [![Code Quality](https://api.codacy.com/project/badge/Grade/be92c4ecf12347da82d266f6a4368b6e)](https://www.codacy.com/manual/aaronmallen/activeinteractor?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=aaronmallen/activeinteractor&amp;utm_campaign=Badge_Grade)
9
6
  [![Test Coverage](https://api.codacy.com/project/badge/Coverage/be92c4ecf12347da82d266f6a4368b6e)](https://www.codacy.com/manual/aaronmallen/activeinteractor?utm_source=github.com&utm_medium=referral&utm_content=aaronmallen/activeinteractor&utm_campaign=Badge_Coverage)
7
+ [![Dependencies](https://img.shields.io/depfu/aaronmallen/activeinteractor.svg?maxAge=300)](https://depfu.com/github/aaronmallen/activeinteractor)
8
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/activeinteractor)
9
+ [![Inline docs](http://inch-ci.org/github/aaronmallen/activeinteractor.svg?branch=master)](http://inch-ci.org/github/aaronmallen/activeinteractor)
10
+ [![License](https://img.shields.io/github/license/aaronmallen/activeinteractor.svg?maxAge=300)](https://github.com/aaronmallen/activeinteractor/blob/master/LICENSE)
10
11
 
11
12
  An implementation of the [command pattern] for Ruby with [ActiveModel::Validations] inspired by the
12
13
  [interactor][collective_idea_interactors] gem. Rich support for attributes, callbacks, and validations,
13
14
  and thread safe performance methods.
14
15
 
16
+ Reduce controller bloat with procedural service objects. Checkout this [Medium article] for a crash
17
+ course on how to use ActiveInteractors. Read the [wiki] for detailed usage information.
18
+
19
+ ## Features
20
+
21
+ * [Context validation][wiki_context_validation]
22
+ * [Callbacks][wiki_callbacks]
23
+ * Thread safe performance calls
24
+ * Organize multiple interactors [conditionally][wiki_organizers_conditionally] or in [parallel][wiki_organizers_parallel]
25
+
15
26
  ## Getting Started
16
27
 
17
28
  Add this line to your application's Gemfile:
@@ -68,6 +79,11 @@ The gem is available as open source under the terms of the [MIT License][mit_lic
68
79
  [business_logic_wikipedia]: https://en.wikipedia.org/wiki/Business_logic
69
80
  [collective_idea_interactors]: https://github.com/collectiveidea/interactor
70
81
  [command pattern]: https://en.wikipedia.org/wiki/Command_pattern
82
+ [Medium article]: https://medium.com/@aaronmallen/activeinteractor-8557c0dc78db
71
83
  [mit_license]: https://opensource.org/licenses/MIT
72
84
  [ruby docs]: https://www.rubydoc.info/gems/activeinteractor
73
85
  [wiki]: https://github.com/aaronmallen/activeinteractor/wiki
86
+ [wiki_callbacks]: https://github.com/aaronmallen/activeinteractor/wiki/Callbacks
87
+ [wiki_context_validation]: https://github.com/aaronmallen/activeinteractor/wiki/Context#validating-the-context
88
+ [wiki_organizers_conditionally]: https://github.com/aaronmallen/activeinteractor/wiki/Interactors#organizing-interactors-conditionally
89
+ [wiki_organizers_parallel]: https://github.com/aaronmallen/activeinteractor/wiki/Interactors#running-interactors-in-parallel
@@ -53,6 +53,7 @@ module ActiveInteractor
53
53
  merge_errors!(context.errors) if context.respond_to?(:errors)
54
54
  copy_flags!(context)
55
55
  copy_called!(context)
56
+ context = context_attributes_as_hash(context) || {}
56
57
  super
57
58
 
58
59
  merge_attribute_values(context)
@@ -114,6 +115,27 @@ module ActiveInteractor
114
115
 
115
116
  private
116
117
 
118
+ def _called
119
+ @_called ||= []
120
+ end
121
+
122
+ def context_attributes_as_hash(context)
123
+ return context.to_h if context&.respond_to?(:to_h)
124
+ return context.attributes.to_h if context.respond_to?(:attributes)
125
+ end
126
+
127
+ def copy_called!(context)
128
+ value = context.instance_variable_get('@_called') || []
129
+ instance_variable_set('@_called', value)
130
+ end
131
+
132
+ def copy_flags!(context)
133
+ %w[_failed _rolled_back].each do |flag|
134
+ value = context.instance_variable_get("@#{flag}")
135
+ instance_variable_set("@#{flag}", value)
136
+ end
137
+ end
138
+
117
139
  def merge_attribute_values(context)
118
140
  return unless context
119
141
 
@@ -90,24 +90,6 @@ module ActiveInteractor
90
90
  !failure?
91
91
  end
92
92
  alias successful? success?
93
-
94
- private
95
-
96
- def _called
97
- @_called ||= []
98
- end
99
-
100
- def copy_called!(context)
101
- value = context.instance_variable_get('@_called') || []
102
- instance_variable_set('@_called', value)
103
- end
104
-
105
- def copy_flags!(context)
106
- %w[_failed _rolled_back].each do |flag|
107
- value = context.instance_variable_get("@#{flag}")
108
- instance_variable_set("@#{flag}", value)
109
- end
110
- end
111
93
  end
112
94
  end
113
95
  end
@@ -13,39 +13,21 @@ module ActiveInteractor
13
13
  # @author Aaron Allen <hello@aaronmallen.me>
14
14
  # @since 1.0.0
15
15
  module InstanceMethods
16
- def initialize(attributes = nil)
17
- copy_flags!(attributes) if attributes
18
- copy_called!(attributes) if attributes
19
- attributes_as_hash = context_attributes_as_hash(attributes)
20
- super(attributes_as_hash)
21
- end
22
-
23
- # Merge an instance of model class into the calling model class instance
24
- #
25
- # @see Context::Attributes#merge!
26
- #
27
- # @param context [Class] a {Base context} instance to be merged
28
- # @return [self] the {Base context} instance
29
- def merge!(context)
30
- copy_flags!(context)
31
- context.each_pair do |key, value|
32
- self[key] = value unless value.nil?
33
- end
34
- self
35
- end
36
-
37
- private
38
-
39
- def context_attributes_as_hash(attributes)
40
- return attributes.to_h if attributes&.respond_to?(:to_h)
41
- return attributes.attributes.to_h if attributes.respond_to?(:attributes)
16
+ def initialize(*)
17
+ @attributes = self.class._default_attributes&.deep_dup
18
+ super
42
19
  end
43
20
  end
44
21
 
45
22
  # Include methods needed for a {Context::Base context} class to function properly.
46
23
  #
24
+ # @note You must include ActiveModel::Model and ActiveModel::Attributes or a similar implementation for
25
+ # the object to function properly.
26
+ #
47
27
  # @example
48
28
  # class User
29
+ # include ActiveModel::Model
30
+ # include ActiveModel::Attributes
49
31
  # extend ActiveInteractor::Models
50
32
  # acts_as_context
51
33
  # end
@@ -55,9 +37,11 @@ module ActiveInteractor
55
37
  # end
56
38
  def acts_as_context
57
39
  class_eval do
58
- include ActiveModel::Validations
59
- include ActiveInteractor::Models::InstanceMethods
40
+ extend ActiveInteractor::Context::Attributes::ClassMethods
41
+
42
+ include ActiveInteractor::Context::Attributes
60
43
  include ActiveInteractor::Context::Status
44
+ include ActiveInteractor::Models::InstanceMethods
61
45
  delegate :each_pair, to: :attributes
62
46
  end
63
47
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dynamoid/document'
4
+
5
+ Dynamoid::Document::ClassMethods.include ActiveInteractor::Models
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveSupport.on_load(:mongoid) do
4
+ Mongoid::Document::ClassMethods.include ActiveInteractor::Models
5
+ end
@@ -3,5 +3,5 @@
3
3
  module ActiveInteractor
4
4
  # The ActiveInteractor version
5
5
  # @return [String] the ActiveInteractor version
6
- VERSION = '1.0.1'
6
+ VERSION = '1.0.2'
7
7
  end
@@ -6,356 +6,22 @@ begin
6
6
  require 'active_interactor/rails/orm/active_record'
7
7
 
8
8
  RSpec.describe 'ActiveRecord integration', type: :integration do
9
- let!(:active_record_base_mock) do
10
- build_class('ActiveRecordBaseMock') do
11
- def self.attr_accessor(*attributes)
12
- attribute_keys.concat(attributes.map(&:to_sym))
13
- super
14
- end
15
-
16
- def self.attribute_keys
17
- @attribute_keys ||= []
18
- end
19
-
20
- def initialize(attributes = nil, _options = {})
21
- (attributes || {}).each do |key, value|
22
- instance_variable_set("@#{key}", value)
23
- end
24
- end
25
-
26
- def [](name)
27
- instance_variable_get("@#{name}")
28
- end
29
-
30
- def []=(name, value)
31
- instance_variable_set("@#{name}", value)
32
- end
33
-
34
- def attributes
35
- self.class.attribute_keys.each_with_object({}) do |key, hash|
36
- hash[key] = instance_variable_get("@#{key}")
37
- end
38
- end
39
-
40
- def to_h
41
- attributes.to_h
42
- end
43
- end
44
- end
9
+ let!(:active_record_base_mock) { build_class('ActiveRecordBaseMock') }
45
10
 
46
11
  context 'after ActiveSupport.run_load_hooks has been received with :active_record' do
47
12
  before { ActiveSupport.run_load_hooks(:active_record, active_record_base_mock) }
48
13
 
49
- describe 'an ActiveRecord model class with .acts_as_context' do
50
- let(:model_mock) do
51
- build_class('ModelMock', active_record_base_mock) do
52
- attr_accessor :foo
14
+ describe 'an ActiveRecord model class with .acts_as_context and attribute :foo' do
15
+ let(:model_class) do
16
+ build_class('ModelClass', active_record_base_mock) do
17
+ include ActiveModel::Attributes
18
+ include ActiveModel::Model
53
19
  acts_as_context
20
+ attribute :foo
54
21
  end
55
22
  end
56
23
 
57
- describe 'as an instance' do
58
- subject { model_mock.new }
59
-
60
- it { is_expected.to respond_to :called! }
61
- it { is_expected.to respond_to :fail! }
62
- it { is_expected.to respond_to :fail? }
63
- it { is_expected.to respond_to :failure? }
64
- it { is_expected.to respond_to :merge! }
65
- it { is_expected.to respond_to :rollback! }
66
- it { is_expected.to respond_to :success? }
67
- it { is_expected.to respond_to :successful? }
68
- end
69
-
70
- describe '.new' do
71
- subject { model_mock.new(attributes) }
72
- let(:attributes) { nil }
73
-
74
- it 'is expected not to receive #copy_flags!' do
75
- expect_any_instance_of(model_mock).not_to receive(:copy_flags!)
76
- subject
77
- end
78
-
79
- it 'is expected not to receive #copy_called!' do
80
- expect_any_instance_of(model_mock).not_to receive(:copy_called!)
81
- subject
82
- end
83
-
84
- it 'is expected to receive super on parent class with nil attributes' do
85
- expect(active_record_base_mock).to receive(:new).with(nil)
86
- subject
87
- end
88
-
89
- context 'with attributes { :foo => "foo" }' do
90
- let(:attributes) { { foo: 'foo' } }
91
-
92
- it { expect { subject }.not_to raise_error }
93
-
94
- it 'is expected to receive #copy_flags!' do
95
- expect_any_instance_of(model_mock).to receive(:copy_flags!).with(foo: 'foo')
96
- subject
97
- end
98
-
99
- it 'is expected to receive #copy_called!' do
100
- expect_any_instance_of(model_mock).to receive(:copy_called!).with(foo: 'foo')
101
- subject
102
- end
103
-
104
- it 'is expected to receive super on parent class with { :foo => "foo" }' do
105
- expect(active_record_base_mock).to receive(:new).with(foo: 'foo')
106
- subject
107
- end
108
- end
109
-
110
- context 'with attributes being an instance of ModelMock having attributes { :foo => "foo" }' do
111
- let(:previous_instance) { model_mock.new(foo: 'foo') }
112
- let(:attributes) { previous_instance }
113
-
114
- it { is_expected.to have_attributes(foo: 'foo') }
115
-
116
- context 'with _failed equal to true on previous instance' do
117
- before { previous_instance.instance_variable_set('@_failed', true) }
118
-
119
- it { is_expected.to be_failure }
120
- end
121
-
122
- context 'with _rolled_back equal to true on previous instance' do
123
- before { previous_instance.instance_variable_set('@_rolled_back', true) }
124
-
125
- it 'is expected to have instance variable @_rolled_back eq to true' do
126
- expect(subject.instance_variable_get('@_rolled_back')).to eq true
127
- end
128
- end
129
-
130
- context 'with _called eq to ["foo"] on previous instance' do
131
- before { previous_instance.instance_variable_set('@_called', %w[foo]) }
132
-
133
- it 'is expected to have instance variable @_called eq to ["foo"]' do
134
- expect(subject.instance_variable_get('@_called')).to eq %w[foo]
135
- end
136
- end
137
- end
138
- end
139
-
140
- describe '#merge!' do
141
- subject { model_mock.new(attributes).merge!(merge_instance) }
142
- context 'having attributes { :foo => nil }' do
143
- let(:attributes) { { foo: nil } }
144
-
145
- context 'with merging instance having attributes { :foo => "foo" }' do
146
- let(:merge_instance) { model_mock.new(foo: 'foo') }
147
-
148
- it { is_expected.to have_attributes(foo: 'foo') }
149
-
150
- context 'with _failed equal to true on merging instance' do
151
- before { merge_instance.instance_variable_set('@_failed', true) }
152
-
153
- it { is_expected.to be_failure }
154
- end
155
-
156
- context 'with _rolled_back equal to true on merging instance' do
157
- before { merge_instance.instance_variable_set('@_rolled_back', true) }
158
-
159
- it 'is expected to have instance variable @_rolled_back eq to true' do
160
- expect(subject.instance_variable_get('@_rolled_back')).to eq true
161
- end
162
- end
163
- end
164
- end
165
-
166
- context 'having attributes { :foo => "foo"}' do
167
- let(:attributes) { { foo: 'foo' } }
168
-
169
- context 'with merging instance having attributes { :foo => "bar" }' do
170
- let(:merge_instance) { model_mock.new(foo: 'bar') }
171
-
172
- it { is_expected.to have_attributes(foo: 'bar') }
173
-
174
- context 'with _failed equal to true on merging instance' do
175
- before { merge_instance.instance_variable_set('@_failed', true) }
176
-
177
- it { is_expected.to be_failure }
178
- end
179
-
180
- context 'with _rolled_back equal to true on merging instance' do
181
- before { merge_instance.instance_variable_set('@_rolled_back', true) }
182
-
183
- it 'is expected to have instance variable @_rolled_back eq to true' do
184
- expect(subject.instance_variable_get('@_rolled_back')).to eq true
185
- end
186
- end
187
- end
188
- end
189
- end
190
- end
191
-
192
- describe 'a basic interactor using an ActiveRecord model class as context' do
193
- let!(:model_mock) do
194
- require 'active_model'
195
- build_class('ModelMock', active_record_base_mock) do
196
- include ActiveModel::Validations
197
- attr_accessor :foo
198
- acts_as_context
199
- end
200
- end
201
-
202
- let(:interactor_class) do
203
- build_interactor do
204
- contextualize_with :model_mock
205
-
206
- def perform
207
- context.foo = 'foo'
208
- end
209
- end
210
- end
211
-
212
- include_examples 'a class with interactor methods'
213
- include_examples 'a class with interactor callback methods'
214
- include_examples 'a class with interactor context methods'
215
-
216
- describe '.context_class' do
217
- subject { interactor_class.context_class }
218
-
219
- it { is_expected.to eq model_mock }
220
- end
221
-
222
- describe '.perform' do
223
- subject { interactor_class.perform }
224
-
225
- it { is_expected.to be_a model_mock }
226
- it { is_expected.to be_successful }
227
- it { is_expected.to have_attributes(foo: 'foo') }
228
- end
229
-
230
- describe '.perform!' do
231
- subject { interactor_class.perform! }
232
-
233
- it { expect { subject }.not_to raise_error }
234
- it { is_expected.to be_a model_mock }
235
- it { is_expected.to be_successful }
236
- it { is_expected.to have_attributes(foo: 'foo') }
237
- end
238
-
239
- context 'failing the context on #perform' do
240
- let(:interactor_class) do
241
- build_interactor do
242
- contextualize_with :model_mock
243
-
244
- def perform
245
- context.fail!
246
- end
247
- end
248
- end
249
-
250
- describe '.perform' do
251
- subject { interactor_class.perform }
252
-
253
- it { expect { subject }.not_to raise_error }
254
- it { is_expected.to be_a model_mock }
255
- it { is_expected.to be_failure }
256
- it 'is expected to receive #rollback' do
257
- expect_any_instance_of(interactor_class).to receive(:rollback)
258
- subject
259
- end
260
- end
261
-
262
- describe '.perform!' do
263
- subject { interactor_class.perform! }
264
-
265
- it { expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure) }
266
- end
267
- end
268
- end
269
-
270
- describe 'a basic organizer using an ActiveRecord model class as context' do
271
- let!(:model_mock) do
272
- require 'active_model'
273
- build_class('ModelMock', active_record_base_mock) do
274
- include ActiveModel::Validations
275
- attr_accessor :first_name, :last_name
276
- acts_as_context
277
- end
278
- end
279
-
280
- context 'with each organized interactor using the model' do
281
- let!(:test_interactor_1) do
282
- build_interactor('TestInteractor1') do
283
- contextualize_with :model_mock
284
-
285
- def perform
286
- context.first_name = 'Test'
287
- end
288
- end
289
- end
290
-
291
- let!(:test_interactor_2) do
292
- build_interactor('TestInteractor2') do
293
- contextualize_with :model_mock
294
-
295
- def perform
296
- context.last_name = 'User'
297
- end
298
- end
299
- end
300
-
301
- let(:interactor_class) do
302
- build_organizer do
303
- contextualize_with :model_mock
304
- organize :test_interactor_1, :test_interactor_2
305
- end
306
- end
307
-
308
- include_examples 'a class with interactor methods'
309
- include_examples 'a class with interactor callback methods'
310
- include_examples 'a class with interactor context methods'
311
- include_examples 'a class with organizer callback methods'
312
-
313
- describe '.perform' do
314
- subject { interactor_class.perform }
315
-
316
- it { is_expected.to be_a model_mock }
317
- it { is_expected.to be_successful }
318
- it { is_expected.to have_attributes(first_name: 'Test', last_name: 'User') }
319
- end
320
- end
321
-
322
- context 'with each organized interactor using their default context' do
323
- let!(:test_interactor_1) do
324
- build_interactor('TestInteractor1') do
325
- def perform
326
- context.first_name = 'Test'
327
- end
328
- end
329
- end
330
-
331
- let!(:test_interactor_2) do
332
- build_interactor('TestInteractor2') do
333
- def perform
334
- context.last_name = 'User'
335
- end
336
- end
337
- end
338
-
339
- let(:interactor_class) do
340
- build_organizer do
341
- contextualize_with :model_mock
342
- organize :test_interactor_1, :test_interactor_2
343
- end
344
- end
345
-
346
- include_examples 'a class with interactor methods'
347
- include_examples 'a class with interactor callback methods'
348
- include_examples 'a class with interactor context methods'
349
- include_examples 'a class with organizer callback methods'
350
-
351
- describe '.perform' do
352
- subject { interactor_class.perform }
353
-
354
- it { is_expected.to be_a model_mock }
355
- it { is_expected.to be_successful }
356
- it { is_expected.to have_attributes(first_name: 'Test', last_name: 'User') }
357
- end
358
- end
24
+ include_examples 'A class that extends ActiveInteractor::Models'
359
25
  end
360
26
  end
361
27
  end
data/spec/spec_helper.rb CHANGED
@@ -1,13 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'support/coverage'
4
-
5
- Spec::Coverage::Runner.start do
6
- add_formatter :simple_cov_html
7
- add_formatter :codacy
8
- track '/lib/**/*.rb'
9
- filter '/spec/'
10
- filter '/lib/rails/**'
3
+ begin
4
+ require 'codacy-coverage'
5
+ require 'simplecov'
6
+
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
8
+ [
9
+ SimpleCov::Formatter::HTMLFormatter,
10
+ Codacy::Formatter
11
+ ]
12
+ )
13
+
14
+ SimpleCov.start do
15
+ enable_coverage :branch
16
+ add_filter '/spec/'
17
+ add_filter '/lib/rails/**/*.rb'
18
+ track_files '/lib/**/*.rb'
19
+ end
20
+ rescue LoadError
21
+ puts 'Skipping coverage...'
11
22
  end
12
23
 
13
24
  require 'bundler/setup'
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples 'A class that extends ActiveInteractor::Models' do
4
+ it { expect(model_class).to respond_to :attribute }
5
+ it { expect(model_class).to respond_to :attributes }
6
+
7
+ describe 'as an instance' do
8
+ subject { model_class.new }
9
+
10
+ it { is_expected.to respond_to :attributes }
11
+ it { is_expected.to respond_to :called! }
12
+ it { is_expected.to respond_to :fail! }
13
+ it { is_expected.to respond_to :fail? }
14
+ it { is_expected.to respond_to :failure? }
15
+ it { is_expected.to respond_to :merge! }
16
+ it { is_expected.to respond_to :rollback! }
17
+ it { is_expected.to respond_to :success? }
18
+ it { is_expected.to respond_to :successful? }
19
+ end
20
+
21
+ describe '.new' do
22
+ subject { model_class.new(attributes) }
23
+
24
+ describe 'with arguments {:foo => "foo"}' do
25
+ let(:attributes) { { foo: 'foo' } }
26
+
27
+ it { is_expected.to have_attributes(foo: 'foo') }
28
+ end
29
+
30
+ describe 'with arguments {:bar => "bar"}' do
31
+ let(:attributes) { model_class.new(bar: 'bar') }
32
+
33
+ it { expect { subject }.to raise_error(ActiveModel::UnknownAttributeError) }
34
+ end
35
+
36
+ describe 'with arguments <#ModelClass foo="foo">' do
37
+ let(:other_instance) { model_class.new(foo: 'foo') }
38
+ let(:attributes) { other_instance }
39
+
40
+ it { is_expected.to have_attributes(foo: 'foo') }
41
+
42
+ context 'with argument instance having @_failed eq to true' do
43
+ before { other_instance.instance_variable_set('@_failed', true) }
44
+
45
+ it { is_expected.to be_failure }
46
+ end
47
+
48
+ context 'with argument instance having @_called eq to ["foo"]' do
49
+ before { other_instance.instance_variable_set('@_called', %w[foo]) }
50
+
51
+ it 'is expected to have instance variable @_called eq to ["foo"]' do
52
+ expect(subject.instance_variable_get('@_called')).to eq %w[foo]
53
+ end
54
+ end
55
+
56
+ context 'with argument instance having @_rolled_back eq to true' do
57
+ before { other_instance.instance_variable_set('@_rolled_back', true) }
58
+
59
+ it 'is expected to have instance variable @_rolled_back eq to true' do
60
+ expect(subject.instance_variable_get('@_rolled_back')).to eq true
61
+ end
62
+ end
63
+ end
64
+
65
+ describe 'with arguments <#OtherClass bar="bar">' do
66
+ let(:attributes) { model_class.new(other_instance) }
67
+ let!(:other_class) do
68
+ build_class('OtherClass') do
69
+ include ActiveModel::Attributes
70
+ include ActiveModel::Model
71
+ extend ActiveInteractor::Models
72
+ acts_as_context
73
+ attribute :bar
74
+ end
75
+ end
76
+ let(:other_instance) { other_class.new(bar: 'bar') }
77
+
78
+ it { expect { subject }.to raise_error(ActiveModel::UnknownAttributeError) }
79
+ end
80
+ end
81
+ end
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.1
4
+ version: 1.0.2
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-01-28 00:00:00.000000000 Z
11
+ date: 2020-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -127,6 +127,8 @@ files:
127
127
  - lib/active_interactor/organizer/perform.rb
128
128
  - lib/active_interactor/rails.rb
129
129
  - lib/active_interactor/rails/orm/active_record.rb
130
+ - lib/active_interactor/rails/orm/dynamoid.rb
131
+ - lib/active_interactor/rails/orm/mongoid.rb
130
132
  - lib/active_interactor/rails/railtie.rb
131
133
  - lib/active_interactor/version.rb
132
134
  - lib/rails/generators/active_interactor.rb
@@ -186,12 +188,8 @@ files:
186
188
  - spec/integration/an_organizer_with_before_each_callbacks_spec.rb
187
189
  - spec/integration/an_organizer_with_conditionally_organized_interactors_spec.rb
188
190
  - spec/spec_helper.rb
189
- - spec/support/coverage.rb
190
- - spec/support/coverage/reporters.rb
191
- - spec/support/coverage/reporters/codacy.rb
192
- - spec/support/coverage/reporters/simple_cov.rb
193
- - spec/support/coverage/runner.rb
194
191
  - spec/support/helpers/factories.rb
192
+ - spec/support/shared_examples/a_class_that_extends_active_interactor_models_example.rb
195
193
  - spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb
196
194
  - spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb
197
195
  - spec/support/shared_examples/a_class_with_interactor_methods_example.rb
@@ -202,10 +200,10 @@ licenses:
202
200
  - MIT
203
201
  metadata:
204
202
  bug_tracker_uri: https://github.com/aaronmallen/activeinteractor/issues
205
- changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v1.0.1/CHANGELOG.md
206
- documentation_uri: https://www.rubydoc.info/gems/activeinteractor/1.0.1
203
+ changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v1.0.2/CHANGELOG.md
204
+ documentation_uri: https://www.rubydoc.info/gems/activeinteractor/1.0.2
207
205
  hompage_uri: https://github.com/aaronmallen/activeinteractor
208
- source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.0.1
206
+ source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.0.2
209
207
  wiki_uri: https://github.com/aaronmallen/activeinteractor/wiki
210
208
  post_install_message:
211
209
  rdoc_options: []
@@ -227,45 +225,41 @@ signing_key:
227
225
  specification_version: 4
228
226
  summary: Ruby interactors with ActiveModel::Validations
229
227
  test_files:
230
- - spec/active_interactor_spec.rb
231
- - spec/integration/a_failing_interactor_spec.rb
232
- - spec/integration/active_record_integration_spec.rb
233
- - spec/integration/an_interactor_with_validations_on_called_spec.rb
234
- - spec/integration/an_interactor_with_around_perform_callbacks_spec.rb
235
- - spec/integration/an_interactor_with_before_rollback_callbacks_spec.rb
236
- - spec/integration/a_basic_organizer_spec.rb
237
- - spec/integration/an_interactor_with_around_rollback_callbacks_spec.rb
238
- - spec/integration/an_organizer_with_after_each_callbacks_spec.rb
228
+ - spec/spec_helper.rb
229
+ - spec/support/helpers/factories.rb
230
+ - spec/support/spec_helpers.rb
231
+ - spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb
232
+ - spec/support/shared_examples/a_class_with_interactor_methods_example.rb
233
+ - spec/support/shared_examples/a_class_that_extends_active_interactor_models_example.rb
234
+ - spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb
235
+ - spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb
236
+ - spec/active_interactor/interactor/perform/options_spec.rb
237
+ - spec/active_interactor/interactor/worker_spec.rb
238
+ - spec/active_interactor/error_spec.rb
239
+ - spec/active_interactor/config_spec.rb
240
+ - spec/active_interactor/organizer/interactor_interface_collection_spec.rb
241
+ - spec/active_interactor/organizer/interactor_interface_spec.rb
242
+ - spec/active_interactor/organizer/base_spec.rb
243
+ - spec/active_interactor/base_spec.rb
244
+ - spec/active_interactor/context/base_spec.rb
239
245
  - spec/integration/an_organizer_performing_in_parallel_spec.rb
240
- - spec/integration/an_interactor_with_an_existing_context_class_spec.rb
241
- - spec/integration/an_interactor_with_after_rollback_callbacks_spec.rb
242
- - spec/integration/an_interactor_with_validations_spec.rb
243
246
  - spec/integration/a_basic_interactor_spec.rb
244
- - spec/integration/an_interactor_with_validations_on_calling_spec.rb
247
+ - spec/integration/an_interactor_with_an_existing_context_class_spec.rb
248
+ - spec/integration/a_failing_interactor_spec.rb
245
249
  - spec/integration/an_interactor_with_before_perform_callbacks_spec.rb
246
- - spec/integration/an_organizer_with_before_each_callbacks_spec.rb
247
250
  - spec/integration/an_organizer_with_conditionally_organized_interactors_spec.rb
251
+ - spec/integration/an_interactor_with_validations_spec.rb
252
+ - spec/integration/an_organizer_with_before_each_callbacks_spec.rb
253
+ - spec/integration/an_interactor_with_after_rollback_callbacks_spec.rb
248
254
  - spec/integration/an_organizer_with_around_each_callbacks_spec.rb
249
- - spec/integration/an_interactor_with_after_context_validation_callbacks_spec.rb
255
+ - spec/integration/an_interactor_with_before_rollback_callbacks_spec.rb
256
+ - spec/integration/an_interactor_with_validations_on_calling_spec.rb
257
+ - spec/integration/an_organizer_with_after_each_callbacks_spec.rb
258
+ - spec/integration/a_basic_organizer_spec.rb
250
259
  - spec/integration/an_interactor_with_after_perform_callbacks_spec.rb
251
- - spec/support/spec_helpers.rb
252
- - spec/support/coverage/reporters.rb
253
- - spec/support/coverage/reporters/codacy.rb
254
- - spec/support/coverage/reporters/simple_cov.rb
255
- - spec/support/coverage/runner.rb
256
- - spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb
257
- - spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb
258
- - spec/support/shared_examples/a_class_with_interactor_methods_example.rb
259
- - spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb
260
- - spec/support/helpers/factories.rb
261
- - spec/support/coverage.rb
262
- - spec/spec_helper.rb
263
- - spec/active_interactor/context/base_spec.rb
264
- - spec/active_interactor/base_spec.rb
265
- - spec/active_interactor/config_spec.rb
266
- - spec/active_interactor/organizer/base_spec.rb
267
- - spec/active_interactor/organizer/interactor_interface_spec.rb
268
- - spec/active_interactor/organizer/interactor_interface_collection_spec.rb
269
- - spec/active_interactor/interactor/worker_spec.rb
270
- - spec/active_interactor/interactor/perform/options_spec.rb
271
- - spec/active_interactor/error_spec.rb
260
+ - spec/integration/an_interactor_with_around_rollback_callbacks_spec.rb
261
+ - spec/integration/an_interactor_with_around_perform_callbacks_spec.rb
262
+ - spec/integration/an_interactor_with_validations_on_called_spec.rb
263
+ - spec/integration/an_interactor_with_after_context_validation_callbacks_spec.rb
264
+ - spec/integration/active_record_integration_spec.rb
265
+ - spec/active_interactor_spec.rb
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'coverage/reporters'
4
- require_relative 'coverage/runner'
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spec
4
- module Coverage
5
- module Reporters
6
- EMPTY_LOAD_RESULT = [{}, [], []].freeze
7
- end
8
- end
9
- end
10
-
11
- Dir[File.expand_path('reporters/*.rb', __dir__)].sort.each { |file| require file }
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spec
4
- module Coverage
5
- module Reporters
6
- module Codacy
7
- class << self
8
- def load
9
- return EMPTY_LOAD_RESULT unless load_dependencies
10
-
11
- [formatters, initialize_steps, run_steps]
12
- end
13
-
14
- private
15
-
16
- def load_dependencies
17
- require 'codacy-coverage'
18
- true
19
- rescue LoadError
20
- puts 'Skipping Codacy Coverage reporting...'
21
- false
22
- end
23
-
24
- def formatters
25
- { codacy: ::Codacy::Formatter }
26
- end
27
-
28
- def initialize_steps
29
- []
30
- end
31
-
32
- def run_steps
33
- []
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spec
4
- module Coverage
5
- module Reporters
6
- module SimpleCov
7
- class << self
8
- def load
9
- return EMPTY_LOAD_RESULT unless load_dependencies
10
-
11
- [formatters, initialize_steps, run_steps]
12
- end
13
-
14
- private
15
-
16
- def load_dependencies
17
- require 'simplecov'
18
- true
19
- rescue LoadError
20
- puts 'Skipping SimpleCov reporting...'
21
- false
22
- end
23
-
24
- def formatters
25
- { simple_cov_html: ::SimpleCov::Formatter::HTMLFormatter }
26
- end
27
-
28
- def initialize_steps
29
- [setup_formatters]
30
- end
31
-
32
- def run_steps
33
- [start_simplecov]
34
- end
35
-
36
- def setup_formatters
37
- lambda do |runner|
38
- ::SimpleCov.formatter = ::SimpleCov::Formatter::MultiFormatter.new(runner.formatters)
39
- end
40
- end
41
-
42
- def start_simplecov
43
- lambda do |runner|
44
- ::SimpleCov.start do
45
- runner.tracked_files.each { |f| track_files f }
46
- runner.filtered_files.each { |f| add_filter f }
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Spec
4
- module Coverage
5
- class Runner
6
- attr_accessor :filtered_files, :formatters, :tracked_files
7
-
8
- def self.start(&block)
9
- instance = new
10
- instance.instance_eval(&block) if block
11
- instance.start
12
- end
13
-
14
- def initialize(options = {})
15
- load_reporters!
16
- @formatters = options[:formatters] || []
17
- @filtered_files = options[:filtered_files] || []
18
- @tracked_files = options[:tracked_files] || []
19
- end
20
-
21
- def add_formatter(formatter)
22
- formatter_class = reporters[:formatters][formatter.to_sym]
23
- formatters << formatter_class if formatter_class
24
- self
25
- end
26
-
27
- def filter(pattern)
28
- filtered_files << pattern
29
- self
30
- end
31
-
32
- def start
33
- initialize_reporters
34
- run_reporters
35
- end
36
-
37
- def track(pattern)
38
- tracked_files << pattern
39
- self
40
- end
41
-
42
- private
43
-
44
- attr_reader :reporters
45
-
46
- def initialize_reporters
47
- reporters[:initialize_steps].each { |step| step.call(self) }
48
- end
49
-
50
- def load_reporters!
51
- @reporters = { formatters: {}, initialize_steps: [], run_steps: [] }
52
- %w[SimpleCov Codacy].each do |dep|
53
- reporter = Reporters.const_get(dep)
54
- formatters, initialize_steps, run_steps = reporter.load
55
- @reporters[:formatters].merge!(formatters)
56
- @reporters[:initialize_steps].concat(initialize_steps)
57
- @reporters[:run_steps].concat(run_steps)
58
- end
59
- end
60
-
61
- def run_reporters
62
- reporters[:run_steps].each { |step| step.call(self) }
63
- end
64
- end
65
- end
66
- end