service_actor 3.6.1 → 3.8.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 +187 -178
- data/lib/service_actor/arguments_validator.rb +18 -0
- data/lib/service_actor/attributable.rb +17 -7
- data/lib/service_actor/base.rb +12 -10
- data/lib/service_actor/checkable.rb +14 -13
- data/lib/service_actor/checks/base.rb +6 -0
- data/lib/service_actor/checks/inclusion_check.rb +13 -10
- data/lib/service_actor/checks/must_check.rb +11 -8
- data/lib/service_actor/checks/nil_check.rb +20 -17
- data/lib/service_actor/checks/type_check.rb +22 -18
- data/lib/service_actor/configurable.rb +17 -3
- data/lib/service_actor/core.rb +4 -2
- data/lib/service_actor/defaultable.rb +19 -7
- data/lib/service_actor/failable.rb +9 -3
- data/lib/service_actor/playable.rb +22 -16
- data/lib/service_actor/result.rb +75 -32
- data/lib/service_actor/version.rb +1 -1
- metadata +63 -27
- data/lib/service_actor/checks/default_check.rb +0 -90
@@ -35,23 +35,25 @@ class ServiceActor::Checks::NilCheck < ServiceActor::Checks::Base
|
|
35
35
|
|
36
36
|
private_constant :DEFAULT_MESSAGE
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
38
|
+
class << self
|
39
|
+
def check(
|
40
|
+
origin:,
|
41
|
+
input_key:,
|
42
|
+
input_options:,
|
43
|
+
actor:,
|
44
|
+
conditions:,
|
45
|
+
result:,
|
46
|
+
**
|
47
|
+
) # do
|
48
|
+
new(
|
49
|
+
origin: origin,
|
50
|
+
input_key: input_key,
|
51
|
+
input_options: input_options,
|
52
|
+
actor: actor,
|
53
|
+
allow_nil: conditions,
|
54
|
+
value: result[input_key],
|
55
|
+
).check
|
56
|
+
end
|
55
57
|
end
|
56
58
|
|
57
59
|
def initialize( # rubocop:disable Metrics/ParameterLists
|
@@ -92,6 +94,7 @@ class ServiceActor::Checks::NilCheck < ServiceActor::Checks::Base
|
|
92
94
|
|
93
95
|
def define_allow_nil_and_message_from(allow_nil)
|
94
96
|
if allow_nil.is_a?(Hash)
|
97
|
+
allow_nil[:message] ||= DEFAULT_MESSAGE
|
95
98
|
allow_nil.values_at(:is, :message)
|
96
99
|
else
|
97
100
|
[allow_nil, DEFAULT_MESSAGE]
|
@@ -34,24 +34,26 @@ class ServiceActor::Checks::TypeCheck < ServiceActor::Checks::Base
|
|
34
34
|
|
35
35
|
private_constant :DEFAULT_MESSAGE
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
37
|
+
class << self
|
38
|
+
def check(
|
39
|
+
check_name:,
|
40
|
+
origin:,
|
41
|
+
input_key:,
|
42
|
+
actor:,
|
43
|
+
conditions:,
|
44
|
+
result:,
|
45
|
+
**
|
46
|
+
) # do
|
47
|
+
return unless check_name == :type
|
48
|
+
|
49
|
+
new(
|
50
|
+
origin: origin,
|
51
|
+
input_key: input_key,
|
52
|
+
actor: actor,
|
53
|
+
type_definition: conditions,
|
54
|
+
given_type: result[input_key],
|
55
|
+
).check
|
56
|
+
end
|
55
57
|
end
|
56
58
|
|
57
59
|
def initialize(origin:, input_key:, actor:, type_definition:, given_type:)
|
@@ -86,6 +88,8 @@ class ServiceActor::Checks::TypeCheck < ServiceActor::Checks::Base
|
|
86
88
|
|
87
89
|
def define_types_and_message
|
88
90
|
if @type_definition.is_a?(Hash)
|
91
|
+
@type_definition[:message] ||= DEFAULT_MESSAGE
|
92
|
+
|
89
93
|
@type_definition, message =
|
90
94
|
@type_definition.values_at(:is, :message)
|
91
95
|
else
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ServiceActor::Configurable
|
4
|
-
|
5
|
-
base
|
4
|
+
class << self
|
5
|
+
def included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
6
8
|
end
|
7
9
|
|
8
10
|
module ClassMethods
|
@@ -15,6 +17,18 @@ module ServiceActor::Configurable
|
|
15
17
|
child.failure_class = failure_class || ServiceActor::Failure
|
16
18
|
end
|
17
19
|
|
18
|
-
|
20
|
+
def argument_error_class=(value)
|
21
|
+
ServiceActor::ArgumentsValidator.validate_error_class(value)
|
22
|
+
|
23
|
+
@argument_error_class = value
|
24
|
+
end
|
25
|
+
|
26
|
+
def failure_class=(value)
|
27
|
+
ServiceActor::ArgumentsValidator.validate_error_class(value)
|
28
|
+
|
29
|
+
@failure_class = value
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :argument_error_class, :failure_class
|
19
33
|
end
|
20
34
|
end
|
data/lib/service_actor/core.rb
CHANGED
@@ -26,8 +26,10 @@
|
|
26
26
|
# }
|
27
27
|
# end
|
28
28
|
module ServiceActor::Defaultable
|
29
|
-
|
30
|
-
base
|
29
|
+
class << self
|
30
|
+
def included(base)
|
31
|
+
base.prepend(PrependedMethods)
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
35
|
module PrependedMethods
|
@@ -43,21 +45,26 @@ module ServiceActor::Defaultable
|
|
43
45
|
|
44
46
|
default = input[:default]
|
45
47
|
|
46
|
-
if default.is_a?(Hash)
|
48
|
+
if default.is_a?(Hash) && default[:is]
|
47
49
|
default_for_advanced_mode_with(result, key, default)
|
48
50
|
else
|
49
51
|
default_for_normal_mode_with(result, key, default)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
55
|
+
self.class.outputs.each do |key, options|
|
56
|
+
unless result.key?(key)
|
57
|
+
result.send(:"#{key}=", options[:default])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
53
61
|
super
|
54
62
|
end
|
55
63
|
|
56
64
|
private
|
57
65
|
|
58
66
|
def default_for_normal_mode_with(result, key, default)
|
59
|
-
|
60
|
-
result[key] = default
|
67
|
+
result[key] = reify_default(result, default)
|
61
68
|
end
|
62
69
|
|
63
70
|
def default_for_advanced_mode_with(result, key, content)
|
@@ -67,8 +74,7 @@ module ServiceActor::Defaultable
|
|
67
74
|
raise_error_with(message, input_key: key, actor: self.class)
|
68
75
|
end
|
69
76
|
|
70
|
-
|
71
|
-
result[key] = default
|
77
|
+
result[key] = reify_default(result, default)
|
72
78
|
|
73
79
|
message.call(key, self.class)
|
74
80
|
end
|
@@ -79,5 +85,11 @@ module ServiceActor::Defaultable
|
|
79
85
|
|
80
86
|
raise self.class.argument_error_class, message
|
81
87
|
end
|
88
|
+
|
89
|
+
def reify_default(result, default)
|
90
|
+
return default unless default.is_a?(Proc)
|
91
|
+
|
92
|
+
default.arity.zero? ? default.call : default.call(result)
|
93
|
+
end
|
82
94
|
end
|
83
95
|
end
|
@@ -7,9 +7,11 @@
|
|
7
7
|
# fail_on ServiceActor::ArgumentError
|
8
8
|
# end
|
9
9
|
module ServiceActor::Failable
|
10
|
-
|
11
|
-
base
|
12
|
-
|
10
|
+
class << self
|
11
|
+
def included(base)
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
base.prepend(PrependedMethods)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
17
|
module ClassMethods
|
@@ -20,6 +22,10 @@ module ServiceActor::Failable
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def fail_on(*exceptions)
|
25
|
+
exceptions.each do |exception|
|
26
|
+
ServiceActor::ArgumentsValidator.validate_error_class(exception)
|
27
|
+
end
|
28
|
+
|
23
29
|
fail_ons.push(*exceptions)
|
24
30
|
end
|
25
31
|
|
@@ -9,9 +9,11 @@
|
|
9
9
|
# SendWelcomeEmail
|
10
10
|
# end
|
11
11
|
module ServiceActor::Playable
|
12
|
-
|
13
|
-
base
|
14
|
-
|
12
|
+
class << self
|
13
|
+
def included(base)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
base.prepend(PrependedMethods)
|
16
|
+
end
|
15
17
|
end
|
16
18
|
|
17
19
|
module ClassMethods
|
@@ -20,6 +22,12 @@ module ServiceActor::Playable
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def alias_input(**options)
|
25
|
+
options.each_key do |new|
|
26
|
+
ServiceActor::ArgumentsValidator.validate_origin_name(
|
27
|
+
new, origin: :alias
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
23
31
|
lambda do |actor|
|
24
32
|
options.each do |new, original|
|
25
33
|
define_alias_input(actor, new, original)
|
@@ -39,24 +47,15 @@ module ServiceActor::Playable
|
|
39
47
|
|
40
48
|
private
|
41
49
|
|
42
|
-
def define_alias_input(actor,
|
43
|
-
actor[
|
44
|
-
actor.instance_exec do
|
45
|
-
[original, new].each do |method|
|
46
|
-
singleton_class.send(:undef_method, "#{method}=")
|
47
|
-
define_singleton_method("#{method}=") do |v|
|
48
|
-
actor[original] = v
|
49
|
-
actor[new] = v
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
50
|
+
def define_alias_input(actor, new_input, original_input)
|
51
|
+
actor[new_input] = actor.delete!(original_input)
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
56
55
|
module PrependedMethods
|
57
56
|
def call
|
58
57
|
self.class.play_actors.each do |options|
|
59
|
-
next
|
58
|
+
next unless callable_actor?(options)
|
60
59
|
|
61
60
|
options[:actors].each { |actor| play_actor(actor) }
|
62
61
|
end
|
@@ -77,6 +76,13 @@ module ServiceActor::Playable
|
|
77
76
|
|
78
77
|
private
|
79
78
|
|
79
|
+
def callable_actor?(options)
|
80
|
+
return false if options[:if] && !options[:if].call(result)
|
81
|
+
return false if options[:unless]&.call(result)
|
82
|
+
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
80
86
|
def play_actor(actor)
|
81
87
|
play_service_actor(actor) ||
|
82
88
|
play_method(actor) ||
|
@@ -106,7 +112,7 @@ module ServiceActor::Playable
|
|
106
112
|
return unless actor.is_a?(Class)
|
107
113
|
return unless actor.ancestors.map(&:name).include?("Interactor")
|
108
114
|
|
109
|
-
result.merge!(actor.call(result).to_h)
|
115
|
+
result.merge!(actor.call(result.to_h).to_h)
|
110
116
|
end
|
111
117
|
end
|
112
118
|
end
|
data/lib/service_actor/result.rb
CHANGED
@@ -1,30 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "ostruct"
|
4
|
-
|
5
3
|
# Represents the context of an actor, holding the data from both its inputs
|
6
4
|
# and outputs.
|
7
|
-
class ServiceActor::Result <
|
8
|
-
|
9
|
-
|
5
|
+
class ServiceActor::Result < BasicObject
|
6
|
+
class << self
|
7
|
+
def to_result(data)
|
8
|
+
return data if data.is_a?(self)
|
9
|
+
|
10
|
+
new(data.to_h)
|
11
|
+
end
|
12
|
+
end
|
10
13
|
|
11
|
-
|
14
|
+
%i[class is_a? kind_of? send tap then block_given?].each do |method_name|
|
15
|
+
define_method(method_name, ::Kernel.instance_method(method_name))
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :yield_self, :then
|
19
|
+
|
20
|
+
def initialize(data = {})
|
21
|
+
@data = data.to_h
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_h
|
25
|
+
data
|
12
26
|
end
|
13
27
|
|
14
28
|
def inspect
|
15
29
|
"<#{self.class.name} #{to_h}>"
|
16
30
|
end
|
17
31
|
|
32
|
+
alias_method :pretty_print, :inspect
|
33
|
+
|
18
34
|
def fail!(failure_class = nil, result = {})
|
19
|
-
if failure_class.nil? || failure_class.is_a?(Hash)
|
35
|
+
if failure_class.nil? || failure_class.is_a?(::Hash)
|
20
36
|
result = failure_class.to_h
|
21
|
-
failure_class = ServiceActor::Failure
|
37
|
+
failure_class = ::ServiceActor::Failure
|
22
38
|
end
|
23
39
|
|
24
|
-
merge!(result)
|
25
|
-
|
40
|
+
data.merge!(result)
|
41
|
+
data[:failure] = true
|
26
42
|
|
27
|
-
raise failure_class, self
|
43
|
+
::Kernel.raise failure_class, self
|
28
44
|
end
|
29
45
|
|
30
46
|
def success?
|
@@ -32,13 +48,11 @@ class ServiceActor::Result < OpenStruct
|
|
32
48
|
end
|
33
49
|
|
34
50
|
def failure?
|
35
|
-
|
51
|
+
data[:failure] || false
|
36
52
|
end
|
37
53
|
|
38
54
|
def merge!(result)
|
39
|
-
result
|
40
|
-
self[key] = value
|
41
|
-
end
|
55
|
+
data.merge!(result)
|
42
56
|
|
43
57
|
self
|
44
58
|
end
|
@@ -48,34 +62,63 @@ class ServiceActor::Result < OpenStruct
|
|
48
62
|
end
|
49
63
|
|
50
64
|
def [](name)
|
51
|
-
|
65
|
+
data[name]
|
52
66
|
end
|
53
67
|
|
54
|
-
|
55
|
-
|
56
|
-
to_h.fetch(:display)
|
68
|
+
def []=(key, value)
|
69
|
+
data[key] = value
|
57
70
|
end
|
58
71
|
|
59
|
-
|
72
|
+
def delete!(key)
|
73
|
+
data.delete(key)
|
74
|
+
end
|
60
75
|
|
61
|
-
def
|
62
|
-
|
76
|
+
def respond_to?(method_name, include_private = false)
|
77
|
+
self.class.instance_methods.include?(method_name) ||
|
78
|
+
respond_to_missing?(method_name, include_private)
|
63
79
|
end
|
64
80
|
|
65
|
-
def
|
66
|
-
|
81
|
+
def deconstruct_keys(keys)
|
82
|
+
deconstructed_keys = to_h.merge(success: success?, failure: failure?)
|
83
|
+
|
84
|
+
keys ? deconstructed_keys.slice(*keys) : deconstructed_keys
|
85
|
+
end
|
67
86
|
|
68
|
-
|
69
|
-
define_singleton_method symbol do
|
70
|
-
value = send(attribute.to_sym)
|
87
|
+
private
|
71
88
|
|
72
|
-
|
73
|
-
value.respond_to?(:empty?) ? !value.empty? : !!value
|
74
|
-
end
|
89
|
+
attr_reader :data
|
75
90
|
|
76
|
-
|
91
|
+
def respond_to_missing?(method_name, _include_private = false)
|
92
|
+
return true if method_name.end_with?("=")
|
93
|
+
if method_name.end_with?("?") &&
|
94
|
+
data.key?(method_name.to_s.chomp("?").to_sym)
|
95
|
+
return true
|
77
96
|
end
|
78
97
|
|
79
|
-
|
98
|
+
return true if data.key?(method_name)
|
99
|
+
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
def method_missing(method_name, *args) # rubocop:disable Metrics/AbcSize
|
104
|
+
if method_name.end_with?("?") &&
|
105
|
+
data.key?(key = method_name.to_s.chomp("?").to_sym)
|
106
|
+
value = data[key]
|
107
|
+
value.respond_to?(:empty?) ? !value.empty? : !!value
|
108
|
+
elsif method_name.end_with?("=")
|
109
|
+
data[method_name.to_s.chomp("=").to_sym] = args.first
|
110
|
+
elsif data.key?(method_name)
|
111
|
+
data[method_name]
|
112
|
+
else
|
113
|
+
warn_on_undefined_method_invocation(method_name)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def warn_on_undefined_method_invocation(message)
|
118
|
+
::Kernel.warn(
|
119
|
+
"DEPRECATED: Invoking undefined methods on `ServiceActor::Result` will " \
|
120
|
+
"lead to runtime errors in the next major release of Actor. " \
|
121
|
+
"Invoked method: `#{message}`",
|
122
|
+
)
|
80
123
|
end
|
81
124
|
end
|