servactory 3.0.0 → 3.1.0.rc1
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/lib/servactory/actions/action.rb +2 -2
- data/lib/servactory/actions/collection.rb +1 -1
- data/lib/servactory/actions/stages/collection.rb +1 -1
- data/lib/servactory/configuration/option_helpers/option_helpers_collection.rb +60 -2
- data/lib/servactory/context/warehouse/inputs.rb +28 -15
- data/lib/servactory/context/workspace/inputs.rb +27 -18
- data/lib/servactory/context/workspace/internals.rb +44 -27
- data/lib/servactory/context/workspace/outputs.rb +31 -23
- data/lib/servactory/dsl.rb +1 -1
- data/lib/servactory/info/builder.rb +2 -3
- data/lib/servactory/inputs/collection.rb +14 -21
- data/lib/servactory/inputs/input.rb +6 -103
- data/lib/servactory/inputs/tools/validation.rb +32 -57
- data/lib/servactory/inputs/validations/required.rb +3 -2
- data/lib/servactory/internals/collection.rb +5 -24
- data/lib/servactory/internals/internal.rb +4 -112
- data/lib/servactory/maintenance/attributes/base.rb +135 -0
- data/lib/servactory/maintenance/attributes/collection.rb +109 -0
- data/lib/servactory/maintenance/attributes/option_helper.rb +33 -12
- data/lib/servactory/maintenance/{attributes/options_collection.rb → options/collection.rb} +6 -7
- data/lib/servactory/maintenance/{attributes → options}/define_conflict.rb +1 -1
- data/lib/servactory/maintenance/{attributes → options}/define_method.rb +1 -1
- data/lib/servactory/maintenance/options/helper.rb +23 -0
- data/lib/servactory/maintenance/{attributes → options}/option.rb +50 -27
- data/lib/servactory/maintenance/options/registrar.rb +200 -0
- data/lib/servactory/maintenance/{attributes/validations → validations/checkers}/must.rb +25 -8
- data/lib/servactory/maintenance/{attributes/validations → validations/checkers}/type.rb +6 -5
- data/lib/servactory/maintenance/validations/concerns/error_builder.rb +50 -0
- data/lib/servactory/maintenance/validations/performer.rb +57 -0
- data/lib/servactory/maintenance/validations/support/type_validator.rb +36 -0
- data/lib/servactory/maintenance/{attributes → validations}/translator/must.rb +1 -1
- data/lib/servactory/maintenance/{attributes → validations}/translator/type.rb +1 -1
- data/lib/servactory/outputs/collection.rb +5 -24
- data/lib/servactory/outputs/output.rb +4 -112
- data/lib/servactory/result.rb +48 -39
- data/lib/servactory/tool_kit/dynamic_options/must.rb +2 -2
- data/lib/servactory/tool_kit/dynamic_options/schema.rb +5 -5
- data/lib/servactory/utils.rb +0 -8
- data/lib/servactory/version.rb +2 -2
- metadata +16 -13
- data/lib/servactory/maintenance/attributes/options/registrar.rb +0 -183
- data/lib/servactory/maintenance/attributes/tools/validation.rb +0 -84
- data/lib/servactory/maintenance/attributes/validations/concerns/error_builder.rb +0 -52
- data/lib/servactory/maintenance/validations/types.rb +0 -34
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Servactory
|
|
4
4
|
module Maintenance
|
|
5
|
-
module
|
|
6
|
-
module
|
|
5
|
+
module Validations
|
|
6
|
+
module Checkers
|
|
7
7
|
# Validates that attribute values match their declared types.
|
|
8
8
|
#
|
|
9
9
|
# ## Purpose
|
|
@@ -35,13 +35,14 @@ module Servactory
|
|
|
35
35
|
# @param attribute [Inputs::Input, Internals::Internal, Outputs::Output] Attribute to validate
|
|
36
36
|
# @param value [Object] Value to check against declared types
|
|
37
37
|
# @param check_key [Symbol] Must be :types to trigger validation
|
|
38
|
+
# @param check_options [Hash, nil] Unused, accepted for uniform checker interface
|
|
38
39
|
# @return [String, nil] Error message on type mismatch, nil on success
|
|
39
|
-
def self.check(context:, attribute:, value:, check_key:,
|
|
40
|
+
def self.check(context:, attribute:, value:, check_key:, check_options: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
40
41
|
return unless should_be_checked_for?(attribute, value, check_key)
|
|
41
42
|
|
|
42
43
|
prepared_value = compute_prepared_value(attribute, value)
|
|
43
44
|
|
|
44
|
-
error_data = Servactory::Maintenance::Validations::
|
|
45
|
+
error_data = Servactory::Maintenance::Validations::Support::TypeValidator.validate(
|
|
45
46
|
context:,
|
|
46
47
|
attribute:,
|
|
47
48
|
types: attribute.types,
|
|
@@ -99,7 +100,7 @@ module Servactory
|
|
|
99
100
|
|
|
100
101
|
# Builds error message from validation error data.
|
|
101
102
|
#
|
|
102
|
-
# @param error_data [Hash] Error data from
|
|
103
|
+
# @param error_data [Hash] Error data from TypeValidator.validate
|
|
103
104
|
# @return [String] Processed error message
|
|
104
105
|
def self.build_error_message(error_data)
|
|
105
106
|
process_message(error_data[:message], **error_data)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Servactory
|
|
4
|
+
module Maintenance
|
|
5
|
+
module Validations
|
|
6
|
+
module Concerns
|
|
7
|
+
# Concern providing error message processing for validators.
|
|
8
|
+
#
|
|
9
|
+
# ## Purpose
|
|
10
|
+
#
|
|
11
|
+
# ErrorBuilder provides shared logic for processing error messages that
|
|
12
|
+
# can be either static strings or dynamic Procs. This allows validators
|
|
13
|
+
# to support both simple error messages and context-aware messages.
|
|
14
|
+
#
|
|
15
|
+
# ## Usage
|
|
16
|
+
#
|
|
17
|
+
# Extend in validator classes:
|
|
18
|
+
#
|
|
19
|
+
# ```ruby
|
|
20
|
+
# class MyValidator
|
|
21
|
+
# extend Concerns::ErrorBuilder
|
|
22
|
+
#
|
|
23
|
+
# def self.build_error(...)
|
|
24
|
+
# process_message(message, **context)
|
|
25
|
+
# end
|
|
26
|
+
# end
|
|
27
|
+
# ```
|
|
28
|
+
#
|
|
29
|
+
# ## Methods Provided
|
|
30
|
+
#
|
|
31
|
+
# - `process_message` - converts String or Proc message to String
|
|
32
|
+
module ErrorBuilder
|
|
33
|
+
# Processes a message that may be a String or Proc.
|
|
34
|
+
#
|
|
35
|
+
# If message is a Proc, calls it with the provided attributes.
|
|
36
|
+
# If message is a String, returns it unchanged.
|
|
37
|
+
#
|
|
38
|
+
# @param message [String, Proc] The message to process
|
|
39
|
+
# @param attributes [Hash] Attributes to pass to Proc if message is callable
|
|
40
|
+
# @return [String] The processed message string
|
|
41
|
+
def process_message(message, **attributes)
|
|
42
|
+
return message unless message.is_a?(Proc)
|
|
43
|
+
|
|
44
|
+
message.call(**attributes)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Servactory
|
|
4
|
+
module Maintenance
|
|
5
|
+
module Validations
|
|
6
|
+
module Performer
|
|
7
|
+
extend self
|
|
8
|
+
|
|
9
|
+
def validate!(context:, attribute:, value:)
|
|
10
|
+
first_error = process(context:, attribute:, value:)
|
|
11
|
+
return if first_error.nil?
|
|
12
|
+
|
|
13
|
+
context.public_send(
|
|
14
|
+
:"fail_#{attribute.system_name}!",
|
|
15
|
+
attribute.name,
|
|
16
|
+
message: first_error
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def process(context:, attribute:, value:) # rubocop:disable Metrics/MethodLength
|
|
23
|
+
attribute.options_for_checks.each do |check_key, check_options|
|
|
24
|
+
error = process_option(
|
|
25
|
+
context:,
|
|
26
|
+
attribute:,
|
|
27
|
+
value:,
|
|
28
|
+
check_key:,
|
|
29
|
+
check_options:
|
|
30
|
+
)
|
|
31
|
+
return error if error.present?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def process_option(context:, attribute:, value:, check_key:, check_options:) # rubocop:disable Metrics/MethodLength
|
|
38
|
+
validation_classes = attribute.collection_of_options.validation_classes
|
|
39
|
+
return if validation_classes.empty?
|
|
40
|
+
|
|
41
|
+
validation_classes.each do |validation_class|
|
|
42
|
+
error_message = validation_class.check(
|
|
43
|
+
context:,
|
|
44
|
+
attribute:,
|
|
45
|
+
value:,
|
|
46
|
+
check_key:,
|
|
47
|
+
check_options:
|
|
48
|
+
)
|
|
49
|
+
return error_message if error_message.present?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Servactory
|
|
4
|
+
module Maintenance
|
|
5
|
+
module Validations
|
|
6
|
+
module Support
|
|
7
|
+
class TypeValidator
|
|
8
|
+
# Validates value against expected types.
|
|
9
|
+
#
|
|
10
|
+
# Returns nil on success, error data Hash on failure.
|
|
11
|
+
#
|
|
12
|
+
# @param context [Object] Service context for error info
|
|
13
|
+
# @param attribute [Inputs::Input, Internals::Internal, Outputs::Output] Attribute being validated
|
|
14
|
+
# @param types [Array<Class, String, Symbol>] Expected type classes
|
|
15
|
+
# @param value [Object] Value to validate
|
|
16
|
+
# @return [Hash, nil] nil on success, error data Hash on failure
|
|
17
|
+
def self.validate(context:, attribute:, types:, value:) # rubocop:disable Metrics/MethodLength
|
|
18
|
+
prepared_types = types.map { |type| Servactory::Utils.constantize_class(type) }
|
|
19
|
+
|
|
20
|
+
return if prepared_types.any? { |type| value.is_a?(type) }
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
message: Servactory::Maintenance::Validations::Translator::Type.default_message,
|
|
24
|
+
service: context.send(:servactory_service_info),
|
|
25
|
+
attribute:,
|
|
26
|
+
value:,
|
|
27
|
+
key_name: nil,
|
|
28
|
+
expected_type: prepared_types.join(", "),
|
|
29
|
+
given_type: value.class.name
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -2,30 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Servactory
|
|
4
4
|
module Outputs
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def initialize(collection = Set.new)
|
|
11
|
-
@collection = collection
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def only(*names)
|
|
15
|
-
Collection.new(filter { |internal| names.include?(internal.name) })
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def except(*names)
|
|
19
|
-
Collection.new(filter { |internal| names.exclude?(internal.name) })
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def names
|
|
23
|
-
map(&:name)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def find_by(name:)
|
|
27
|
-
find { |output| output.name == name }
|
|
28
|
-
end
|
|
5
|
+
# Specialized collection for Output attributes.
|
|
6
|
+
#
|
|
7
|
+
# Inherits all behavior from the base Attributes::Collection
|
|
8
|
+
# without any overrides.
|
|
9
|
+
class Collection < Servactory::Maintenance::Attributes::Collection
|
|
29
10
|
end
|
|
30
11
|
end
|
|
31
12
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Servactory
|
|
4
4
|
module Outputs
|
|
5
|
-
class Output
|
|
5
|
+
class Output < Servactory::Maintenance::Attributes::Base
|
|
6
6
|
class Actor
|
|
7
7
|
attr_reader :name,
|
|
8
8
|
:types,
|
|
@@ -26,138 +26,30 @@ module Servactory
|
|
|
26
26
|
# The methods below are required to support the internal work.
|
|
27
27
|
|
|
28
28
|
def input?
|
|
29
|
-
|
|
29
|
+
@attribute.input?
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def internal?
|
|
33
|
-
|
|
33
|
+
@attribute.internal?
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def output?
|
|
37
|
-
|
|
37
|
+
@attribute.output?
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
attr_reader :name,
|
|
42
|
-
:collection_of_options,
|
|
43
|
-
:options
|
|
44
|
-
|
|
45
|
-
def initialize(
|
|
46
|
-
name,
|
|
47
|
-
*helpers,
|
|
48
|
-
option_helpers:,
|
|
49
|
-
**options
|
|
50
|
-
)
|
|
51
|
-
@name = name
|
|
52
|
-
@option_helpers = option_helpers
|
|
53
|
-
|
|
54
|
-
register_options(helpers:, options:)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def method_missing(name, *args, &block)
|
|
58
|
-
option = @collection_of_options.find_by(name:)
|
|
59
|
-
return super if option.nil?
|
|
60
|
-
|
|
61
|
-
option.body
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def respond_to_missing?(name, *)
|
|
65
|
-
@collection_of_options.names.include?(name) || super
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def register_options(helpers:, options:)
|
|
69
|
-
merged_options = augment_options_with_helpers(helpers:, options:)
|
|
70
|
-
options_registrar = create_options_registrar(options: merged_options)
|
|
71
|
-
|
|
72
|
-
@options = merged_options
|
|
73
|
-
@collection_of_options = options_registrar.collection
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def options_for_checks
|
|
77
|
-
@collection_of_options.options_for_checks
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def system_name
|
|
81
|
-
self.class.name.demodulize.downcase.to_sym
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def i18n_name
|
|
85
|
-
system_name.to_s.pluralize
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def input?
|
|
89
|
-
false
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def internal?
|
|
93
|
-
false
|
|
94
|
-
end
|
|
95
|
-
|
|
96
41
|
def output?
|
|
97
42
|
true
|
|
98
43
|
end
|
|
99
44
|
|
|
100
45
|
private
|
|
101
46
|
|
|
102
|
-
def create_options_registrar(options:)
|
|
103
|
-
Servactory::Maintenance::Attributes::Options::Registrar.register(
|
|
104
|
-
attribute: self,
|
|
105
|
-
options:,
|
|
106
|
-
features: available_feature_options
|
|
107
|
-
)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
47
|
def available_feature_options
|
|
111
48
|
{
|
|
112
49
|
types: true,
|
|
113
50
|
must: true
|
|
114
51
|
}
|
|
115
52
|
end
|
|
116
|
-
|
|
117
|
-
def augment_options_with_helpers(helpers:, options:)
|
|
118
|
-
result_options = options.dup
|
|
119
|
-
merge_standard_helpers_into(target_options: result_options, helpers:) if helpers.present?
|
|
120
|
-
merge_advanced_helpers_into(target_options: result_options, source_options: options)
|
|
121
|
-
result_options
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def merge_standard_helpers_into(target_options:, helpers:)
|
|
125
|
-
standard_helpers_result = transform_helpers_to_options(helpers:)
|
|
126
|
-
target_options.deep_merge!(standard_helpers_result)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def merge_advanced_helpers_into(target_options:, source_options:)
|
|
130
|
-
advanced_helpers = filter_advanced_helpers(options: source_options)
|
|
131
|
-
return if advanced_helpers.blank?
|
|
132
|
-
|
|
133
|
-
advanced_helpers_result = transform_helpers_to_options(helpers: advanced_helpers)
|
|
134
|
-
target_options.deep_merge!(advanced_helpers_result)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def filter_advanced_helpers(options:)
|
|
138
|
-
reserved_options = Servactory::Maintenance::Attributes::Options::Registrar::RESERVED_OPTIONS
|
|
139
|
-
options.except(*reserved_options)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def transform_helpers_to_options(helpers:)
|
|
143
|
-
helpers.each_with_object({}) do |(helper_name, values), result|
|
|
144
|
-
helper = @option_helpers.find_by(name: helper_name)
|
|
145
|
-
next if helper.blank?
|
|
146
|
-
|
|
147
|
-
transformed_option = transform_helper_to_option(helper:, values:)
|
|
148
|
-
result.deep_merge!(transformed_option) if transformed_option.present?
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def transform_helper_to_option(helper:, values:)
|
|
153
|
-
return helper.equivalent unless helper.equivalent.is_a?(Proc)
|
|
154
|
-
|
|
155
|
-
if values.is_a?(Hash)
|
|
156
|
-
helper.equivalent.call(**values)
|
|
157
|
-
else
|
|
158
|
-
helper.equivalent.call(values)
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
53
|
end
|
|
162
54
|
end
|
|
163
55
|
end
|
data/lib/servactory/result.rb
CHANGED
|
@@ -41,10 +41,10 @@ module Servactory
|
|
|
41
41
|
# ```ruby
|
|
42
42
|
# result.active? # Equivalent to Utils.query_attribute(result.active)
|
|
43
43
|
# ```
|
|
44
|
-
class Result
|
|
44
|
+
class Result # rubocop:disable Metrics/ClassLength
|
|
45
45
|
# Internal container for service output values.
|
|
46
46
|
#
|
|
47
|
-
# Provides dynamic method access to output values
|
|
47
|
+
# Provides dynamic method access to output values.
|
|
48
48
|
# Stores outputs in hash and supports predicate methods when enabled.
|
|
49
49
|
class Outputs
|
|
50
50
|
# Creates an Outputs container with given output values.
|
|
@@ -55,6 +55,8 @@ module Servactory
|
|
|
55
55
|
def initialize(outputs:, predicate_methods_enabled:)
|
|
56
56
|
@outputs = outputs
|
|
57
57
|
@predicate_methods_enabled = predicate_methods_enabled
|
|
58
|
+
|
|
59
|
+
define_attribute_methods!
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
# Returns string representation for debugging.
|
|
@@ -64,45 +66,26 @@ module Servactory
|
|
|
64
66
|
"#<#{self.class.name} #{draw_result}>"
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# Defines singleton accessor methods for output values on this instance.
|
|
68
72
|
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
73
|
+
# Creates getter methods for each output key and, when predicate methods
|
|
74
|
+
# are enabled, predicate methods (e.g., user?) for boolean queries.
|
|
71
75
|
#
|
|
72
|
-
# @
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if name.to_s.end_with?("?")
|
|
77
|
-
base_name = name.to_s.chomp("?").to_sym
|
|
78
|
-
if @predicate_methods_enabled && @outputs.key?(base_name)
|
|
79
|
-
return Servactory::Utils.query_attribute(@outputs[base_name])
|
|
80
|
-
end
|
|
81
|
-
elsif @outputs.key?(name)
|
|
82
|
-
return @outputs[name]
|
|
83
|
-
end
|
|
76
|
+
# @return [void]
|
|
77
|
+
def define_attribute_methods!
|
|
78
|
+
@outputs.each_key do |name|
|
|
79
|
+
define_singleton_method(name) { @outputs[name] }
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
end
|
|
81
|
+
next unless @predicate_methods_enabled
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# @param include_private [Boolean] Include private methods in check
|
|
92
|
-
# @return [Boolean] True if output exists for this method
|
|
93
|
-
def respond_to_missing?(name, include_private = false)
|
|
94
|
-
if name.to_s.end_with?("?")
|
|
95
|
-
base_name = name.to_s.chomp("?").to_sym
|
|
96
|
-
return true if @predicate_methods_enabled && @outputs.key?(base_name)
|
|
97
|
-
elsif @outputs.key?(name)
|
|
98
|
-
return true
|
|
83
|
+
define_singleton_method(:"#{name}?") do
|
|
84
|
+
Servactory::Utils.query_attribute(@outputs[name])
|
|
85
|
+
end
|
|
99
86
|
end
|
|
100
|
-
|
|
101
|
-
super
|
|
102
87
|
end
|
|
103
88
|
|
|
104
|
-
private
|
|
105
|
-
|
|
106
89
|
# Returns array of output attribute names.
|
|
107
90
|
#
|
|
108
91
|
# @return [Array<Symbol>] Output names without predicates
|
|
@@ -297,15 +280,16 @@ module Servactory
|
|
|
297
280
|
self
|
|
298
281
|
end
|
|
299
282
|
|
|
300
|
-
# Delegates method calls to outputs container.
|
|
283
|
+
# Delegates method calls to the outputs container.
|
|
301
284
|
#
|
|
302
|
-
#
|
|
303
|
-
#
|
|
285
|
+
# On first access, triggers lazy initialization of outputs and
|
|
286
|
+
# installs singleton delegator methods for subsequent direct access.
|
|
304
287
|
#
|
|
305
288
|
# @param name [Symbol] Method name (output attribute)
|
|
306
289
|
# @param args [Array] Method arguments
|
|
307
290
|
# @param block [Proc] Optional block
|
|
308
|
-
# @return [Object] Output value
|
|
291
|
+
# @return [Object] Output value when name matches an output attribute
|
|
292
|
+
# @raise [NoMethodError] When method is truly undefined and no context present
|
|
309
293
|
def method_missing(name, *args, &block)
|
|
310
294
|
return outputs.public_send(name, *args, &block) if outputs.respond_to?(name)
|
|
311
295
|
|
|
@@ -348,9 +332,19 @@ module Servactory
|
|
|
348
332
|
|
|
349
333
|
# Returns outputs container, lazily initialized.
|
|
350
334
|
#
|
|
335
|
+
# On first access, also defines singleton delegator methods on this
|
|
336
|
+
# Result instance for subsequent direct access.
|
|
337
|
+
#
|
|
351
338
|
# @return [Outputs] Outputs container with service values
|
|
352
339
|
def outputs
|
|
353
|
-
@outputs ||=
|
|
340
|
+
@outputs ||= build_outputs.tap { |outputs_container| define_output_delegators!(outputs_container) }
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Builds Outputs container with predicate configuration.
|
|
344
|
+
#
|
|
345
|
+
# @return [Outputs] New outputs container
|
|
346
|
+
def build_outputs
|
|
347
|
+
Outputs.new(
|
|
354
348
|
outputs: build_outputs_hash,
|
|
355
349
|
predicate_methods_enabled:
|
|
356
350
|
@context.is_a?(Servactory::TestKit::Result) || @context.config.predicate_methods_enabled
|
|
@@ -368,6 +362,21 @@ module Servactory
|
|
|
368
362
|
hash
|
|
369
363
|
end
|
|
370
364
|
|
|
365
|
+
# Defines singleton delegator methods on this Result instance
|
|
366
|
+
# for direct access to output values without method_missing.
|
|
367
|
+
#
|
|
368
|
+
# @param outputs_container [Outputs] Outputs container to delegate to
|
|
369
|
+
# @return [void]
|
|
370
|
+
def define_output_delegators!(outputs_container)
|
|
371
|
+
outputs_container.send(:output_names).each do |name|
|
|
372
|
+
define_singleton_method(name) { outputs.public_send(name) }
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
outputs_container.send(:predicate_names).each do |name|
|
|
376
|
+
define_singleton_method(name) { outputs.public_send(name) }
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
371
380
|
########################################################################
|
|
372
381
|
|
|
373
382
|
# Wraps NoMethodError with contextual failure.
|
|
@@ -155,9 +155,9 @@ module Servactory
|
|
|
155
155
|
# Creates an OptionHelper for registration with Servactory.
|
|
156
156
|
#
|
|
157
157
|
# @param name [Symbol] Internal validation name
|
|
158
|
-
# @return [Servactory::Maintenance::
|
|
158
|
+
# @return [Servactory::Maintenance::Options::Helper]
|
|
159
159
|
def must(name)
|
|
160
|
-
Servactory::Maintenance::
|
|
160
|
+
Servactory::Maintenance::Options::Helper.new(
|
|
161
161
|
name: @option_name,
|
|
162
162
|
equivalent: equivalent_with(name),
|
|
163
163
|
meta: {
|
|
@@ -277,7 +277,7 @@ module Servactory
|
|
|
277
277
|
return true
|
|
278
278
|
end
|
|
279
279
|
|
|
280
|
-
value = object
|
|
280
|
+
value = object[schema_key]
|
|
281
281
|
prepared_value = prepare_value_from(schema_value:, value:, required: attribute_required)
|
|
282
282
|
|
|
283
283
|
[
|
|
@@ -297,7 +297,7 @@ module Servactory
|
|
|
297
297
|
required || (
|
|
298
298
|
!required && !fetch_default_from(schema_value).nil?
|
|
299
299
|
) || (
|
|
300
|
-
!required && !object
|
|
300
|
+
!required && !object[schema_key].nil?
|
|
301
301
|
)
|
|
302
302
|
end
|
|
303
303
|
|
|
@@ -320,7 +320,7 @@ module Servactory
|
|
|
320
320
|
# @param value [Hash] Schema definition
|
|
321
321
|
# @return [Object, nil] Default value or nil
|
|
322
322
|
def fetch_default_from(value)
|
|
323
|
-
value
|
|
323
|
+
value[:default]
|
|
324
324
|
end
|
|
325
325
|
|
|
326
326
|
########################################################################
|
|
@@ -352,14 +352,14 @@ module Servactory
|
|
|
352
352
|
)
|
|
353
353
|
else
|
|
354
354
|
# Apply scalar defaults.
|
|
355
|
-
default_value = schema_value
|
|
355
|
+
default_value = schema_value[:default]
|
|
356
356
|
|
|
357
357
|
if !required && !default_value.nil? && !Servactory::Utils.value_present?(object_value)
|
|
358
358
|
object[schema_key] = default_value
|
|
359
359
|
end
|
|
360
360
|
|
|
361
361
|
# Execute prepare callback if defined.
|
|
362
|
-
unless (input_prepare = schema_value
|
|
362
|
+
unless (input_prepare = schema_value[:prepare]).nil?
|
|
363
363
|
object[schema_key] = input_prepare.call(value: object[schema_key])
|
|
364
364
|
end
|
|
365
365
|
|
data/lib/servactory/utils.rb
CHANGED
|
@@ -12,14 +12,6 @@ module Servactory
|
|
|
12
12
|
data.symbolize_keys
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def fetch_hash_with_desired_attribute(attribute)
|
|
16
|
-
return { input: attribute.class::Actor.new(attribute) } if really_input?(attribute)
|
|
17
|
-
return { internal: attribute.class::Actor.new(attribute) } if really_internal?(attribute)
|
|
18
|
-
return { output: attribute.class::Actor.new(attribute) } if really_output?(attribute)
|
|
19
|
-
|
|
20
|
-
raise ArgumentError, "Failed to define attribute"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
15
|
def define_attribute_with(input: nil, internal: nil, output: nil)
|
|
24
16
|
return input if really_input?(input)
|
|
25
17
|
return internal if really_internal?(internal)
|
data/lib/servactory/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: servactory
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.1.0.rc1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anton Sokolov
|
|
@@ -264,19 +264,22 @@ files:
|
|
|
264
264
|
- lib/servactory/internals/collection.rb
|
|
265
265
|
- lib/servactory/internals/dsl.rb
|
|
266
266
|
- lib/servactory/internals/internal.rb
|
|
267
|
-
- lib/servactory/maintenance/attributes/
|
|
268
|
-
- lib/servactory/maintenance/attributes/
|
|
269
|
-
- lib/servactory/maintenance/attributes/option.rb
|
|
267
|
+
- lib/servactory/maintenance/attributes/base.rb
|
|
268
|
+
- lib/servactory/maintenance/attributes/collection.rb
|
|
270
269
|
- lib/servactory/maintenance/attributes/option_helper.rb
|
|
271
|
-
- lib/servactory/maintenance/
|
|
272
|
-
- lib/servactory/maintenance/
|
|
273
|
-
- lib/servactory/maintenance/
|
|
274
|
-
- lib/servactory/maintenance/
|
|
275
|
-
- lib/servactory/maintenance/
|
|
276
|
-
- lib/servactory/maintenance/
|
|
277
|
-
- lib/servactory/maintenance/
|
|
278
|
-
- lib/servactory/maintenance/
|
|
279
|
-
- lib/servactory/maintenance/validations/
|
|
270
|
+
- lib/servactory/maintenance/options/collection.rb
|
|
271
|
+
- lib/servactory/maintenance/options/define_conflict.rb
|
|
272
|
+
- lib/servactory/maintenance/options/define_method.rb
|
|
273
|
+
- lib/servactory/maintenance/options/helper.rb
|
|
274
|
+
- lib/servactory/maintenance/options/option.rb
|
|
275
|
+
- lib/servactory/maintenance/options/registrar.rb
|
|
276
|
+
- lib/servactory/maintenance/validations/checkers/must.rb
|
|
277
|
+
- lib/servactory/maintenance/validations/checkers/type.rb
|
|
278
|
+
- lib/servactory/maintenance/validations/concerns/error_builder.rb
|
|
279
|
+
- lib/servactory/maintenance/validations/performer.rb
|
|
280
|
+
- lib/servactory/maintenance/validations/support/type_validator.rb
|
|
281
|
+
- lib/servactory/maintenance/validations/translator/must.rb
|
|
282
|
+
- lib/servactory/maintenance/validations/translator/type.rb
|
|
280
283
|
- lib/servactory/outputs/collection.rb
|
|
281
284
|
- lib/servactory/outputs/dsl.rb
|
|
282
285
|
- lib/servactory/outputs/output.rb
|