interactor_support 1.0.2 → 1.0.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/.prettierignore +1 -0
- data/.yardopts +19 -0
- data/CHANGELOG.md +10 -0
- data/README.md +302 -319
- data/lib/interactor_support/actions.rb +33 -0
- data/lib/interactor_support/concerns/findable.rb +64 -20
- data/lib/interactor_support/concerns/organizable.rb +194 -0
- data/lib/interactor_support/concerns/skippable.rb +42 -0
- data/lib/interactor_support/concerns/transactionable.rb +37 -0
- data/lib/interactor_support/concerns/transformable.rb +64 -10
- data/lib/interactor_support/concerns/updatable.rb +43 -1
- data/lib/interactor_support/configuration.rb +32 -9
- data/lib/interactor_support/core.rb +19 -1
- data/lib/interactor_support/request_object.rb +132 -19
- data/lib/interactor_support/validations.rb +89 -9
- data/lib/interactor_support/version.rb +1 -1
- data/lib/interactor_support.rb +44 -0
- metadata +5 -2
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
module InteractorSupport
|
|
2
|
+
##
|
|
3
|
+
# Core behavior that ensures the `Interactor` module is included
|
|
4
|
+
# when any InteractorSupport concern is mixed in.
|
|
5
|
+
#
|
|
6
|
+
# This module is automatically included by all `InteractorSupport::Concerns`,
|
|
7
|
+
# so you generally do not need to include it manually.
|
|
8
|
+
#
|
|
9
|
+
# @example Included implicitly
|
|
10
|
+
# class MyInteractor
|
|
11
|
+
# include InteractorSupport::Concerns::Findable
|
|
12
|
+
# # => Interactor is automatically included
|
|
13
|
+
# end
|
|
2
14
|
module Core
|
|
3
15
|
class << self
|
|
16
|
+
##
|
|
17
|
+
# Ensures the `Interactor` module is included in the base class.
|
|
18
|
+
#
|
|
19
|
+
# This hook runs when `Core` is included by a concern and conditionally
|
|
20
|
+
# includes `Interactor` if not already present.
|
|
21
|
+
#
|
|
22
|
+
# @param base [Class] the class or module including this concern
|
|
4
23
|
def included(base)
|
|
5
|
-
# Only include Interactor if it isn’t already present.
|
|
6
24
|
base.include(Interactor) unless base.included_modules.include?(Interactor)
|
|
7
25
|
end
|
|
8
26
|
end
|
|
@@ -1,18 +1,75 @@
|
|
|
1
|
-
# app/concerns/interactor_support/request_object.rb
|
|
2
1
|
module InteractorSupport
|
|
2
|
+
##
|
|
3
|
+
# A base module for building validated, transformable, and optionally nested request objects.
|
|
4
|
+
#
|
|
5
|
+
# It builds on top of `ActiveModel::Model`, adds coercion, default values, attribute transforms,
|
|
6
|
+
# key rewriting, and automatic context conversion (via `#to_context`). It integrates tightly with
|
|
7
|
+
# `InteractorSupport::Configuration` to control return behavior and key formatting.
|
|
8
|
+
#
|
|
9
|
+
# @example Basic usage
|
|
10
|
+
# class CreateUserRequest
|
|
11
|
+
# include InteractorSupport::RequestObject
|
|
12
|
+
#
|
|
13
|
+
# attribute :name, transform: [:strip, :downcase]
|
|
14
|
+
# attribute :email
|
|
15
|
+
# attribute :metadata, default: {}
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# CreateUserRequest.new(name: " JOHN ", email: "hi@example.com")
|
|
19
|
+
# # => { name: "john", email: "hi@example.com", metadata: {} }
|
|
20
|
+
#
|
|
21
|
+
# @example Key rewriting
|
|
22
|
+
# class UploadRequest
|
|
23
|
+
# include InteractorSupport::RequestObject
|
|
24
|
+
#
|
|
25
|
+
# attribute :image, rewrite: :image_url
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# UploadRequest.new(image: "url").image_url # => "url"
|
|
29
|
+
#
|
|
30
|
+
# @see InteractorSupport::Configuration
|
|
3
31
|
module RequestObject
|
|
4
32
|
extend ActiveSupport::Concern
|
|
33
|
+
SUPPORTED_ACTIVEMODEL_TYPES = ActiveModel::Type.registry.send(:registrations).keys.map { |type| ":#{type}" }
|
|
34
|
+
SUPPORTED_PRIMITIVES = ['AnyClass', 'Symbol', 'Hash', 'Array']
|
|
35
|
+
SUPPORTED_TYPES = SUPPORTED_PRIMITIVES + SUPPORTED_ACTIVEMODEL_TYPES
|
|
36
|
+
|
|
37
|
+
class TypeError < StandardError
|
|
38
|
+
end
|
|
5
39
|
|
|
6
40
|
included do
|
|
7
41
|
include ActiveModel::Model
|
|
8
42
|
include ActiveModel::Attributes
|
|
9
43
|
include ActiveModel::Validations::Callbacks
|
|
10
44
|
|
|
45
|
+
##
|
|
46
|
+
# Initializes the request object and raises if invalid.
|
|
47
|
+
#
|
|
48
|
+
# Rewritten keys are converted before passing to ActiveModel.
|
|
49
|
+
#
|
|
50
|
+
# @param attributes [Hash] the input attributes
|
|
51
|
+
# @raise [ActiveModel::ValidationError] if the object is invalid
|
|
11
52
|
def initialize(attributes = {})
|
|
53
|
+
attributes = attributes.dup
|
|
54
|
+
self.class.rewritten_attributes.each do |external, internal|
|
|
55
|
+
if attributes.key?(external)
|
|
56
|
+
attributes[internal] = attributes.delete(external)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
12
60
|
super(attributes)
|
|
13
61
|
raise ActiveModel::ValidationError, self unless valid?
|
|
14
62
|
end
|
|
15
63
|
|
|
64
|
+
##
|
|
65
|
+
# Converts the request object into a format suitable for interactor context.
|
|
66
|
+
#
|
|
67
|
+
# - If `key_type` is `:symbol` or `:string`, returns a Hash.
|
|
68
|
+
# - If `key_type` is `:struct`, returns a Struct instance.
|
|
69
|
+
#
|
|
70
|
+
# Nested request objects will also be converted recursively.
|
|
71
|
+
#
|
|
72
|
+
# @return [Hash, Struct]
|
|
16
73
|
def to_context
|
|
17
74
|
key_type = InteractorSupport.configuration.request_object_key_type
|
|
18
75
|
attrs = attributes.each_with_object({}) do |(name, value), hash|
|
|
@@ -25,32 +82,49 @@ module InteractorSupport
|
|
|
25
82
|
value
|
|
26
83
|
end
|
|
27
84
|
end
|
|
85
|
+
|
|
28
86
|
return Struct.new(*attrs.keys).new(*attrs.values) if key_type == :struct
|
|
29
87
|
|
|
30
88
|
attrs
|
|
31
89
|
end
|
|
32
90
|
|
|
33
91
|
class << self
|
|
92
|
+
##
|
|
93
|
+
# Custom constructor that optionally returns the context instead of the object itself.
|
|
94
|
+
#
|
|
95
|
+
# Behavior is configured via `InteractorSupport.configuration.request_object_behavior`.
|
|
96
|
+
#
|
|
97
|
+
# @param args [Array] positional args
|
|
98
|
+
# @param kwargs [Hash] keyword args
|
|
99
|
+
# @return [RequestObject, Hash, Struct]
|
|
34
100
|
def new(*args, **kwargs)
|
|
35
101
|
return super(*args, **kwargs) if InteractorSupport.configuration.request_object_behavior == :returns_self
|
|
36
102
|
|
|
37
103
|
super(*args, **kwargs).to_context
|
|
38
104
|
end
|
|
39
105
|
|
|
40
|
-
|
|
106
|
+
##
|
|
107
|
+
# Defines one or more attributes with optional coercion, default values, transformation,
|
|
108
|
+
# and an optional `rewrite:` key to rename the underlying attribute.
|
|
109
|
+
#
|
|
110
|
+
# @param names [Array<Symbol>] the attribute names
|
|
111
|
+
# @param type [Class, nil] optional class to coerce the value to (often another request object)
|
|
112
|
+
# @param array [Boolean] whether to treat the input as an array of typed objects
|
|
113
|
+
# @param default [Object] default value if not provided
|
|
114
|
+
# @param transform [Symbol, Array<Symbol>] method(s) to apply to the value
|
|
115
|
+
# @param rewrite [Symbol, nil] optional internal name to rewrite this attribute to
|
|
41
116
|
#
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
# - array: when true, expects an array; each element is cast.
|
|
45
|
-
# - default: default value for the attribute.
|
|
46
|
-
# - transform: a symbol or an array of symbols that will be applied (if the value responds to them).
|
|
47
|
-
def attribute(*names, type: nil, array: false, default: nil, transform: nil)
|
|
117
|
+
# @raise [ArgumentError] if a transform method is not found
|
|
118
|
+
def attribute(*names, type: nil, array: false, default: nil, transform: nil, rewrite: nil)
|
|
48
119
|
names.each do |name|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
120
|
+
attr_name = rewrite || name
|
|
121
|
+
rewritten_attributes[name.to_sym] = attr_name if rewrite
|
|
122
|
+
transform_options[attr_name.to_sym] = transform if transform.present?
|
|
123
|
+
|
|
124
|
+
super(attr_name, default: default)
|
|
125
|
+
original_writer = instance_method("#{attr_name}=")
|
|
126
|
+
|
|
127
|
+
define_method("#{attr_name}=") do |value|
|
|
54
128
|
if transform
|
|
55
129
|
Array(transform).each do |method|
|
|
56
130
|
if value.respond_to?(method)
|
|
@@ -62,25 +136,64 @@ module InteractorSupport
|
|
|
62
136
|
end
|
|
63
137
|
end
|
|
64
138
|
end
|
|
65
|
-
|
|
139
|
+
|
|
140
|
+
# If a `type` is specified, we attempt to cast the `value` to that type
|
|
66
141
|
if type
|
|
67
|
-
value =
|
|
68
|
-
Array(value).map { |v| v.is_a?(type) ? v : type.new(v) }
|
|
69
|
-
else
|
|
70
|
-
value.is_a?(type) ? value : type.new(value)
|
|
71
|
-
end
|
|
142
|
+
value = array ? Array(value).map { |v| cast_value(v, type) } : cast_value(value, type)
|
|
72
143
|
end
|
|
144
|
+
|
|
73
145
|
original_writer.bind(self).call(value)
|
|
74
146
|
end
|
|
75
147
|
end
|
|
76
148
|
end
|
|
77
149
|
|
|
150
|
+
##
|
|
151
|
+
# Internal map of external attribute names to internal rewritten names.
|
|
152
|
+
#
|
|
153
|
+
# @return [Hash{Symbol => Symbol}]
|
|
154
|
+
def rewritten_attributes
|
|
155
|
+
@_rewritten_attributes ||= {}
|
|
156
|
+
end
|
|
157
|
+
|
|
78
158
|
private
|
|
79
159
|
|
|
160
|
+
##
|
|
161
|
+
# Internal storage for transform options per attribute.
|
|
162
|
+
#
|
|
163
|
+
# @return [Hash{Symbol => Symbol, Array<Symbol>}]
|
|
80
164
|
def transform_options
|
|
81
165
|
@_transform_options ||= {}
|
|
82
166
|
end
|
|
83
167
|
end
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
def cast_value(value, type)
|
|
172
|
+
return typecast(value, type) if type.is_a?(Symbol)
|
|
173
|
+
return value if value.is_a?(type)
|
|
174
|
+
return type.new(value) if type <= InteractorSupport::RequestObject
|
|
175
|
+
|
|
176
|
+
typecast(value, type)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def typecast(value, type)
|
|
180
|
+
if type.is_a?(Symbol)
|
|
181
|
+
ActiveModel::Type.lookup(type).cast(value)
|
|
182
|
+
elsif type == Symbol
|
|
183
|
+
value.to_sym
|
|
184
|
+
elsif type == Array
|
|
185
|
+
value.to_a
|
|
186
|
+
elsif type == Hash
|
|
187
|
+
value.to_h
|
|
188
|
+
else
|
|
189
|
+
raise TypeError
|
|
190
|
+
end
|
|
191
|
+
rescue ArgumentError
|
|
192
|
+
message = ":#{type} is not a supported type. Supported types are: #{SUPPORTED_TYPES.join(", ")}"
|
|
193
|
+
raise TypeError, message
|
|
194
|
+
rescue
|
|
195
|
+
raise TypeError, "Cannot cast #{value.inspect} to #{type.name}"
|
|
196
|
+
end
|
|
84
197
|
end
|
|
85
198
|
end
|
|
86
199
|
end
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
require 'active_model'
|
|
2
2
|
|
|
3
3
|
module InteractorSupport
|
|
4
|
+
##
|
|
5
|
+
# Provides context-aware validation DSL for interactors.
|
|
6
|
+
#
|
|
7
|
+
# This module adds `ActiveModel::Validations` and wraps it with methods like
|
|
8
|
+
# `required`, `optional`, `validates_before`, and `validates_after`, allowing
|
|
9
|
+
# declarative validation of interactor context values.
|
|
10
|
+
#
|
|
11
|
+
# Validations are executed automatically before (or after) the interactor runs.
|
|
12
|
+
#
|
|
13
|
+
# @example Required attributes with ActiveModel rules
|
|
14
|
+
# required :email, :name
|
|
15
|
+
# required age: { numericality: { greater_than: 18 } }
|
|
16
|
+
#
|
|
17
|
+
# @example Optional attributes with presence/format validations
|
|
18
|
+
# optional bio: { length: { maximum: 500 } }
|
|
19
|
+
#
|
|
20
|
+
# @example Type and inclusion validation before execution
|
|
21
|
+
# validates_before :role, type: String, inclusion: { in: %w[admin user guest] }
|
|
22
|
+
#
|
|
23
|
+
# @example Persistence validation after execution
|
|
24
|
+
# validates_after :user, persisted: true
|
|
25
|
+
#
|
|
26
|
+
# @see ActiveModel::Validations
|
|
4
27
|
module Validations
|
|
5
28
|
extend ActiveSupport::Concern
|
|
6
29
|
include InteractorSupport::Core
|
|
@@ -11,14 +34,35 @@ module InteractorSupport
|
|
|
11
34
|
end
|
|
12
35
|
|
|
13
36
|
class_methods do
|
|
37
|
+
##
|
|
38
|
+
# Declares one or more attributes as required.
|
|
39
|
+
#
|
|
40
|
+
# Values must be present in the context. You can also pass validation options
|
|
41
|
+
# as a hash, which will be forwarded to ActiveModel's `validates`.
|
|
42
|
+
#
|
|
43
|
+
# @param keys [Array<Symbol, Hash>] attribute names or hash of attributes with validation options
|
|
14
44
|
def required(*keys)
|
|
15
45
|
apply_validations(keys, required: true)
|
|
16
46
|
end
|
|
17
47
|
|
|
48
|
+
##
|
|
49
|
+
# Declares one or more attributes as optional.
|
|
50
|
+
#
|
|
51
|
+
# Optional values can be nil, but still support validation rules.
|
|
52
|
+
#
|
|
53
|
+
# @param keys [Array<Symbol, Hash>] attribute names or hash of attributes with validation options
|
|
18
54
|
def optional(*keys)
|
|
19
55
|
apply_validations(keys, required: false)
|
|
20
56
|
end
|
|
21
57
|
|
|
58
|
+
##
|
|
59
|
+
# Runs additional validations *after* the interactor executes.
|
|
60
|
+
#
|
|
61
|
+
# Useful for checking persisted records, custom conditions, or results
|
|
62
|
+
# that depend on post-processing logic.
|
|
63
|
+
#
|
|
64
|
+
# @param keys [Array<Symbol>] context keys to validate
|
|
65
|
+
# @param validations [Hash] validation options (e.g., presence:, type:, inclusion:, persisted:)
|
|
22
66
|
def validates_after(*keys, **validations)
|
|
23
67
|
after do
|
|
24
68
|
keys.each do |key|
|
|
@@ -27,6 +71,15 @@ module InteractorSupport
|
|
|
27
71
|
end
|
|
28
72
|
end
|
|
29
73
|
|
|
74
|
+
##
|
|
75
|
+
# Runs validations *before* the interactor executes.
|
|
76
|
+
#
|
|
77
|
+
# Prevents invalid data from reaching business logic.
|
|
78
|
+
#
|
|
79
|
+
# NOTE: `persisted:` validation is only available in `validates_after`.
|
|
80
|
+
#
|
|
81
|
+
# @param keys [Array<Symbol>] context keys to validate
|
|
82
|
+
# @param validations [Hash] validation options (e.g., presence:, type:, inclusion:)
|
|
30
83
|
def validates_before(*keys, **validations)
|
|
31
84
|
before do
|
|
32
85
|
if validations[:persisted]
|
|
@@ -41,6 +94,11 @@ module InteractorSupport
|
|
|
41
94
|
|
|
42
95
|
private
|
|
43
96
|
|
|
97
|
+
##
|
|
98
|
+
# Applies ActiveModel-based validations and wires up accessors to context.
|
|
99
|
+
#
|
|
100
|
+
# @param keys [Array<Symbol, Hash>] attributes to validate
|
|
101
|
+
# @param required [Boolean] whether presence is enforced
|
|
44
102
|
def apply_validations(keys, required:)
|
|
45
103
|
keys.each do |key|
|
|
46
104
|
if key.is_a?(Hash)
|
|
@@ -61,18 +119,27 @@ module InteractorSupport
|
|
|
61
119
|
validates(key, presence: true) if required
|
|
62
120
|
end
|
|
63
121
|
end
|
|
64
|
-
|
|
122
|
+
|
|
65
123
|
before do
|
|
66
124
|
context.fail!(errors: errors.full_messages) unless valid?
|
|
67
125
|
end
|
|
68
126
|
end
|
|
69
127
|
|
|
128
|
+
##
|
|
129
|
+
# Defines methods to read/write from the interactor context.
|
|
130
|
+
#
|
|
131
|
+
# @param key [Symbol] the context key
|
|
70
132
|
def define_context_methods(key)
|
|
71
133
|
define_method(key) { context[key] }
|
|
72
134
|
define_method("#{key}=") { |value| context[key] = value }
|
|
73
135
|
end
|
|
74
136
|
end
|
|
75
137
|
|
|
138
|
+
##
|
|
139
|
+
# Applies custom inline validations to a context key.
|
|
140
|
+
#
|
|
141
|
+
# @param key [Symbol] the context key
|
|
142
|
+
# @param validations [Hash] options like presence:, type:, inclusion:, persisted:
|
|
76
143
|
def apply_custom_validations(key, validations)
|
|
77
144
|
validation_for_presence(key) if validations[:presence]
|
|
78
145
|
validation_for_inclusion(key, validations[:inclusion]) if validations[:inclusion]
|
|
@@ -80,10 +147,20 @@ module InteractorSupport
|
|
|
80
147
|
validation_for_type(key, validations[:type]) if validations[:type]
|
|
81
148
|
end
|
|
82
149
|
|
|
150
|
+
##
|
|
151
|
+
# Fails if context value is not of expected type.
|
|
152
|
+
#
|
|
153
|
+
# @param key [Symbol]
|
|
154
|
+
# @param type [Class]
|
|
83
155
|
def validation_for_type(key, type)
|
|
84
156
|
context.fail!(errors: ["#{key} was not of type #{type}"]) unless context[key].is_a?(type)
|
|
85
157
|
end
|
|
86
158
|
|
|
159
|
+
##
|
|
160
|
+
# Fails if value is not included in allowed values.
|
|
161
|
+
#
|
|
162
|
+
# @param key [Symbol]
|
|
163
|
+
# @param inclusion [Hash] with `:in` key
|
|
87
164
|
def validation_for_inclusion(key, inclusion)
|
|
88
165
|
unless inclusion.is_a?(Hash) && inclusion[:in].is_a?(Enumerable)
|
|
89
166
|
raise ArgumentError, 'inclusion validation requires an :in key with an array or range'
|
|
@@ -94,23 +171,26 @@ module InteractorSupport
|
|
|
94
171
|
context.fail!(errors: [e.message])
|
|
95
172
|
end
|
|
96
173
|
|
|
174
|
+
##
|
|
175
|
+
# Fails if value is nil or blank.
|
|
176
|
+
#
|
|
177
|
+
# @param key [Symbol]
|
|
97
178
|
def validation_for_presence(key)
|
|
98
179
|
context.fail!(errors: ["#{key} does not exist"]) unless context[key].present?
|
|
99
180
|
end
|
|
100
181
|
|
|
182
|
+
##
|
|
183
|
+
# Fails if value is not a persisted `ApplicationRecord`.
|
|
184
|
+
#
|
|
185
|
+
# @param key [Symbol]
|
|
101
186
|
def validation_for_persistence(key)
|
|
102
187
|
validation_for_presence(key)
|
|
188
|
+
|
|
103
189
|
unless context[key].is_a?(ApplicationRecord)
|
|
104
|
-
context.fail!(
|
|
105
|
-
errors: [
|
|
106
|
-
"#{key} is not an ApplicationRecord, which is required for persisted validation",
|
|
107
|
-
],
|
|
108
|
-
)
|
|
190
|
+
context.fail!(errors: ["#{key} is not an ApplicationRecord, which is required for persisted validation"])
|
|
109
191
|
end
|
|
110
192
|
|
|
111
|
-
context.fail!(
|
|
112
|
-
errors: ["#{key} was not persisted"] + context[key].errors.full_messages,
|
|
113
|
-
) unless context[key].persisted?
|
|
193
|
+
context.fail!(errors: ["#{key} was not persisted"] + context[key].errors.full_messages) unless context[key].persisted?
|
|
114
194
|
end
|
|
115
195
|
end
|
|
116
196
|
end
|
data/lib/interactor_support.rb
CHANGED
|
@@ -12,15 +12,59 @@ require_relative 'interactor_support/configuration'
|
|
|
12
12
|
|
|
13
13
|
Dir[File.join(__dir__, 'interactor_support/concerns/*.rb')].sort.each { |file| require file }
|
|
14
14
|
|
|
15
|
+
##
|
|
16
|
+
# InteractorSupport is a modular DSL for building expressive, validated, and
|
|
17
|
+
# transactional service objects using the [Interactor](https://github.com/collectiveidea/interactor) gem.
|
|
18
|
+
#
|
|
19
|
+
# It enhances interactors with powerful helpers like:
|
|
20
|
+
# - `Actions` for data loading, transformation, and persistence
|
|
21
|
+
# - `Validations` for context-aware presence/type/inclusion checks
|
|
22
|
+
# - `RequestObject` for clean, validated, form-like parameter objects
|
|
23
|
+
#
|
|
24
|
+
# It also provides configuration options to control request object behavior.
|
|
25
|
+
#
|
|
26
|
+
# @example Basic usage
|
|
27
|
+
# class CreateUser
|
|
28
|
+
# include Interactor
|
|
29
|
+
# include InteractorSupport
|
|
30
|
+
#
|
|
31
|
+
# required :email, :name
|
|
32
|
+
#
|
|
33
|
+
# transform :email, with: [:strip, :downcase]
|
|
34
|
+
#
|
|
35
|
+
# find_by :account
|
|
36
|
+
#
|
|
37
|
+
# update :user, attributes: { email: :email, name: :name }
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# @example Configuration
|
|
41
|
+
# InteractorSupport.configure do |config|
|
|
42
|
+
# config.request_object_behavior = :returns_self
|
|
43
|
+
# config.request_object_key_type = :symbol
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# @see InteractorSupport::Actions
|
|
47
|
+
# @see InteractorSupport::Validations
|
|
48
|
+
# @see InteractorSupport::RequestObject
|
|
49
|
+
# @see InteractorSupport::Configuration
|
|
15
50
|
module InteractorSupport
|
|
16
51
|
extend ActiveSupport::Concern
|
|
17
52
|
|
|
18
53
|
class << self
|
|
54
|
+
##
|
|
55
|
+
# Allows external configuration of InteractorSupport.
|
|
56
|
+
#
|
|
57
|
+
# @yieldparam config [InteractorSupport::Configuration] the global configuration object
|
|
58
|
+
# @return [void]
|
|
19
59
|
def configure
|
|
20
60
|
self.configuration ||= Configuration.new
|
|
21
61
|
yield(configuration) if block_given?
|
|
22
62
|
end
|
|
23
63
|
|
|
64
|
+
##
|
|
65
|
+
# Returns the global InteractorSupport configuration object.
|
|
66
|
+
#
|
|
67
|
+
# @return [InteractorSupport::Configuration]
|
|
24
68
|
def configuration
|
|
25
69
|
@configuration ||= Configuration.new
|
|
26
70
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: interactor_support
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Charlie Mitchell
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-04-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email:
|
|
@@ -17,8 +17,10 @@ executables: []
|
|
|
17
17
|
extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
|
19
19
|
files:
|
|
20
|
+
- ".prettierignore"
|
|
20
21
|
- ".rspec"
|
|
21
22
|
- ".rubocop.yml"
|
|
23
|
+
- ".yardopts"
|
|
22
24
|
- CHANGELOG.md
|
|
23
25
|
- CODE_OF_CONDUCT.md
|
|
24
26
|
- LICENSE.txt
|
|
@@ -28,6 +30,7 @@ files:
|
|
|
28
30
|
- lib/interactor_support.rb
|
|
29
31
|
- lib/interactor_support/actions.rb
|
|
30
32
|
- lib/interactor_support/concerns/findable.rb
|
|
33
|
+
- lib/interactor_support/concerns/organizable.rb
|
|
31
34
|
- lib/interactor_support/concerns/skippable.rb
|
|
32
35
|
- lib/interactor_support/concerns/transactionable.rb
|
|
33
36
|
- lib/interactor_support/concerns/transformable.rb
|