service_actor 3.9.4 → 4.0.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 +31 -18
- data/lib/service_actor/arguments_validator.rb +9 -0
- data/lib/service_actor/attributable.rb +8 -0
- data/lib/service_actor/checkable.rb +1 -2
- data/lib/service_actor/checks/base.rb +0 -6
- data/lib/service_actor/checks/type_check.rb +2 -2
- data/lib/service_actor/defaultable.rb +9 -44
- data/lib/service_actor/playable.rb +9 -1
- data/lib/service_actor/result.rb +1 -3
- data/lib/service_actor/version.rb +1 -1
- metadata +18 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86aa1f5411838fa24961e50eff4138d414c86aa99c7bdc5907953f7643406431
|
4
|
+
data.tar.gz: 1e0c82c0ba0e3b3c8278fa7d286454f891266972d34144b2ee3aa18a2bddd20d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed8bfce6061647dee123bfdecc2a89f92cb7b4fc09664bef3671d722e59605787acfe3ceb9822b785a4a0ed651b315a9c27a38366516cbeadef9403d92c49709
|
7
|
+
data.tar.gz: 9dec2bb8b9d5815c1c8d39108432003575f2f5a9a9431c93c69228c2c13f776eea60794696328e2d9ebc6e13849e2fa3e6db3e6e3ac337c03a39d29b24c578ea
|
data/README.md
CHANGED
@@ -314,20 +314,20 @@ end
|
|
314
314
|
|
315
315
|
### Defaults
|
316
316
|
|
317
|
-
Inputs can be optional by providing a `default` value
|
317
|
+
Inputs can be optional by providing a `default` value in a lambda.
|
318
318
|
|
319
319
|
```rb
|
320
320
|
class BuildGreeting < Actor
|
321
321
|
input :name
|
322
|
-
input :adjective, default: "wonderful"
|
322
|
+
input :adjective, default: -> { "wonderful" }
|
323
323
|
input :length_of_time, default: -> { ["day", "week", "month"].sample }
|
324
324
|
input :article,
|
325
|
-
default: ->
|
325
|
+
default: -> actor { actor.adjective.match?(/^[aeiou]/) ? "an" : "a" }
|
326
326
|
|
327
327
|
output :greeting
|
328
328
|
|
329
329
|
def call
|
330
|
-
self.greeting = "Have #{article} #{length_of_time}, #{name}!"
|
330
|
+
self.greeting = "Have #{article} #{adjective} #{length_of_time}, #{name}!"
|
331
331
|
end
|
332
332
|
end
|
333
333
|
|
@@ -338,6 +338,33 @@ actor = BuildGreeting.call(name: "Siobhan", adjective: "elegant")
|
|
338
338
|
actor.greeting # => "Have an elegant week, Siobhan!"
|
339
339
|
```
|
340
340
|
|
341
|
+
While lambdas are the preferred way to specify defaults, you can also provide
|
342
|
+
a default value without using lambdas by using an immutable object.
|
343
|
+
|
344
|
+
```rb
|
345
|
+
# frozen_string_literal: true
|
346
|
+
|
347
|
+
class ExampleActor < Actor
|
348
|
+
input :options, default: {
|
349
|
+
names: {male: "Iaroslav", female: "Anna"}.freeze,
|
350
|
+
country_codes: %w[gb ru].freeze
|
351
|
+
}.freeze
|
352
|
+
end
|
353
|
+
```
|
354
|
+
|
355
|
+
Note that default values might be mutated if the values returned by the lambda
|
356
|
+
are references to mutable objects, e.g.
|
357
|
+
|
358
|
+
```rb
|
359
|
+
class ExampleActor < Actor
|
360
|
+
input :options, default: -> { Registry::DEFAULT_OPTIONS } # `Registry::DEFAULT_OPTIONS` is not frozen
|
361
|
+
|
362
|
+
def call
|
363
|
+
options[:names] = nil
|
364
|
+
end
|
365
|
+
end
|
366
|
+
```
|
367
|
+
|
341
368
|
### Allow nil
|
342
369
|
|
343
370
|
By default inputs accept `nil` values. To raise an error instead:
|
@@ -471,20 +498,6 @@ end
|
|
471
498
|
end
|
472
499
|
```
|
473
500
|
|
474
|
-
#### Default
|
475
|
-
|
476
|
-
```ruby
|
477
|
-
class MultiplyThing < Actor
|
478
|
-
input :multiplier,
|
479
|
-
default: {
|
480
|
-
is: -> { rand(1..10) },
|
481
|
-
message: (lambda do |input_key:, **|
|
482
|
-
"Input \"#{input_key}\" is required"
|
483
|
-
end)
|
484
|
-
}
|
485
|
-
end
|
486
|
-
```
|
487
|
-
|
488
501
|
#### Type
|
489
502
|
|
490
503
|
```ruby
|
@@ -16,4 +16,13 @@ module ServiceActor::ArgumentsValidator
|
|
16
16
|
|
17
17
|
raise ArgumentError, "Expected #{value} to be a subclass of Exception"
|
18
18
|
end
|
19
|
+
|
20
|
+
def validate_default_value(value, origin_type:, origin_name:, actor:)
|
21
|
+
return if value.is_a?(Proc) || !defined?(Ractor.shareable?) || Ractor.shareable?(value)
|
22
|
+
|
23
|
+
::Kernel.warn(
|
24
|
+
"DEPRECATED: Actor `#{actor}` has #{origin_type} `#{origin_name}` with default " \
|
25
|
+
"which is not a Proc or an immutable object.",
|
26
|
+
)
|
27
|
+
end
|
19
28
|
end
|
@@ -26,6 +26,10 @@ module ServiceActor::Attributable
|
|
26
26
|
name, origin: :input
|
27
27
|
)
|
28
28
|
|
29
|
+
ServiceActor::ArgumentsValidator.validate_default_value(
|
30
|
+
arguments[:default], actor: self, origin_type: :input, origin_name: name
|
31
|
+
)
|
32
|
+
|
29
33
|
inputs[name] = arguments
|
30
34
|
|
31
35
|
define_method(name) do
|
@@ -47,6 +51,10 @@ module ServiceActor::Attributable
|
|
47
51
|
name, origin: :output
|
48
52
|
)
|
49
53
|
|
54
|
+
ServiceActor::ArgumentsValidator.validate_default_value(
|
55
|
+
arguments[:default], actor: self, origin_type: :output, origin_name: name
|
56
|
+
)
|
57
|
+
|
50
58
|
outputs[name] = arguments
|
51
59
|
|
52
60
|
define_method(name) do
|
@@ -31,10 +31,9 @@ module ServiceActor::Checkable
|
|
31
31
|
|
32
32
|
# rubocop:disable Metrics/MethodLength
|
33
33
|
def service_actor_checks_for(origin)
|
34
|
-
check_classes = CHECK_CLASSES.select { _1.applicable_to_origin?(origin) }
|
35
34
|
self.class.public_send(:"#{origin}s").each do |input_key, input_options|
|
36
35
|
input_options.each do |check_name, check_conditions|
|
37
|
-
|
36
|
+
CHECK_CLASSES.each do |check_class|
|
38
37
|
argument_errors = check_class.check(
|
39
38
|
check_name: check_name,
|
40
39
|
origin: origin,
|
@@ -72,14 +72,14 @@ class ServiceActor::Checks::TypeCheck < ServiceActor::Checks::Base
|
|
72
72
|
|
73
73
|
types, message = define_types_and_message
|
74
74
|
|
75
|
-
return if types.any? { |type| @given_type
|
75
|
+
return if types.any? { |type| type === @given_type }
|
76
76
|
|
77
77
|
add_argument_error(
|
78
78
|
message,
|
79
79
|
origin: @origin,
|
80
80
|
input_key: @input_key,
|
81
81
|
actor: @actor,
|
82
|
-
expected_type: types.join(", "),
|
82
|
+
expected_type: types.map(&:name).join(", "),
|
83
83
|
given_type: @given_type.class,
|
84
84
|
)
|
85
85
|
end
|
@@ -9,22 +9,6 @@
|
|
9
9
|
# input :counter, default: 1
|
10
10
|
# input :multiplier, default: -> { rand(1..10) }
|
11
11
|
# end
|
12
|
-
#
|
13
|
-
# class MultiplyThing < Actor
|
14
|
-
# input :counter,
|
15
|
-
# default: {
|
16
|
-
# is: 1,
|
17
|
-
# message: "Counter is required"
|
18
|
-
# }
|
19
|
-
#
|
20
|
-
# input :multiplier,
|
21
|
-
# default: {
|
22
|
-
# is: -> { rand(1..10) },
|
23
|
-
# message: (lambda do |input_key:, actor:|
|
24
|
-
# "Input \"#{input_key}\" is required"
|
25
|
-
# end)
|
26
|
-
# }
|
27
|
-
# end
|
28
12
|
module ServiceActor::Defaultable
|
29
13
|
class << self
|
30
14
|
def included(base)
|
@@ -43,19 +27,13 @@ module ServiceActor::Defaultable
|
|
43
27
|
)
|
44
28
|
end
|
45
29
|
|
46
|
-
|
47
|
-
|
48
|
-
if default.is_a?(Hash) && default[:is]
|
49
|
-
default_for_advanced_mode_with(result, key, default)
|
50
|
-
else
|
51
|
-
default_for_normal_mode_with(result, key, default)
|
52
|
-
end
|
30
|
+
apply_default_for_origin(key, input)
|
53
31
|
end
|
54
32
|
|
55
|
-
self.class.outputs.each do |key,
|
56
|
-
|
57
|
-
|
58
|
-
|
33
|
+
self.class.outputs.each do |key, output|
|
34
|
+
next if result.key?(key)
|
35
|
+
|
36
|
+
apply_default_for_origin(key, output)
|
59
37
|
end
|
60
38
|
|
61
39
|
super
|
@@ -63,26 +41,13 @@ module ServiceActor::Defaultable
|
|
63
41
|
|
64
42
|
private
|
65
43
|
|
66
|
-
def
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def default_for_advanced_mode_with(result, key, content)
|
71
|
-
default, message = content.values_at(:is, :message)
|
44
|
+
def apply_default_for_origin(origin_name, origin_options)
|
45
|
+
default = origin_options[:default]
|
72
46
|
|
73
|
-
|
74
|
-
raise_error_with(message, input_key: key, actor: self.class)
|
75
|
-
end
|
76
|
-
|
77
|
-
result[key] = reify_default(result, default)
|
78
|
-
|
79
|
-
message.call(key, self.class)
|
47
|
+
result[origin_name] = reify_default(result, default)
|
80
48
|
end
|
81
49
|
|
82
|
-
|
83
|
-
def raise_error_with(message, **arguments)
|
84
|
-
message = message.call(**arguments) if message.is_a?(Proc)
|
85
|
-
|
50
|
+
def raise_error_with(message)
|
86
51
|
raise self.class.argument_error_class, message
|
87
52
|
end
|
88
53
|
|
@@ -90,7 +90,15 @@ module ServiceActor::Playable
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def play_actor(actor)
|
93
|
-
|
93
|
+
actor_includes_kernel = begin
|
94
|
+
actor.respond_to?(:is_a?)
|
95
|
+
rescue NoMethodError
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
if !actor_includes_kernel
|
100
|
+
actor.call(result)
|
101
|
+
elsif actor.is_a?(Symbol)
|
94
102
|
send(actor)
|
95
103
|
elsif actor.is_a?(Class) && actor.ancestors.include?(ServiceActor::Core)
|
96
104
|
play_service_actor(actor)
|
data/lib/service_actor/result.rb
CHANGED
@@ -124,9 +124,7 @@ class ServiceActor::Result < BasicObject
|
|
124
124
|
# Key `_default_output` is an internal datum used by actor class
|
125
125
|
# method `.valuable`. Don't expose it with the rest of the result.
|
126
126
|
def filter_default_output(h)
|
127
|
-
|
128
|
-
# update once support for 2.7 is dropped
|
129
|
-
h.filter { |k| k != :_default_output }
|
127
|
+
h.except(:_default_output)
|
130
128
|
end
|
131
129
|
|
132
130
|
def respond_to_missing?(method_name, _include_private = false)
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: service_actor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sunny Ripert
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-24 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: zeitwerk
|
@@ -206,6 +205,20 @@ dependencies:
|
|
206
205
|
- - ">="
|
207
206
|
- !ruby/object:Gem::Version
|
208
207
|
version: '0.0'
|
208
|
+
- !ruby/object:Gem::Dependency
|
209
|
+
name: ostruct
|
210
|
+
requirement: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - ">="
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '0.0'
|
215
|
+
type: :development
|
216
|
+
prerelease: false
|
217
|
+
version_requirements: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0.0'
|
209
222
|
description: Service objects for your application logic
|
210
223
|
email:
|
211
224
|
- sunny@sunfox.org
|
@@ -247,7 +260,6 @@ metadata:
|
|
247
260
|
source_code_uri: https://github.com/sunny/actor
|
248
261
|
changelog_uri: https://github.com/sunny/actor/blob/main/CHANGELOG.md
|
249
262
|
rubygems_mfa_required: 'true'
|
250
|
-
post_install_message:
|
251
263
|
rdoc_options: []
|
252
264
|
require_paths:
|
253
265
|
- lib
|
@@ -255,15 +267,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
255
267
|
requirements:
|
256
268
|
- - ">="
|
257
269
|
- !ruby/object:Gem::Version
|
258
|
-
version: '
|
270
|
+
version: '3.0'
|
259
271
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
260
272
|
requirements:
|
261
273
|
- - ">="
|
262
274
|
- !ruby/object:Gem::Version
|
263
275
|
version: '0'
|
264
276
|
requirements: []
|
265
|
-
rubygems_version: 3.
|
266
|
-
signing_key:
|
277
|
+
rubygems_version: 3.6.5
|
267
278
|
specification_version: 4
|
268
279
|
summary: Service objects for your application logic
|
269
280
|
test_files: []
|