activeinteractor 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df118b852db85867fab87a6582604a59c89fd0a194843e569c663cb09b969abc
4
- data.tar.gz: 281f4e6672238ccfac070bd0c17f6831f76b455c26444a49945388b85738153c
3
+ metadata.gz: 91b9f4936670919fb0f3f1bda4f9320a3abd439adef16b7bae4d8cf14d3fb6da
4
+ data.tar.gz: 725547555164c173ab870afafb3f8ee43b6e355c3fcab3732b5a457d66e4f468
5
5
  SHA512:
6
- metadata.gz: 19822562f299f87b863686d0449e4c66b31096696f9f73c47e2c226a62413cdd8a379150a9e5d35a7d3f5e35433300b787965111a0bf0f9a0e29bcf4628afa04
7
- data.tar.gz: dee8cdf2ad05de200a09549fd3ad4f2c904e34da01374230d69a6a040d2ea9c0542e76cae81a80b0bbd259f81c413784934e21e8069dbfda1b16a1acc1247056
6
+ metadata.gz: bfd019dc0f1b7c86a7de23cca6c663b8be68c6ed5d1e4bb11aa6a09101e72537dab5f06f985b1ee38b5f3cd4b763615473031525227d75f14e70bfa48a33f0f2
7
+ data.tar.gz: 3c1e0a9d3340ec4362de5232fad83172537819b034fc891b5a1ac74f83f079c0ef03a9f2e6eace44125d1546a315ab4818c8989a4c3c931c050480ee1e82e65e
data/CHANGELOG.md CHANGED
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning].
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [v1.0.1] - 2020-01-28
11
+
12
+ ### Added
13
+
14
+ - `ActiveInteractor::Context::Attributes#attribute?`
15
+ - `ActiveInteractor::Context::Attributes#has_attribute?`
16
+ - `ActiveInteractor::Context::Base.attribute`
17
+ - `ActiveInteractor::Context::Base.attribute_missing`
18
+ - `ActiveInteractor::Context::Base.attribute_names`
19
+ - `ActiveInteractor::Context::Base.method_missing`
20
+ - `ActiveInteractor::Context::Base.respond_to?`
21
+ - `ActiveInteractor::Context::Base.respond_to_without_attributes?`
22
+ - `ActiveInteractor::Context::Base#attribute_missing`
23
+ - `ActiveInteractor::Context::Base#attribute_names`
24
+ - `ActiveInteractor::Context::Base#method_missing`
25
+ - `ActiveInteractor::Context::Base#respond_to?`
26
+ - `ActiveInteractor::Context::Base#respond_to_without_attributes?`
27
+ - `ActiveInteractor::Interactor::Context#context_attribute_missing`
28
+ - `ActiveInteractor::Interactor::Context#context_attribute_names`
29
+ - `ActiveInteractor::Interactor::Context#context_respond_to_without_attributes?`
30
+ - `ActiveInteractor::Interactor::Context::ClassMethods#context_attribute`
31
+ - `ActiveInteractor::Interactor::Context::ClassMethods#context_attribute_missing`
32
+ - `ActiveInteractor::Interactor::Context::ClassMethods#context_attribute_names`
33
+ - `ActiveInteractor::Interactor::Context::ClassMethods#context_respond_to_without_attributes?`
34
+
10
35
  ## [v1.0.0] - 2020-01-26
11
36
 
12
37
  ### Added
@@ -134,7 +159,8 @@ and this project adheres to [Semantic Versioning].
134
159
 
135
160
  <!-- versions -->
136
161
 
