activeinteractor 0.1.3 → 0.1.4
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 +22 -5
- data/README.md +41 -4
- data/lib/active_interactor/context.rb +4 -134
- data/lib/active_interactor/context/attributes.rb +194 -0
- data/lib/active_interactor/context/errors.rb +26 -0
- data/lib/active_interactor/interactor.rb +1 -1
- data/lib/active_interactor/interactor/context.rb +38 -1
- data/lib/active_interactor/version.rb +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f7136d8728ef016a9041ff462d8874af56028432ab839e8b7dab707b3ad1c59
|
4
|
+
data.tar.gz: 04f08a4985a45385885b165f26fb65a93f9952ea4d2c0849312d5ff63075770a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6148b98fb26e34891e81fa84243f21d4db8460be907f69bae1a082ebce941ae3112c031aaba03086bba52b729fe358833b3a5fcbabb7e5fad505f29114eca6c
|
7
|
+
data.tar.gz: daa7e71d54dfd86195e0487ef4f0da05df2cd3a47e4067e520a86876d87492dd04bcc406157214c55434404d82dfb5c4358adc24546e6f7e60998d6e2f562a9a
|
data/CHANGELOG.md
CHANGED
@@ -7,24 +7,30 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [v0.1.4] - 2019-04-12
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- [#28] The ability to alias attributes on interactor contexts.
|
15
|
+
|
10
16
|
## [v0.1.3] - 2019-04-01
|
11
17
|
|
12
18
|
### Added
|
13
19
|
|
14
|
-
- #25
|
20
|
+
- [#25] Implement `each_perform` callbacks on organizers
|
15
21
|
|
16
22
|
## [v0.1.2] - 2019-04-01
|
17
23
|
|
18
24
|
### Added
|
19
25
|
|
20
|
-
- #22
|
26
|
+
- [#22] Allow the directory interactors are generated in to be configurable
|
21
27
|
|
22
28
|
## [v0.1.1] - 2019-03-30
|
23
29
|
|
24
30
|
### Fixed
|
25
31
|
|
26
|
-
- #15
|
27
|
-
- #16
|
32
|
+
- [#15] `NameError` (uninitialized constant `ActiveInteractor::Organizer`)
|
33
|
+
- [#16] `NoMethodError` (undefined method `merge` for `ActiveInteractor::Context::Base`)
|
28
34
|
|
29
35
|
## v0.1.0 - 2019-03-30
|
30
36
|
|
@@ -33,7 +39,18 @@ and this project adheres to [Semantic Versioning].
|
|
33
39
|
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
|
34
40
|
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html
|
35
41
|
|
36
|
-
|
42
|
+
<!-- versions -->
|
43
|
+
|
44
|
+
[Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.4..HEAD
|
45
|
+
[v0.1.4]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.3...v0.1.4
|
37
46
|
[v0.1.3]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.2...v0.1.3
|
38
47
|
[v0.1.2]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.1...v0.1.2
|
39
48
|
[v0.1.1]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.0...v0.1.1
|
49
|
+
|
50
|
+
<!-- pull requests and issues -->
|
51
|
+
|
52
|
+
[#15]: https://github.com/aaronmallen/activeinteractor/pull/15
|
53
|
+
[#16]: https://github.com/aaronmallen/activeinteractor/pull/16
|
54
|
+
[#22]: https://github.com/aaronmallen/activeinteractor/pull/22
|
55
|
+
[#25]: https://github.com/aaronmallen/activeinteractor/pull/25
|
56
|
+
[#28]: https://github.com/aaronmallen/activeinteractor/pull/28
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
[](https://codeclimate.com/github/aaronmallen/activeinteractor/maintainability)
|
9
9
|
[](https://codeclimate.com/github/aaronmallen/activeinteractor/test_coverage)
|
10
10
|
|
11
|
-
Ruby interactors with [ActiveModel::Validations] based on the [
|
11
|
+
Ruby interactors with [ActiveModel::Validations] based on the [interactor][collective_idea_interactors] gem.
|
12
12
|
|
13
13
|
## Getting Started
|
14
14
|
|
@@ -178,6 +178,38 @@ context.clean! #=> { occupation: 'Software Dude' }
|
|
178
178
|
context.occupation #=> nil
|
179
179
|
```
|
180
180
|
|
181
|
+
#### Aliasing Attributes
|
182
|
+
|
183
|
+
Some times you may want to use the same interactor functionality with different
|
184
|
+
model types having different naming conventions for similar attributes. We can
|
185
|
+
inform the interactors context of these aliases with the `context_attribute_aliases`
|
186
|
+
method on our interactors.
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
class MyInteractor < ActiveInteractor::Base
|
190
|
+
context_attributes :first_name, :last_name
|
191
|
+
context_attribute_aliases last_name: :sir_name
|
192
|
+
end
|
193
|
+
|
194
|
+
context = MyInteractor.perform(first_name: 'Aaron', sir_name: 'Allen')
|
195
|
+
# => <#MyInteractor::Context first_name='Aaron', last_name='Allen'
|
196
|
+
```
|
197
|
+
|
198
|
+
We can also pass an array of aliases to the attribute like this:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
class MyInteractor < ActiveInteractor::Base
|
202
|
+
context_attributes :first_name, :last_name
|
203
|
+
context_attribute_aliases last_name: %i[sir_name sirname]
|
204
|
+
end
|
205
|
+
|
206
|
+
context = MyInteractor.perform(first_name: 'Aaron', sir_name: 'Allen')
|
207
|
+
# => <#MyInteractor::Context first_name='Aaron', last_name='Allen'
|
208
|
+
|
209
|
+
context = MyInteractor.perform(first_name: 'Aaron', sirname: 'Allen')
|
210
|
+
# => <#MyInteractor::Context first_name='Aaron', last_name='Allen'
|
211
|
+
```
|
212
|
+
|
181
213
|
#### Validating the Context
|
182
214
|
|
183
215
|
`ActiveInteractor` delegates all the validation methods provided by [ActiveModel::Validations]
|
@@ -460,7 +492,10 @@ context.rollback!
|
|
460
492
|
"Done"
|
461
493
|
```
|
462
494
|
|
463
|
-
|
495
|
+
#### Organizer Callbacks
|
496
|
+
|
497
|
+
We can do worker before `perform` is invoked on each interactor in an [Organizer](#organizers)
|
498
|
+
with the `before_each_perform` method:
|
464
499
|
|
465
500
|
```ruby
|
466
501
|
class MyInteractor1 < ActiveInteractor::Base
|
@@ -499,7 +534,8 @@ MyOrganizer.perform(name: 'Aaron')
|
|
499
534
|
#=> <MyOrganizer::Context name='Aaron'>
|
500
535
|
```
|
501
536
|
|
502
|
-
We can do worker around `perform` is invokation on each interactor in an [Organizer](#organizers)
|
537
|
+
We can do worker around `perform` is invokation on each interactor in an [Organizer](#organizers)
|
538
|
+
with the `around_each_perform` method:
|
503
539
|
|
504
540
|
```ruby
|
505
541
|
class MyInteractor1 < ActiveInteractor::Base
|
@@ -542,7 +578,8 @@ MyOrganizer.perform(name: 'Aaron')
|
|
542
578
|
#=> <MyOrganizer::Context name='Aaron'>
|
543
579
|
```
|
544
580
|
|
545
|
-
We can do worker after `perform` is invoked on each interactor in an [Organizer](#organizers)
|
581
|
+
We can do worker after `perform` is invoked on each interactor in an [Organizer](#organizers)
|
582
|
+
with the `after_each_perform` method:
|
546
583
|
|
547
584
|
```ruby
|
548
585
|
class MyInteractor1 < ActiveInteractor::Base
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_support/core_ext/class/attribute'
|
4
3
|
require 'ostruct'
|
5
4
|
|
5
|
+
Dir[File.expand_path('context/*.rb', __dir__)].each { |file| require file }
|
6
|
+
|
6
7
|
module ActiveInteractor
|
7
8
|
# ActiveInteractor::Context module
|
8
9
|
#
|
@@ -10,35 +11,14 @@ module ActiveInteractor
|
|
10
11
|
# @since 0.0.1
|
11
12
|
# @version 0.1
|
12
13
|
module Context
|
13
|
-
# Raised when an interactor context fails
|
14
|
-
#
|
15
|
-
# @author Aaron Allen <hello@aaronmallen.me>
|
16
|
-
# @since 0.0.1
|
17
|
-
# @version 0.1
|
18
|
-
#
|
19
|
-
# @!attribute [r] context
|
20
|
-
# @return [Base] an instance of {Base}
|
21
|
-
class Failure < StandardError
|
22
|
-
attr_reader :context
|
23
|
-
|
24
|
-
# A new instance of {Failure}
|
25
|
-
# @param context [Hash] an instance of {Base}
|
26
|
-
# @return [Failure] a new instance of {Failure}
|
27
|
-
def initialize(context = {})
|
28
|
-
@context = context
|
29
|
-
super
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
14
|
# The base context class inherited by all {Interactor::Context} classes
|
34
15
|
#
|
35
16
|
# @author Aaron Allen <hello@aaronmallen.me>
|
36
17
|
# @since 0.0.1
|
37
|
-
# @version 0.
|
18
|
+
# @version 0.2
|
38
19
|
class Base < OpenStruct
|
39
20
|
include ActiveModel::Validations
|
40
|
-
|
41
|
-
class_attribute :__default_attributes, instance_writer: false, default: []
|
21
|
+
include Attributes
|
42
22
|
|
43
23
|
# A new instance of {Base}
|
44
24
|
# @param interactor [ActiveInteractor::Base] an interactor instance
|
@@ -50,66 +30,6 @@ module ActiveInteractor
|
|
50
30
|
super(attributes)
|
51
31
|
end
|
52
32
|
|
53
|
-
class << self
|
54
|
-
# Attributes defined on the context class
|
55
|
-
#
|
56
|
-
# @example Get attributes defined on a context class
|
57
|
-
# MyInteractor::Context.attributes
|
58
|
-
# #=> [:first_name, :last_name]
|
59
|
-
#
|
60
|
-
# @return [Array<Symbol>] the defined attributes
|
61
|
-
def attributes
|
62
|
-
__default_attributes
|
63
|
-
.concat(_validate_callbacks.map(&:filter).map(&:attributes).flatten)
|
64
|
-
.flatten
|
65
|
-
.uniq
|
66
|
-
end
|
67
|
-
|
68
|
-
# Set attributes on a context class
|
69
|
-
# @param [Array<Symbol, String>] attributes
|
70
|
-
#
|
71
|
-
# @example Define attributes on a context class
|
72
|
-
# MyInteractor::Context.attributes = :first_name, :last_name
|
73
|
-
# #=> [:first_name, :last_name]
|
74
|
-
#
|
75
|
-
# @return [Array<Symbol>] the defined attributes
|
76
|
-
def attributes=(*attributes)
|
77
|
-
self.__default_attributes = self.attributes.concat(attributes.flatten.map(&:to_sym)).uniq
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Attributes defined on the instance
|
82
|
-
#
|
83
|
-
# @example Get attributes defined on an instance
|
84
|
-
# MyInteractor::Context.attributes = :first_name, :last_name
|
85
|
-
# #=> [:first_name, :last_name]
|
86
|
-
#
|
87
|
-
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen')
|
88
|
-
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen'>
|
89
|
-
#
|
90
|
-
# context.attributes
|
91
|
-
# #=> { first_name: 'Aaron', last_name: 'Allen' }
|
92
|
-
#
|
93
|
-
# @example Get attributes defined on an instance with unknown attribute
|
94
|
-
# MyInteractor::Context.attributes = :first_name, :last_name
|
95
|
-
# #=> [:first_name, :last_name]
|
96
|
-
#
|
97
|
-
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen', unknown: 'unknown')
|
98
|
-
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen', unknown='unknown'>
|
99
|
-
#
|
100
|
-
# context.attributes
|
101
|
-
# #=> { first_name: 'Aaron', last_name: 'Allen' }
|
102
|
-
#
|
103
|
-
# context.unknown
|
104
|
-
# #=> 'unknown'
|
105
|
-
#
|
106
|
-
# @return [Hash{Symbol => *}] the defined attributes and values
|
107
|
-
def attributes
|
108
|
-
self.class.attributes.each_with_object({}) do |attribute, hash|
|
109
|
-
hash[attribute] = self[attribute] if self[attribute]
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
33
|
# Track that an Interactor has been called. The {#called!} method
|
114
34
|
# is used by the interactor being invoked with this context. After an
|
115
35
|
# interactor is successfully called, the interactor instance is tracked in
|
@@ -120,37 +40,6 @@ module ActiveInteractor
|
|
120
40
|
_called << interactor
|
121
41
|
end
|
122
42
|
|
123
|
-
# Removes properties from the instance that are not
|
124
|
-
# explicitly defined in the context instance {#attributes}
|
125
|
-
#
|
126
|
-
# @example Clean an instance of Context with unknown attribute
|
127
|
-
# MyInteractor::Context.attributes = :first_name, :last_name
|
128
|
-
# #=> [:first_name, :last_name]
|
129
|
-
#
|
130
|
-
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen', unknown: 'unknown')
|
131
|
-
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen', unknown='unknown'>
|
132
|
-
#
|
133
|
-
# context.unknown
|
134
|
-
# #=> 'unknown'
|
135
|
-
#
|
136
|
-
# context.clean!
|
137
|
-
# #=> { unknown: 'unknown' }
|
138
|
-
#
|
139
|
-
# context.unknown
|
140
|
-
# #=> nil
|
141
|
-
#
|
142
|
-
# @return [Hash{Symbol => *}] the deleted attributes
|
143
|
-
def clean!
|
144
|
-
deleted = {}
|
145
|
-
return deleted if keys.empty?
|
146
|
-
|
147
|
-
keys.reject { |key| self.class.attributes.include?(key) }.each do |attribute|
|
148
|
-
deleted[attribute] = self[attribute] if self[attribute]
|
149
|
-
delete_field(key.to_s)
|
150
|
-
end
|
151
|
-
deleted
|
152
|
-
end
|
153
|
-
|
154
43
|
# Fail the context instance. Failing a context raises an error
|
155
44
|
# that may be rescued by the calling interactor. The context is also flagged
|
156
45
|
# as having failed
|
@@ -195,23 +84,6 @@ module ActiveInteractor
|
|
195
84
|
end
|
196
85
|
alias fail? failure?
|
197
86
|
|
198
|
-
# All keys of properties currently defined on the instance
|
199
|
-
#
|
200
|
-
# @example An instance of Context with unknown attribute
|
201
|
-
# MyInteractor::Context.attributes = :first_name, :last_name
|
202
|
-
# #=> [:first_name, :last_name]
|
203
|
-
#
|
204
|
-
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen', unknown: 'unknown')
|
205
|
-
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen', unknown='unknown'>
|
206
|
-
#
|
207
|
-
# context.keys
|
208
|
-
# #=> [:first_name, :last_name, :unknown]
|
209
|
-
#
|
210
|
-
# @return [Array<Symbol>] keys defined on the instance
|
211
|
-
def keys
|
212
|
-
each_pair.map { |pair| pair[0].to_sym }
|
213
|
-
end
|
214
|
-
|
215
87
|
# Attempt to call the interactor for missing validation callback methods
|
216
88
|
# @raise [NameError] if the method is not a validation callback or method
|
217
89
|
# does not exist on the interactor instance
|
@@ -295,6 +167,4 @@ module ActiveInteractor
|
|
295
167
|
end
|
296
168
|
end
|
297
169
|
end
|
298
|
-
|
299
|
-
Dir[File.expand_path('context/*.rb', __dir__)].each { |file| require file }
|
300
170
|
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
4
|
+
require 'active_support/core_ext/class/attribute'
|
5
|
+
|
6
|
+
module ActiveInteractor
|
7
|
+
# ActiveInteractor::Context module
|
8
|
+
#
|
9
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
10
|
+
# @since 0.0.1
|
11
|
+
# @version 0.1
|
12
|
+
module Context
|
13
|
+
# Provides Context Attribute methods to included classes
|
14
|
+
#
|
15
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
16
|
+
# @since 0.1.4
|
17
|
+
# @version 0.1
|
18
|
+
module Attributes
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
included do
|
22
|
+
extend ClassMethods
|
23
|
+
class_attribute :__default_attributes, instance_writer: false, default: []
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
# Attributes defined on the context class
|
28
|
+
#
|
29
|
+
# @example Get attributes defined on a context class
|
30
|
+
# MyInteractor::Context.attributes
|
31
|
+
# #=> [:first_name, :last_name]
|
32
|
+
#
|
33
|
+
# @return [Array<Symbol>] the defined attributes
|
34
|
+
def attributes
|
35
|
+
__default_attributes
|
36
|
+
.concat(_validate_callbacks.map(&:filter).map(&:attributes).flatten)
|
37
|
+
.flatten
|
38
|
+
.uniq
|
39
|
+
end
|
40
|
+
|
41
|
+
# Set attributes on a context class
|
42
|
+
#
|
43
|
+
# @param attributes [Array<Symbol, String>] the attributes of the context
|
44
|
+
#
|
45
|
+
# @example Define attributes on a context class
|
46
|
+
# MyInteractor::Context.attributes = :first_name, :last_name
|
47
|
+
# #=> [:first_name, :last_name]
|
48
|
+
#
|
49
|
+
# @return [Array<Symbol>] the defined attributes
|
50
|
+
def attributes=(*attributes)
|
51
|
+
self.__default_attributes = self.attributes.concat(attributes.flatten.map(&:to_sym)).uniq
|
52
|
+
end
|
53
|
+
|
54
|
+
# Attribute aliases defined on the context class
|
55
|
+
#
|
56
|
+
# @example Get attribute aliases defined on a context class
|
57
|
+
# MyInteractor::Context.attribute_aliases
|
58
|
+
# #=> { last_name: [:sir_name] }
|
59
|
+
#
|
60
|
+
# @return [Hash{Symbol => Array<Symbol>}]
|
61
|
+
def attribute_aliases
|
62
|
+
@attribute_aliases ||= {}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Set attribute aliases on the context class
|
66
|
+
#
|
67
|
+
# @param aliases [Hash{Symbol => Symbol, Array<Symbol>}] the attribute aliases of
|
68
|
+
# the context
|
69
|
+
#
|
70
|
+
# @return [Hash{Symbol => Array<Symbol>}]
|
71
|
+
def alias_attributes(aliases = {})
|
72
|
+
map_attribute_aliases(aliases)
|
73
|
+
attribute_aliases
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def map_attribute_aliases(aliases)
|
79
|
+
aliases.each_key do |attribute|
|
80
|
+
key = attribute.to_sym
|
81
|
+
attribute_aliases[key] ||= []
|
82
|
+
attribute_aliases[key].concat(Array.wrap(aliases[attribute]).map(&:to_sym))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize(attributes = {})
|
88
|
+
super(map_attributes(attributes))
|
89
|
+
end
|
90
|
+
|
91
|
+
# Attributes defined on the instance
|
92
|
+
#
|
93
|
+
# @example Get attributes defined on an instance
|
94
|
+
# MyInteractor::Context.attributes = :first_name, :last_name
|
95
|
+
# #=> [:first_name, :last_name]
|
96
|
+
#
|
97
|
+
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen')
|
98
|
+
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen'>
|
99
|
+
#
|
100
|
+
# context.attributes
|
101
|
+
# #=> { first_name: 'Aaron', last_name: 'Allen' }
|
102
|
+
#
|
103
|
+
# @example Get attributes defined on an instance with unknown attribute
|
104
|
+
# MyInteractor::Context.attributes = :first_name, :last_name
|
105
|
+
# #=> [:first_name, :last_name]
|
106
|
+
#
|
107
|
+
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen', unknown: 'unknown')
|
108
|
+
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen', unknown='unknown'>
|
109
|
+
#
|
110
|
+
# context.attributes
|
111
|
+
# #=> { first_name: 'Aaron', last_name: 'Allen' }
|
112
|
+
#
|
113
|
+
# context.unknown
|
114
|
+
# #=> 'unknown'
|
115
|
+
#
|
116
|
+
# @return [Hash{Symbol => *}] the defined attributes and values
|
117
|
+
def attributes
|
118
|
+
self.class.attributes.each_with_object({}) do |attribute, hash|
|
119
|
+
hash[attribute] = self[attribute] if self[attribute]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Removes properties from the instance that are not
|
124
|
+
# explicitly defined in the context instance {#attributes}
|
125
|
+
#
|
126
|
+
# @example Clean an instance of Context with unknown attribute
|
127
|
+
# MyInteractor::Context.attributes = :first_name, :last_name
|
128
|
+
# #=> [:first_name, :last_name]
|
129
|
+
#
|
130
|
+
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen', unknown: 'unknown')
|
131
|
+
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen', unknown='unknown'>
|
132
|
+
#
|
133
|
+
# context.unknown
|
134
|
+
# #=> 'unknown'
|
135
|
+
#
|
136
|
+
# context.clean!
|
137
|
+
# #=> { unknown: 'unknown' }
|
138
|
+
#
|
139
|
+
# context.unknown
|
140
|
+
# #=> nil
|
141
|
+
#
|
142
|
+
# @return [Hash{Symbol => *}] the deleted attributes
|
143
|
+
def clean!
|
144
|
+
deleted = {}
|
145
|
+
return deleted if keys.empty?
|
146
|
+
|
147
|
+
keys.reject { |key| self.class.attributes.include?(key) }.each do |attribute|
|
148
|
+
deleted[attribute] = self[attribute] if self[attribute]
|
149
|
+
delete_field(key.to_s)
|
150
|
+
end
|
151
|
+
deleted
|
152
|
+
end
|
153
|
+
|
154
|
+
# All keys of properties currently defined on the instance
|
155
|
+
#
|
156
|
+
# @example An instance of Context with unknown attribute
|
157
|
+
# MyInteractor::Context.attributes = :first_name, :last_name
|
158
|
+
# #=> [:first_name, :last_name]
|
159
|
+
#
|
160
|
+
# context = MyInteractor::Context.new(first_name: 'Aaron', last_name: 'Allen', unknown: 'unknown')
|
161
|
+
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen', unknown='unknown'>
|
162
|
+
#
|
163
|
+
# context.keys
|
164
|
+
# #=> [:first_name, :last_name, :unknown]
|
165
|
+
#
|
166
|
+
# @return [Array<Symbol>] keys defined on the instance
|
167
|
+
def keys
|
168
|
+
each_pair.map { |pair| pair[0].to_sym }
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
def aliased_key(key)
|
174
|
+
self.class.attribute_aliases.each_pair do |attribute, aliases|
|
175
|
+
key = aliases.any? { |aliased| aliased == key.to_sym } ? attribute : key.to_sym
|
176
|
+
end
|
177
|
+
key
|
178
|
+
end
|
179
|
+
|
180
|
+
def map_attributes(attributes)
|
181
|
+
return {} unless attributes
|
182
|
+
|
183
|
+
attributes.keys.each_with_object({}) do |attribute, hash|
|
184
|
+
key = aliased_key(attribute)
|
185
|
+
hash[key] = attributes[attribute]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def new_ostruct_member!(name)
|
190
|
+
super(aliased_key(name))
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
# Raised when an interactor context fails
|
6
|
+
#
|
7
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
8
|
+
# @since 0.0.1
|
9
|
+
# @version 0.2
|
10
|
+
#
|
11
|
+
# @!attribute [r] context
|
12
|
+
# @return [Base] an instance of {Base}
|
13
|
+
class Failure < StandardError
|
14
|
+
attr_reader :context
|
15
|
+
|
16
|
+
# A new instance of {Failure}
|
17
|
+
# @param context [ActiveInteractor::Context::Base] an
|
18
|
+
# instance of {ActiveInteractor::Context::Base}
|
19
|
+
# @return [Failure] a new instance of {Failure}
|
20
|
+
def initialize(context = nil)
|
21
|
+
@context = context
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -81,7 +81,7 @@ module ActiveInteractor
|
|
81
81
|
@should_clean_context.nil? && self.class.__clean_after_perform
|
82
82
|
end
|
83
83
|
|
84
|
-
# Skip {ActiveInteractor::Context::
|
84
|
+
# Skip {ActiveInteractor::Context::Attributes#clean! #clean! on an interactor
|
85
85
|
# context that calls the {Callbacks.clean_context_on_completion} class method.
|
86
86
|
# This method is meant to be invoked by organizer interactors
|
87
87
|
# to ensure contexts are approriately passed between interactors.
|
@@ -7,7 +7,7 @@ module ActiveInteractor
|
|
7
7
|
# @api private
|
8
8
|
# @author Aaron Allen <hello@aaronmallen.me>
|
9
9
|
# @since 0.0.1
|
10
|
-
# @version 0.
|
10
|
+
# @version 0.2
|
11
11
|
module Context
|
12
12
|
extend ActiveSupport::Concern
|
13
13
|
|
@@ -42,6 +42,43 @@ module ActiveInteractor
|
|
42
42
|
context_class.attributes = attributes
|
43
43
|
end
|
44
44
|
|
45
|
+
# Assign attribute aliases to the context class of the interactor
|
46
|
+
# any aliases passed to the context will be assigned to the
|
47
|
+
# key of the aliases hash
|
48
|
+
#
|
49
|
+
# @example Assign attribute aliases to the context class
|
50
|
+
# class MyInteractor > ActiveInteractor::Base
|
51
|
+
# context_attributes :first_name, :last_name
|
52
|
+
# context_attribute_aliases last_name: :sir_name
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# MyInteractor::Context.attribute_aliases
|
56
|
+
# #=> { last_name: [:sir_name] }
|
57
|
+
#
|
58
|
+
# class MyInteractor > ActiveInteractor::Base
|
59
|
+
# context_attributes :first_name, :last_name
|
60
|
+
# context_attribute_aliases last_name: %i[sir_name, sirname]
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# MyInteractor::Context.attribute_aliases
|
64
|
+
# #=> { last_name: [:sir_name, :sirname] }
|
65
|
+
#
|
66
|
+
# context = MyInteractor.perform(first_name: 'Aaron', sir_name: 'Allen')
|
67
|
+
# #=> <#MyInteractor::Context first_name='Aaron', last_name='Allen')
|
68
|
+
#
|
69
|
+
# context.sir_name
|
70
|
+
# #=> nil
|
71
|
+
#
|
72
|
+
# context.last_name
|
73
|
+
# #=> 'Allen'
|
74
|
+
#
|
75
|
+
# @param aliases [Hash{Symbol => Symbol, Array<Symbol>}] the attribute aliases
|
76
|
+
#
|
77
|
+
# @return [Hash{Symbol => Array<Symbol>}] the attribute aliases
|
78
|
+
def context_attribute_aliases(aliases = {})
|
79
|
+
context_class.alias_attributes(aliases)
|
80
|
+
end
|
81
|
+
|
45
82
|
# The context class of the interactor
|
46
83
|
#
|
47
84
|
# @example
|
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: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Allen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -220,6 +220,8 @@ files:
|
|
220
220
|
- lib/active_interactor/base.rb
|
221
221
|
- lib/active_interactor/configuration.rb
|
222
222
|
- lib/active_interactor/context.rb
|
223
|
+
- lib/active_interactor/context/attributes.rb
|
224
|
+
- lib/active_interactor/context/errors.rb
|
223
225
|
- lib/active_interactor/interactor.rb
|
224
226
|
- lib/active_interactor/interactor/callbacks.rb
|
225
227
|
- lib/active_interactor/interactor/context.rb
|
@@ -244,10 +246,10 @@ licenses:
|
|
244
246
|
- MIT
|
245
247
|
metadata:
|
246
248
|
bug_tracker_uri: https://github.com/aaronmallen/activeinteractor/issues
|
247
|
-
changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v0.1.
|
248
|
-
documentation_uri: https://www.rubydoc.info/gems/activeinteractor/0.1.
|
249
|
+
changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v0.1.4/CHANGELOG.md
|
250
|
+
documentation_uri: https://www.rubydoc.info/gems/activeinteractor/0.1.4
|
249
251
|
hompage_uri: https://github.com/aaronmallen/activeinteractor
|
250
|
-
source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v0.1.
|
252
|
+
source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v0.1.4
|
251
253
|
wiki_uri: https://github.com/aaronmallen/activeinteractor/wiki
|
252
254
|
post_install_message:
|
253
255
|
rdoc_options: []
|