treaty 0.19.0 → 0.20.0
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/README.md +1 -1
- data/lib/treaty/action/base.rb +11 -0
- data/lib/treaty/action/context/callable.rb +90 -0
- data/lib/treaty/action/context/dsl.rb +56 -0
- data/lib/treaty/action/context/workspace.rb +92 -0
- data/lib/treaty/action/executor/inventory.rb +136 -0
- data/lib/treaty/{info/rest → action/info}/builder.rb +2 -2
- data/lib/treaty/{info/rest → action/info}/dsl.rb +2 -2
- data/lib/treaty/{info/rest → action/info}/result.rb +2 -2
- data/lib/treaty/action/inventory/collection.rb +77 -0
- data/lib/treaty/action/inventory/factory.rb +108 -0
- data/lib/treaty/action/inventory/inventory.rb +146 -0
- data/lib/treaty/action/request/attribute/attribute.rb +76 -0
- data/lib/treaty/action/request/attribute/builder.rb +98 -0
- data/lib/treaty/action/request/entity.rb +78 -0
- data/lib/treaty/action/request/factory.rb +116 -0
- data/lib/treaty/action/request/validator.rb +120 -0
- data/lib/treaty/action/response/attribute/attribute.rb +79 -0
- data/lib/treaty/action/response/attribute/builder.rb +96 -0
- data/lib/treaty/action/response/entity.rb +79 -0
- data/lib/treaty/action/response/factory.rb +129 -0
- data/lib/treaty/action/response/validator.rb +111 -0
- data/lib/treaty/action/result.rb +81 -0
- data/lib/treaty/action/versions/collection.rb +47 -0
- data/lib/treaty/action/versions/dsl.rb +116 -0
- data/lib/treaty/action/versions/execution/request.rb +287 -0
- data/lib/treaty/action/versions/executor.rb +61 -0
- data/lib/treaty/action/versions/factory.rb +253 -0
- data/lib/treaty/action/versions/resolver.rb +150 -0
- data/lib/treaty/action/versions/semantic.rb +64 -0
- data/lib/treaty/action/versions/workspace.rb +106 -0
- data/lib/treaty/action.rb +31 -0
- data/lib/treaty/controller/dsl.rb +1 -1
- data/lib/treaty/entity/attribute/base.rb +1 -1
- data/lib/treaty/entity/attribute/builder/base.rb +1 -1
- data/lib/treaty/entity/attribute/dsl.rb +1 -1
- data/lib/treaty/entity/base.rb +1 -1
- data/lib/treaty/entity/builder.rb +62 -5
- data/lib/treaty/version.rb +1 -1
- metadata +32 -31
- data/lib/treaty/base.rb +0 -9
- data/lib/treaty/context/callable.rb +0 -26
- data/lib/treaty/context/dsl.rb +0 -12
- data/lib/treaty/context/workspace.rb +0 -32
- data/lib/treaty/executor/inventory.rb +0 -122
- data/lib/treaty/inventory/collection.rb +0 -71
- data/lib/treaty/inventory/factory.rb +0 -91
- data/lib/treaty/inventory/inventory.rb +0 -92
- data/lib/treaty/request/attribute/attribute.rb +0 -25
- data/lib/treaty/request/attribute/builder.rb +0 -46
- data/lib/treaty/request/entity.rb +0 -33
- data/lib/treaty/request/factory.rb +0 -81
- data/lib/treaty/request/validator.rb +0 -60
- data/lib/treaty/response/attribute/attribute.rb +0 -25
- data/lib/treaty/response/attribute/builder.rb +0 -46
- data/lib/treaty/response/entity.rb +0 -33
- data/lib/treaty/response/factory.rb +0 -87
- data/lib/treaty/response/validator.rb +0 -53
- data/lib/treaty/result.rb +0 -23
- data/lib/treaty/versions/collection.rb +0 -15
- data/lib/treaty/versions/dsl.rb +0 -42
- data/lib/treaty/versions/execution/request.rb +0 -177
- data/lib/treaty/versions/executor.rb +0 -14
- data/lib/treaty/versions/factory.rb +0 -112
- data/lib/treaty/versions/resolver.rb +0 -70
- data/lib/treaty/versions/semantic.rb +0 -22
- data/lib/treaty/versions/workspace.rb +0 -43
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Action
|
|
5
|
+
module Versions
|
|
6
|
+
# DSL module for defining API versions in treaty classes.
|
|
7
|
+
#
|
|
8
|
+
# ## Purpose
|
|
9
|
+
#
|
|
10
|
+
# Provides the `version` class method for defining API versions.
|
|
11
|
+
# Each version can have its own request/response schema, executor,
|
|
12
|
+
# summary, and deprecation status.
|
|
13
|
+
#
|
|
14
|
+
# ## Usage
|
|
15
|
+
#
|
|
16
|
+
# Included in:
|
|
17
|
+
# - Treaty::Action::Base (as core DSL functionality)
|
|
18
|
+
#
|
|
19
|
+
# ## DSL Methods
|
|
20
|
+
#
|
|
21
|
+
# When included, provides:
|
|
22
|
+
# - `version` - Define a new API version with configuration block
|
|
23
|
+
# - `collection_of_versions` - Access all defined versions
|
|
24
|
+
#
|
|
25
|
+
# ## Version Definition
|
|
26
|
+
#
|
|
27
|
+
# class Posts::CreateTreaty < ApplicationTreaty
|
|
28
|
+
# version 1, default: true do
|
|
29
|
+
# summary "Initial version"
|
|
30
|
+
#
|
|
31
|
+
# request do
|
|
32
|
+
# object :post do
|
|
33
|
+
# string :title, :required
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# response 201 do
|
|
38
|
+
# object :post do
|
|
39
|
+
# string :id
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# delegate_to Posts::CreateService
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# version 2 do
|
|
47
|
+
# summary "Added tags"
|
|
48
|
+
# deprecated { ENV["V2_DEPRECATED"] == "true" }
|
|
49
|
+
# # ...
|
|
50
|
+
# end
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# ## Validation
|
|
54
|
+
#
|
|
55
|
+
# Validates that only one version is marked as default.
|
|
56
|
+
# Raises `VersionMultipleDefaults` if multiple defaults detected.
|
|
57
|
+
module DSL
|
|
58
|
+
# Hook called when module is included
|
|
59
|
+
#
|
|
60
|
+
# @param base [Class] The class including this module
|
|
61
|
+
def self.included(base)
|
|
62
|
+
base.extend(ClassMethods)
|
|
63
|
+
base.include(Workspace)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Class methods added to including class
|
|
67
|
+
module ClassMethods
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# Defines a new API version
|
|
71
|
+
#
|
|
72
|
+
# Creates a version factory, evaluates the configuration block,
|
|
73
|
+
# validates the configuration, and adds to collection.
|
|
74
|
+
#
|
|
75
|
+
# @param version [Integer, String, Array] Version identifier
|
|
76
|
+
# @param default [Boolean] Whether this is the default version
|
|
77
|
+
# @param block [Proc] Configuration block (request, response, delegate_to, etc.)
|
|
78
|
+
# @raise [Treaty::Exceptions::VersionMultipleDefaults] If multiple defaults
|
|
79
|
+
# @return [void]
|
|
80
|
+
def version(version, default: false, &block)
|
|
81
|
+
@version_factory = Factory.new(version:, default:)
|
|
82
|
+
|
|
83
|
+
@version_factory.instance_eval(&block)
|
|
84
|
+
@version_factory.validate_after_block!
|
|
85
|
+
|
|
86
|
+
validate_multiple_defaults! if @version_factory.default_result == true
|
|
87
|
+
|
|
88
|
+
collection_of_versions << @version_factory
|
|
89
|
+
|
|
90
|
+
@version_factory = nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Returns collection of all defined versions
|
|
94
|
+
#
|
|
95
|
+
# @return [Treaty::Action::Versions::Collection] Collection of version factories
|
|
96
|
+
def collection_of_versions
|
|
97
|
+
@collection_of_versions ||= Collection.new
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Validates that only one version is marked as default
|
|
101
|
+
#
|
|
102
|
+
# @raise [Treaty::Exceptions::VersionMultipleDefaults] If multiple defaults
|
|
103
|
+
# @return [void]
|
|
104
|
+
def validate_multiple_defaults!
|
|
105
|
+
existing_defaults = collection_of_versions.map(&:default_result).count(true)
|
|
106
|
+
|
|
107
|
+
return if existing_defaults.zero?
|
|
108
|
+
|
|
109
|
+
raise Treaty::Exceptions::VersionMultipleDefaults,
|
|
110
|
+
I18n.t("treaty.versioning.factory.multiple_defaults")
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Action
|
|
5
|
+
module Versions
|
|
6
|
+
module Execution
|
|
7
|
+
# Executes the configured service/proc with validated parameters.
|
|
8
|
+
#
|
|
9
|
+
# ## Purpose
|
|
10
|
+
#
|
|
11
|
+
# Handles the actual execution of the delegated service, supporting
|
|
12
|
+
# multiple executor types: Class, String path, and Proc/Lambda.
|
|
13
|
+
# Provides special handling for Servactory services.
|
|
14
|
+
#
|
|
15
|
+
# ## Usage
|
|
16
|
+
#
|
|
17
|
+
# Called by:
|
|
18
|
+
# - Versions::Workspace (after request validation)
|
|
19
|
+
#
|
|
20
|
+
# ## Executor Types
|
|
21
|
+
#
|
|
22
|
+
# | Type | Example | Resolution |
|
|
23
|
+
# |------|---------|------------|
|
|
24
|
+
# | Class | `Posts::CreateService` | Direct call |
|
|
25
|
+
# | String | `"posts/create_service"` | Constantized then called |
|
|
26
|
+
# | Proc | `->(params:) { ... }` | Direct call |
|
|
27
|
+
#
|
|
28
|
+
# ## Servactory Integration
|
|
29
|
+
#
|
|
30
|
+
# Detects Servactory services via `servactory?` class method.
|
|
31
|
+
# Catches Servactory-specific exceptions and wraps them in
|
|
32
|
+
# `Treaty::Exceptions::Execution`.
|
|
33
|
+
#
|
|
34
|
+
# ## Execution Flow
|
|
35
|
+
#
|
|
36
|
+
# 1. Resolve executor (constantize string if needed)
|
|
37
|
+
# 2. Build call parameters (params + optional inventory)
|
|
38
|
+
# 3. Execute via appropriate method:
|
|
39
|
+
# - Proc: `executor.call(**params)`
|
|
40
|
+
# - Servactory: `executor.call!(**params)`
|
|
41
|
+
# - Regular: `executor.public_send(method, **params)`
|
|
42
|
+
# 4. Extract data from result (handles `.data` accessor)
|
|
43
|
+
#
|
|
44
|
+
# ## Example
|
|
45
|
+
#
|
|
46
|
+
# result = Execution::Request.execute!(
|
|
47
|
+
# version_factory: factory,
|
|
48
|
+
# validated_params: { post: { title: "Hello" } },
|
|
49
|
+
# inventory: inventory_collection,
|
|
50
|
+
# context: controller
|
|
51
|
+
# )
|
|
52
|
+
class Request # rubocop:disable Metrics/ClassLength
|
|
53
|
+
# Executes service with validated parameters (class method shortcut)
|
|
54
|
+
#
|
|
55
|
+
# @param version_factory [Treaty::Action::Versions::Factory] Version configuration
|
|
56
|
+
# @param validated_params [Hash] Validated request parameters
|
|
57
|
+
# @param inventory [Treaty::Action::Inventory::Collection, nil] Optional inventory
|
|
58
|
+
# @param context [Object, nil] Controller context for inventory
|
|
59
|
+
# @return [Hash] Service execution result
|
|
60
|
+
# @raise [Treaty::Exceptions::Execution] If execution fails
|
|
61
|
+
def self.execute!(...)
|
|
62
|
+
new(...).execute!
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Creates a new execution request instance
|
|
66
|
+
#
|
|
67
|
+
# @param version_factory [Treaty::Action::Versions::Factory] Version with executor configuration
|
|
68
|
+
# @param validated_params [Hash] Validated request parameters
|
|
69
|
+
# @param inventory [Treaty::Action::Inventory::Collection, nil] Optional inventory
|
|
70
|
+
# @param context [Object, nil] Controller context for inventory evaluation
|
|
71
|
+
def initialize(version_factory:, validated_params:, inventory: nil, context: nil)
|
|
72
|
+
@inventory = inventory
|
|
73
|
+
@context = context
|
|
74
|
+
@version_factory = version_factory
|
|
75
|
+
@validated_params = validated_params
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Executes the service and returns result
|
|
79
|
+
#
|
|
80
|
+
# @return [Hash] Execution result data
|
|
81
|
+
# @raise [Treaty::Exceptions::Execution] If executor missing or fails
|
|
82
|
+
def execute!
|
|
83
|
+
raise_executor_missing_error! if @version_factory.executor.nil?
|
|
84
|
+
|
|
85
|
+
extract_data_from_result
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# Extracts data from execution result
|
|
91
|
+
#
|
|
92
|
+
# Handles different result types:
|
|
93
|
+
# - Proc results returned directly
|
|
94
|
+
# - Objects with `.data` accessor unwrapped
|
|
95
|
+
# - Other results returned directly
|
|
96
|
+
#
|
|
97
|
+
# @return [Object] Extracted result data
|
|
98
|
+
def extract_data_from_result
|
|
99
|
+
return execution_result if executor.is_a?(Proc)
|
|
100
|
+
return execution_result.data if execution_result.respond_to?(:data)
|
|
101
|
+
|
|
102
|
+
execution_result
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
########################################################################
|
|
106
|
+
|
|
107
|
+
# Executes and caches the service result
|
|
108
|
+
#
|
|
109
|
+
# @return [Object] Raw execution result
|
|
110
|
+
def execution_result
|
|
111
|
+
@execution_result ||=
|
|
112
|
+
if executor.is_a?(Proc)
|
|
113
|
+
execute_proc
|
|
114
|
+
elsif servactory_service?
|
|
115
|
+
execute_servactory
|
|
116
|
+
else
|
|
117
|
+
execute_regular_class
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
########################################################################
|
|
122
|
+
|
|
123
|
+
# Returns resolved executor (cached)
|
|
124
|
+
#
|
|
125
|
+
# @return [Class, Proc] Resolved executor
|
|
126
|
+
def executor
|
|
127
|
+
@executor ||= resolve_executor(@version_factory.executor.executor)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
########################################################################
|
|
131
|
+
|
|
132
|
+
# Resolves executor from various input types
|
|
133
|
+
#
|
|
134
|
+
# @param executor [Class, String, Symbol, Proc] Executor reference
|
|
135
|
+
# @return [Class, Proc] Resolved executor
|
|
136
|
+
# @raise [Treaty::Exceptions::Execution] If resolution fails
|
|
137
|
+
def resolve_executor(executor) # rubocop:disable Metrics/MethodLength
|
|
138
|
+
return executor if executor.is_a?(Proc) || executor.is_a?(Class)
|
|
139
|
+
|
|
140
|
+
if executor.is_a?(String) || executor.is_a?(Symbol)
|
|
141
|
+
string_executor = executor.to_s
|
|
142
|
+
|
|
143
|
+
if string_executor.empty?
|
|
144
|
+
raise Treaty::Exceptions::Execution,
|
|
145
|
+
I18n.t("treaty.execution.executor_empty")
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
constant_name = normalize_constant_name(executor)
|
|
149
|
+
|
|
150
|
+
begin
|
|
151
|
+
constant_name.constantize
|
|
152
|
+
rescue NameError
|
|
153
|
+
raise Treaty::Exceptions::Execution,
|
|
154
|
+
I18n.t("treaty.execution.executor_not_found", class_name: constant_name)
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
raise Treaty::Exceptions::Execution,
|
|
158
|
+
I18n.t("treaty.execution.executor_invalid_type", type: executor.class)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
########################################################################
|
|
163
|
+
|
|
164
|
+
# Normalizes string/symbol to constant name
|
|
165
|
+
#
|
|
166
|
+
# Handles path-style strings like "posts/create_service"
|
|
167
|
+
# converting to "Posts::CreateService".
|
|
168
|
+
#
|
|
169
|
+
# @param name [String, Symbol] Name to normalize
|
|
170
|
+
# @return [String] Constant name
|
|
171
|
+
def normalize_constant_name(name)
|
|
172
|
+
string = name.to_s
|
|
173
|
+
|
|
174
|
+
return string if string.include?("::")
|
|
175
|
+
return string.split("/").map(&:camelize).join("::") if string.include?("/")
|
|
176
|
+
|
|
177
|
+
string
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
########################################################################
|
|
181
|
+
########################################################################
|
|
182
|
+
########################################################################
|
|
183
|
+
|
|
184
|
+
# Creates inventory executor for lazy evaluation
|
|
185
|
+
#
|
|
186
|
+
# @return [Treaty::Action::Executor::Inventory] Inventory executor
|
|
187
|
+
def evaluated_inventory
|
|
188
|
+
@evaluated_inventory ||= Treaty::Action::Executor::Inventory.new(@inventory, @context)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
########################################################################
|
|
192
|
+
|
|
193
|
+
# Executes Proc executor
|
|
194
|
+
#
|
|
195
|
+
# @return [Object] Proc result
|
|
196
|
+
# @raise [Treaty::Exceptions::Execution] If proc raises error
|
|
197
|
+
def execute_proc
|
|
198
|
+
executor.call(**build_call_params)
|
|
199
|
+
rescue StandardError => e
|
|
200
|
+
raise Treaty::Exceptions::Execution,
|
|
201
|
+
I18n.t("treaty.execution.proc_error", message: e.message)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Executes Servactory service
|
|
205
|
+
#
|
|
206
|
+
# Uses `call!` method and catches Servactory-specific exceptions.
|
|
207
|
+
#
|
|
208
|
+
# @return [Object] Service result
|
|
209
|
+
# @raise [Treaty::Exceptions::Execution] If service raises error
|
|
210
|
+
def execute_servactory # rubocop:disable Metrics/MethodLength
|
|
211
|
+
executor.call!(**build_call_params)
|
|
212
|
+
rescue Servactory::Exceptions::Input => e
|
|
213
|
+
raise Treaty::Exceptions::Execution,
|
|
214
|
+
I18n.t("treaty.execution.servactory_input_error", message: e.message)
|
|
215
|
+
rescue Servactory::Exceptions::Internal => e
|
|
216
|
+
raise Treaty::Exceptions::Execution,
|
|
217
|
+
I18n.t("treaty.execution.servactory_internal_error", message: e.message)
|
|
218
|
+
rescue Servactory::Exceptions::Output => e
|
|
219
|
+
raise Treaty::Exceptions::Execution,
|
|
220
|
+
I18n.t("treaty.execution.servactory_output_error", message: e.message)
|
|
221
|
+
rescue Servactory::Exceptions::Failure => e
|
|
222
|
+
raise Treaty::Exceptions::Execution,
|
|
223
|
+
I18n.t("treaty.execution.servactory_failure_error", message: e.message)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Executes regular class with configured method
|
|
227
|
+
#
|
|
228
|
+
# @return [Object] Method result
|
|
229
|
+
# @raise [Treaty::Exceptions::Execution] If method missing or raises error
|
|
230
|
+
def execute_regular_class # rubocop:disable Metrics/MethodLength
|
|
231
|
+
method_name = @version_factory.executor.method
|
|
232
|
+
|
|
233
|
+
unless executor.respond_to?(method_name)
|
|
234
|
+
raise Treaty::Exceptions::Execution,
|
|
235
|
+
I18n.t(
|
|
236
|
+
"treaty.execution.method_not_found",
|
|
237
|
+
method: method_name,
|
|
238
|
+
class_name: executor
|
|
239
|
+
)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
executor.public_send(method_name, **build_call_params)
|
|
243
|
+
rescue StandardError => e
|
|
244
|
+
raise Treaty::Exceptions::Execution,
|
|
245
|
+
I18n.t("treaty.execution.regular_service_error", message: e.message)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
########################################################################
|
|
249
|
+
########################################################################
|
|
250
|
+
########################################################################
|
|
251
|
+
|
|
252
|
+
# Builds parameters hash for service call
|
|
253
|
+
#
|
|
254
|
+
# Includes validated params and optionally inventory if defined.
|
|
255
|
+
#
|
|
256
|
+
# @return [Hash] Call parameters
|
|
257
|
+
def build_call_params
|
|
258
|
+
if @inventory&.exists?
|
|
259
|
+
{ params: @validated_params, inventory: evaluated_inventory }
|
|
260
|
+
else
|
|
261
|
+
{ params: @validated_params }
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Raises error when executor not configured
|
|
266
|
+
#
|
|
267
|
+
# @raise [Treaty::Exceptions::Execution]
|
|
268
|
+
def raise_executor_missing_error!
|
|
269
|
+
raise Treaty::Exceptions::Execution,
|
|
270
|
+
I18n.t(
|
|
271
|
+
"treaty.execution.executor_missing",
|
|
272
|
+
version: @version_factory.version
|
|
273
|
+
)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Checks if executor is a Servactory service
|
|
277
|
+
#
|
|
278
|
+
# @return [Boolean] True if executor responds to servactory?
|
|
279
|
+
def servactory_service?
|
|
280
|
+
executor.respond_to?(:servactory?) &&
|
|
281
|
+
executor.servactory?
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Action
|
|
5
|
+
module Versions
|
|
6
|
+
# Value object holding executor reference and method name.
|
|
7
|
+
#
|
|
8
|
+
# ## Purpose
|
|
9
|
+
#
|
|
10
|
+
# Stores the service class/proc and method name configured via
|
|
11
|
+
# `delegate_to` in version definitions. Separates executor
|
|
12
|
+
# configuration from execution logic.
|
|
13
|
+
#
|
|
14
|
+
# ## Usage
|
|
15
|
+
#
|
|
16
|
+
# Created by:
|
|
17
|
+
# - Versions::Factory (when `delegate_to` is called)
|
|
18
|
+
#
|
|
19
|
+
# Consumed by:
|
|
20
|
+
# - Versions::Execution::Request (to execute the service)
|
|
21
|
+
#
|
|
22
|
+
# ## Executor Types
|
|
23
|
+
#
|
|
24
|
+
# The `executor` attribute can hold:
|
|
25
|
+
# - Class reference: `Posts::CreateService`
|
|
26
|
+
# - String path: `"posts/create_service"`
|
|
27
|
+
# - Proc/Lambda: `->(params:) { ... }`
|
|
28
|
+
#
|
|
29
|
+
# ## Method Attribute
|
|
30
|
+
#
|
|
31
|
+
# The `method` attribute specifies which method to call:
|
|
32
|
+
# - Default: `:call`
|
|
33
|
+
# - Custom: specified via hash syntax `delegate_to Service => :perform`
|
|
34
|
+
#
|
|
35
|
+
# ## Example
|
|
36
|
+
#
|
|
37
|
+
# # In version definition:
|
|
38
|
+
# delegate_to Posts::CreateService # method defaults to :call
|
|
39
|
+
# delegate_to Posts::CreateService => :call! # explicit method
|
|
40
|
+
#
|
|
41
|
+
# # Creates:
|
|
42
|
+
# Executor.new(Posts::CreateService, :call)
|
|
43
|
+
class Executor
|
|
44
|
+
# @return [Class, String, Proc] Service class, path string, or proc
|
|
45
|
+
attr_reader :executor
|
|
46
|
+
|
|
47
|
+
# @return [Symbol] Method name to call on executor
|
|
48
|
+
attr_reader :method
|
|
49
|
+
|
|
50
|
+
# Creates a new executor value object
|
|
51
|
+
#
|
|
52
|
+
# @param executor [Class, String, Proc] Service reference
|
|
53
|
+
# @param method [Symbol] Method to invoke (default: :call)
|
|
54
|
+
def initialize(executor, method)
|
|
55
|
+
@executor = executor
|
|
56
|
+
@method = method
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|