137
- [Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0...HEAD
162
+ [Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.1...HEAD
163
+ [v1.0.1]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0...v1.0.1
138
164
  [v1.0.0]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.7...v1.0.0
139
165
  [v0.1.7]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.6...v0.1.7
140
166
  [v0.1.6]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.5...v0.1.6
data/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  [![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
9
  [![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)
10
10
 
11
- An implementation of the [command pattern] for Ruby with [ActiveModel::Validations] based on the
11
+ An implementation of the [command pattern] for Ruby with [ActiveModel::Validations] inspired by the
12
12
  [interactor][collective_idea_interactors] gem. Rich support for attributes, callbacks, and validations,
13
13
  and thread safe performance methods.
14
14
 
@@ -17,7 +17,7 @@ and thread safe performance methods.
17
17
  Add this line to your application's Gemfile:
18
18
 
19
19
  ```ruby
20
- gem 'activeinteractor'
20
+ gem 'activeinteractor', require: 'active_interactor'
21
21
  ```
22
22
 
23
23
  And then execute:
@@ -22,7 +22,10 @@ require 'active_interactor/version'
22
22
  # {Base interactor} needs to do its work. When an {Base interactor} does its single purpose, it affects its given
23
23
  # {Context::Base context}.
24
24
  #
25
- # @see https://github.com/aaronmallen/activeinteractor/wiki Usage
25
+ # @see https://medium.com/@aaronmallen/activeinteractor-8557c0dc78db Basic Usage
26
+ # @see https://github.com/aaronmallen/activeinteractor/wiki Advanced Usage
27
+ # @see https://github.com/aaronmallen/activeinteractor Source Code
28
+ # @see https://github.com/aaronmallen/activeinteractor/issues Issues
26
29
  #
27
30
  # ## License
28
31
  #
@@ -25,18 +25,24 @@ module ActiveInteractor
25
25
  # MyContext.attributes
26
26
  # #=> [:first_name, :last_name]
27
27
  #
28
+ # @example Set defaults for attributes on a {Base context} class
29
+ # class MyContext < ActiveInteractor::Context::Base
30
+ # attributes first_name: { default: -> { 'Aaron' } }, last_name: { default: -> { 'Allen' } }
31
+ # end
32
+ #
28
33
  # @return [Array<Symbol>] the defined attributes
29
34
  def attributes(*attributes)
30
- return __attributes if attributes.empty?
35
+ attributes.compact.uniq.each { |attr| attribute(attr) }
31
36
 
32
- @__attributes = __attributes.concat(attributes.map(&:to_sym)).compact.uniq.sort
37
+ attribute_names.sort.collect(&:to_sym)
33
38
  end
34
39
 
35
40
  private
36
41
 
37
- def __attributes
38
- @__attributes ||= []
42
+ def attribute?(attr_name)
43
+ attribute_types.key?(attr_name.to_s)
39
44
  end
45
+ alias has_attribute? attribute?
40
46
  end
41
47
 
42
48
  # Initialize a new instance of {Base}
@@ -48,6 +54,8 @@ module ActiveInteractor
48
54
  copy_flags!(context)
49
55
  copy_called!(context)
50
56
  super
57
+
58
+ merge_attribute_values(context)
51
59
  end
52
60
 
53
61
  # Get values defined on the instance of {Base context} whose keys are defined on the {Base context} class'
@@ -69,10 +77,19 @@ module ActiveInteractor
69
77
  #
70
78
  # @return [Hash{Symbol => *}] the defined attributes and values
71
79
  def attributes
72
- self.class.attributes.each_with_object({}) do |attribute, hash|
73
- hash[attribute] = self[attribute] if self[attribute]
74
- end
80
+ super.symbolize_keys
81
+ end
82
+
83
+ # Check if the {Base context} instance has an attribute
84
+ #
85
+ # @since 1.0.1
86
+ #
87
+ # @param attr_name [Symbol, String] the name of the attribute to check
88
+ # @return [Boolean] whether or not the {Base context} instance has the attribute
89
+ def attribute?(attr_name)
90
+ @attributes.key?(attr_name.to_s)
75
91
  end
92
+ alias has_attribute? attribute?
76
93
 
77
94
  # Merge an instance of {Base context} into the calling {Base context} instance
78
95
  #
@@ -90,13 +107,21 @@ module ActiveInteractor
90
107
  merge_errors!(context.errors) if context.respond_to?(:errors)
91
108
  copy_flags!(context)
92
109
  context.each_pair do |key, value|
93
- self[key] = value unless value.nil?
110
+ public_send("#{key}=", value) unless value.nil?
94
111
  end
95
112
  self
96
113
  end
97
114
 
98
115
  private
99
116
 
117
+ def merge_attribute_values(context)
118
+ return unless context
119
+
120
+ context.each_pair do |key, value|
121
+ public_send("#{key}=", value)
122
+ end
123
+ end
124
+
100
125
  def merge_errors!(errors)
101
126
  if errors.is_a? String
102
127
  self.errors.add(:context, errors)
@@ -7,6 +7,26 @@ module ActiveInteractor
7
7
  # @author Aaron Allen <hello@aaronmallen.me>
8
8
  # @since 0.1.0
9
9
  #
10
+ # @!method attribute(name, type=Type::Value.new, **options)
11
+ # @!scope class
12
+ # @since 1.0.1
13
+ #
14
+ # @example Setting default values on the {Base context} class
15
+ # class MyContext < ActiveInteractor::Context::Base
16
+ # attribute :first_name, default: -> { 'Aaron' }
17
+ # end
18
+ #
19
+ # MyContext.new
20
+ # #=> <#MyContext first_name='Aaron'>
21
+ #
22
+ # MyContext.new(first_name: 'Bob')
23
+ # #=> <#MyContext first_name='Bob'>
24
+ #
25
+ # @see
26
+ # https://api.rubyonrails.org/classes/ActiveModel/Attributes/ClassMethods.html#method-i-attribute
27
+ # ActiveModel::Attributes::ClassMethods#attribute
28
+ #
29
+ #
10
30
  # @!method attribute_method?(attribute)
11
31
  # @!scope class
12
32
  # @since 0.1.0
@@ -14,6 +34,20 @@ module ActiveInteractor
14
34
  # https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-attribute_method-3F
15
35
  # ActiveModel::Validations::ClassMethods#attribute_method?
16
36
  #
37
+ # @!method attribute_missing(match, *args, &block)
38
+ # @!scope class
39
+ # @since 1.0.1
40
+ # @see
41
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-attribute_missing
42
+ # ActiveModel::AttributeMethods#attribute_missing
43
+ #
44
+ # @!method attribute_names
45
+ # @!scope class
46
+ # @since 1.0.1
47
+ # @see
48
+ # https://api.rubyonrails.org/classes/ActiveModel/Attributes/ClassMethods.html#method-i-attribute_names
49
+ # ActiveModel::Attributes::ClassMethods#attribute_names
50
+ #
17
51
  # @!method clear_validators!(attribute)
18
52
  # @!scope class
19
53
  # @since 0.1.0
@@ -21,6 +55,27 @@ module ActiveInteractor
21
55
  # https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-clear_validators-21
22
56
  # ActiveModel::Validations::ClassMethods#clear_validators!
23
57
  #
58
+ # @!method method_missing(method, *args, &block)
59
+ # @scope class
60
+ # @since 1.0.1
61
+ # @see
62
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-method_missing
63
+ # ActiveModel::AttributeMethods#method_missing
64
+ #
65
+ # @!method respond_to?(method, include_private_methods = false)
66
+ # @scope class
67
+ # @since 1.0.1
68
+ # @see
69
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-respond_to-3F
70
+ # ActiveModel::AttributeMethods#respond_to?
71
+ #
72
+ # @!method respond_to_without_attributes?(method, include_private_methods = false)
73
+ # @scope class
74
+ # @since 1.0.1
75
+ # @see
76
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-respond_to_without_attributes-3F
77
+ # ActiveModel::AttributeMethods#respond_to_without_attributes?
78
+ #
24
79
  # @!method validate(*args, &block)
25
80
  # @!scope class
26
81
  # @since 0.1.0
@@ -140,6 +195,18 @@ module ActiveInteractor
140
195
  # https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validators_on
141
196
  # ActiveModel::Validations::ClassMethods#validators_on
142
197
  #
198
+ # @!method attribute_missing(match, *args, &block)
199
+ # @since 1.0.1
200
+ # @see
201
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-attribute_missing
202
+ # ActiveModel::AttributeMethods#attribute_missing
203
+ #
204
+ # @!method attribute_names
205
+ # @since 1.0.1
206
+ # @see
207
+ # https://api.rubyonrails.org/classes/ActiveModel/Attributes/ClassMethods.html#method-i-attribute_names
208
+ # ActiveModel::Attributes::ClassMethods#attribute_names
209
+ #
143
210
  # @!method errors
144
211
  # @since 0.1.0
145
212
  # @see
@@ -152,6 +219,24 @@ module ActiveInteractor
152
219
  # https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-invalid-3F
153
220
  # ActiveModel::Validations#invalid?
154
221
  #
222
+ # @!method method_missing(method, *args, &block)
223
+ # @since 1.0.1
224
+ # @see
225
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-method_missing
226
+ # ActiveModel::AttributeMethods#method_missing
227
+ #
228
+ # @!method respond_to?(method, include_private_methods = false)
229
+ # @since 1.0.1
230
+ # @see
231
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-respond_to-3F
232
+ # ActiveModel::AttributeMethods#respond_to?
233
+ #
234
+ # @!method respond_to_without_attributes?(method, include_private_methods = false)
235
+ # @since 1.0.1
236
+ # @see
237
+ # https://api.rubyonrails.org/classes/ActiveModel/AttributeMethods.html#method-i-respond_to_without_attributes-3F
238
+ # ActiveModel::AttributeMethods#respond_to_without_attributes?
239
+ #
155
240
  # @!method valid?(context = nil)
156
241
  # @since 0.1.0
157
242
  # @see
@@ -238,6 +323,7 @@ module ActiveInteractor
238
323
  class Base < OpenStruct
239
324
  extend ActiveInteractor::Context::Attributes::ClassMethods
240
325
 
326
+ include ActiveModel::Attributes
241
327
  include ActiveModel::Validations
242
328
  include ActiveInteractor::Context::Attributes
243
329
  include ActiveInteractor::Context::Status
@@ -27,7 +27,43 @@ module ActiveInteractor
27
27
  #
28
28
  # MyInteractor.context_class.attributes
29
29
  # #=> [:first_name, :last_name]
30
- delegate :attributes, to: :context_class, prefix: :context
30
+ #
31
+ # @!method context_attribute_missing(match, *args, &block)
32
+ # Call {ActiveInteractor::Context::Base.attribute_missing .attribute_missing} on the {Base interactor} class'
33
+ # {#context_class context class}
34
+ #
35
+ # @since 1.0.1
36
+ #
37
+ # @!method context_respond_to_without_attributes?(method, include_private_methods = false)
38
+ # Call {ActiveInteractor::Context::Base.respond_to_without_attributes? .respond_to_without_attributes?} on the
39
+ # {Base interactor} class' {#context_class context class}
40
+ #
41
+ # @since 1.0.1
42
+ delegate :attributes, :attribute_missing, :respond_to_without_attributes?, to: :context_class, prefix: :context
43
+
44
+ # @!method context_attribute(name, type=Type::Value.new, **options)
45
+ # Call {ActiveInteractor::Context::Base.attribute .attribute} on the {Base interactor} class'
46
+ # {#context_class context class}
47
+ #
48
+ # @since 1.0.1
49
+ #
50
+ # @example Setting default values on the {ActiveInteractor::Context::Base context} class
51
+ # class MyInteractor < ActiveInteractor::Base
52
+ # context_attribute :first_name, default: -> { 'Aaron' }
53
+ # end
54
+ #
55
+ # MyInteractor.perform
56
+ # #=> <#MyInteractor::Context first_name='Aaron'>
57
+ #
58
+ # MyInteractor.perform(first_name: 'Bob')
59
+ # #=> <#MyInteractor::Context first_name='Bob'>
60
+ #
61
+ # @!method context_attribute_names
62
+ # Call {ActiveInteractor::Context::Base.attribute_names .attribute_names} on the {Base interactor} class'
63
+ # {#context_class context class}
64
+ #
65
+ # @since 1.0.1
66
+ delegate(*ActiveModel::Attributes::ClassMethods.instance_methods, to: :context_class, prefix: :context)
31
67
 
32
68
  # @!method context_attribute_method?(attribute)
33
69
  # Call {ActiveInteractor::Context::Base.attribute_method? .attribute_method?} on the {Base interactor} class'
@@ -183,18 +219,37 @@ module ActiveInteractor
183
219
  end
184
220
  end
185
221
 
222
+ # @!method context_attribute_missing(match, *args, &block)
223
+ # Call {ActiveInteractor::Context::Base#attribute_missing #attribute_missing} on the {Base interactor} instance's
224
+ # {ActiveInteractor::Context::Base context} instance
225
+ #
226
+ # @since 1.0.1
227
+ #
228
+ # @!method context_attribute_names
229
+ # Call {ActiveInteractor::Context::Base#attribute_names #attribute_names} on the {Base interactor} instance's
230
+ # {ActiveInteractor::Context::Base context} instance
231
+ #
232
+ # @since 1.0.1
233
+ #
186
234
  # @!method context_fail!(errors = nil)
187
235
  # Call {ActiveInteractor::Context::Status#fail! #fail!} on the {Base interactor} instance's
188
236
  # {ActiveInteractor::Context::Base context} instance
189
237
  #
190
238
  # @since 1.0.0
191
239
  #
240
+ # @!method context_respond_to_without_attributes?(method, include_private_methods = false)
241
+ # Call {ActiveInteractor::Context::Base#respond_to_without_attributes? #respond_to_without_attributes?} on the
242
+ # {Base interactor} instance's {ActiveInteractor::Context::Base context} instance
243
+ #
244
+ # @since 1.0.1
245
+ #
192
246
  # @!method context_rollback!
193
247
  # Call {ActiveInteractor::Context::Status#rollback! #rollback!} on the {Base interactor} instance's
194
248
  # {ActiveInteractor::Context::Base context} instance
195
249
  #
196
250
  # @since 1.0.0
197
- delegate :fail!, :rollback!, to: :context, prefix: true
251
+ delegate :attribute_missing, :attribute_names, :fail!, :respond_to_without_attributes?, :rollback!,
252
+ to: :context, prefix: true
198
253
 
199
254
  # @!method context_errors
200
255
  # Call {ActiveInteractor::Context::Base#errors #errors} on the {Base interactor} instance's
@@ -3,5 +3,5 @@
3
3
  module ActiveInteractor
4
4
  # The ActiveInteractor version
5
5
  # @return [String] the ActiveInteractor version
6
- VERSION = '1.0.0'
6
+ VERSION = '1.0.1'
7
7
  end
@@ -3,34 +3,70 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe ActiveInteractor::Context::Base do
6
- after(:each) { described_class.instance_variable_set('@__attributes', []) }
7
-
8
- describe '#attributes' do
6
+ describe '.attributes' do
9
7
  context 'when no arguments are passed' do
10
- subject { described_class.attributes }
8
+ subject { context_class.attributes }
9
+ let!(:context_class) { build_context }
11
10
  it { is_expected.to eq [] }
12
11
 
13
12
  context 'when an attribute :foo was previously defined' do
14
- before { described_class.instance_variable_set('@__attributes', %i[foo]) }
13
+ let!(:context_class) do
14
+ build_context do
15
+ attributes :foo
16
+ end
17
+ end
15
18
 
16
19
  it { is_expected.to eq %i[foo] }
17
20
  end
18
21
  end
19
22
 
20
23
  context 'when given arguments :foo and :bar' do
21
- subject { described_class.attributes(:foo, :bar) }
24
+ subject { context_class.attributes(:foo, :bar) }
25
+ let!(:context_class) { build_context }
22
26
 
23
27
  it { is_expected.to eq %i[bar foo] }
24
28
 
25
29
  context 'when an attribute :foo was previously defined' do
26
- before { described_class.instance_variable_set('@__attributes', %i[foo]) }
30
+ before { TestContext.attributes(:foo) }
27
31
 
28
32
  it { is_expected.to eq %i[bar foo] }
29
33
  end
30
34
  end
31
35
  end
32
36
 
33
- describe '.attributes' do
37
+ describe '#attribute?' do
38
+ subject { instance.attribute?(attribute) }
39
+
40
+ context 'with class attributes []' do
41
+ let(:instance) { build_context.new }
42
+ let(:attribute) { :foo }
43
+
44
+ it { is_expected.to eq false }
45
+ end
46
+
47
+ context 'with class attributes [:foo]' do
48
+ let!(:context_class) do
49
+ build_context do
50
+ attributes :foo
51
+ end
52
+ end
53
+ let(:instance) { context_class.new }
54
+
55
+ context 'checking attribute :foo' do
56
+ let(:attribute) { :foo }
57
+
58
+ it { is_expected.to eq true }
59
+ end
60
+
61
+ context 'checking attribute :bar' do
62
+ let(:attribute) { :bar }
63
+
64
+ it { is_expected.to eq false }
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '#attributes' do
34
70
  subject { instance.attributes }
35
71
 
36
72
  context 'with class attributes []' do
@@ -43,13 +79,23 @@ RSpec.describe ActiveInteractor::Context::Base do
43
79
  end
44
80
 
45
81
  context 'with class attributes [:foo, :bar, :baz]' do
46
- before { described_class.attributes(:foo, :bar, :baz) }
82
+ before { build_context.attributes(:foo, :bar) }
83
+
84
+ context 'with an instance having attributes { :foo => "foo", :bar => "bar" }' do
85
+ let(:instance) { TestContext.new(foo: 'foo', bar: 'bar') }
86
+
87
+ it { is_expected.to be_a Hash }
88
+ it { is_expected.to eq(bar: 'bar', foo: 'foo') }
89
+ end
47
90
 
48
91
  context 'with an instance having attributes { :foo => "foo", :bar => "bar", :baz => "baz" }' do
49
- let(:instance) { described_class.new(foo: 'foo', bar: 'bar', baz: 'baz') }
92
+ let(:instance) { TestContext.new(foo: 'foo', bar: 'bar', baz: 'baz') }
50
93
 
51
94
  it { is_expected.to be_a Hash }
52
- it { is_expected.to eq(bar: 'bar', baz: 'baz', foo: 'foo') }
95
+ it { is_expected.to eq(bar: 'bar', foo: 'foo') }
96
+ it 'is expected to assign :baz' do
97
+ expect(instance.baz).to eq 'baz'
98
+ end
53
99
  end
54
100
  end
55
101
  end
@@ -103,4 +103,52 @@ RSpec.describe 'A basic interactor', type: :integration do
103
103
  end
104
104
  end
105
105
  end
106
+
107
+ context 'having default context attributes {:foo => "foo"}' do
108
+ let(:interactor_class) do
109
+ build_interactor do
110
+ context_attribute :foo, default: -> { 'foo' }
111
+ end
112
+ end
113
+
114
+ describe '.perform' do
115
+ subject { interactor_class.perform(context_attributes) }
116
+
117
+ context 'when no context is passed' do
118
+ let(:context_attributes) { {} }
119
+
120
+ it { is_expected.to have_attributes(foo: 'foo') }
121
+ end
122
+
123
+ context 'when context {:foo => "bar"} is passed' do
124
+ let(:context_attributes) { { foo: 'bar' } }
125
+
126
+ it { is_expected.to have_attributes(foo: 'bar') }
127
+ end
128
+ end
129
+ end
130
+
131
+ context 'having default context attributes {:foo => "foo", :bar => "bar"} using the #context_attributes method' do
132
+ let(:interactor_class) do
133
+ build_interactor do
134
+ context_attributes foo: { default: -> { 'foo' } }, bar: { default: -> { 'bar' } }
135
+ end
136
+
137
+ describe '.perform' do
138
+ subject { interactor_class.perform(context_attributes) }
139
+
140
+ context 'when no context is passed' do
141
+ let(:context_attributes) { {} }
142
+
143
+ it { is_expected.to have_attributes(foo: 'foo', bar: 'bar') }
144
+ end
145
+
146
+ context 'when context {:foo => "bar"} is passed' do
147
+ let(:context_attributes) { { foo: 'bar' } }
148
+
149
+ it { is_expected.to have_attributes(foo: 'bar', bar: 'bar') }
150
+ end
151
+ end
152
+ end
153
+ end
106
154
  end
@@ -94,4 +94,83 @@ RSpec.describe 'A basic organizer', type: :integration do
94
94
  end
95
95
  end
96
96
  end
97
+
98
+ # https://github.com/aaronmallen/activeinteractor/issues/151
99
+ context 'with an interactor class having a predefined context class with attributes [:foo]' do
100
+ let!(:test_context_class) do
101
+ build_context('TestInteractor1Context') do
102
+ attributes :foo
103
+ end
104
+ end
105
+
106
+ # rubocop:disable Metrics/AbcSize
107
+ let!(:test_interactor_1) do
108
+ build_interactor('TestInteractor1') do
109
+ def perform
110
+ context.has_foo_as_method = context.foo.present?
111
+ context.has_foo_as_element = context[:foo].present?
112
+ context.has_bar_as_method = context.bar.present?
113
+ context.has_bar_as_element = context[:bar].present?
114
+ end
115
+ end
116
+ end
117
+ # rubocop:enable Metrics/AbcSize
118
+
119
+ let(:interactor_class) do
120
+ build_organizer do
121
+ organize :test_interactor_1
122
+ end
123
+ end
124
+
125
+ context 'when passing a context argument { :foo => "foo", :bar => "bar" }' do
126
+ let(:context_attributes) { { foo: 'foo', bar: 'bar' } }
127
+
128
+ describe '.perform' do
129
+ subject(:result) { interactor_class.perform(context_attributes) }
130
+ it { is_expected.to have_attributes(foo: 'foo', bar: 'bar') }
131
+
132
+ it 'is expected to copy all attributes in the contexts to each interactor' do
133
+ expect(subject.has_foo_as_method).to be true
134
+ expect(subject.has_foo_as_element).to be true
135
+ expect(subject.has_bar_as_method).to be true
136
+ expect(subject.has_bar_as_element).to be true
137
+ end
138
+
139
+ describe '#attributes' do
140
+ subject { result.attributes }
141
+
142
+ it { is_expected.to be_a Hash }
143
+ it { is_expected.to be_empty }
144
+ end
145
+ end
146
+
147
+ context 'with attributes [:foo] on the organizer context class' do
148
+ let!(:interactor_class) do
149
+ build_organizer do
150
+ context_attributes :foo
151
+ organize :test_interactor_1
152
+ end
153
+ end
154
+
155
+ describe '.perform' do
156
+ subject(:result) { interactor_class.perform(context_attributes) }
157
+ it { is_expected.to have_attributes(foo: 'foo', bar: 'bar') }
158
+
159
+ it 'is expected to copy all attributes in the contexts to each interactor' do
160
+ expect(subject.has_foo_as_method).to be true
161
+ expect(subject.has_foo_as_element).to be true
162
+ expect(subject.has_bar_as_method).to be true
163
+ expect(subject.has_bar_as_element).to be true
164
+ end
165
+
166
+ describe '#attributes' do
167
+ subject { result.attributes }
168
+
169
+ it { is_expected.to be_a Hash }
170
+ it { is_expected.to eq(foo: 'foo') }
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
97
176
  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.0
4
+ version: 1.0.1
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-26 00:00:00.000000000 Z
11
+ date: 2020-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -93,7 +93,7 @@ dependencies:
93
93
  - !ruby/object:Gem::Version
94
94
  version: '3.9'
95
95
  description: |
96
- An implementation of the Command Pattern for Ruby with ActiveModel::Validations based on the interactors gem.
96
+ An implementation of the Command Pattern for Ruby with ActiveModel::Validations inspired by the interactor gem.
97
97
  Rich support for attributes, callbacks, and validations, and thread safe performance methods.
98
98
  email:
99
99
  - hello@aaronmallen.me
@@ -202,10 +202,10 @@ licenses:
202
202
  - MIT
203
203
  metadata:
204
204
  bug_tracker_uri: https://github.com/aaronmallen/activeinteractor/issues
205
- changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v1.0.0/CHANGELOG.md
206
- documentation_uri: https://www.rubydoc.info/gems/activeinteractor/1.0.0
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
207
207
  hompage_uri: https://github.com/aaronmallen/activeinteractor
208
- source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.0.0
208
+ source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.0.1
209
209
  wiki_uri: https://github.com/aaronmallen/activeinteractor/wiki
210
210
  post_install_message:
211
211
  rdoc_options: []