servactory 3.0.4 → 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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/servactory/actions/action.rb +2 -2
  3. data/lib/servactory/actions/collection.rb +1 -1
  4. data/lib/servactory/actions/stages/collection.rb +1 -1
  5. data/lib/servactory/configuration/config.rb +0 -16
  6. data/lib/servactory/configuration/configurable.rb +3 -6
  7. data/lib/servactory/configuration/hash_mode/class_names_collection.rb +1 -4
  8. data/lib/servactory/configuration/option_helpers/option_helpers_collection.rb +57 -8
  9. data/lib/servactory/context/warehouse/inputs.rb +28 -15
  10. data/lib/servactory/context/workspace/inputs.rb +27 -18
  11. data/lib/servactory/context/workspace/internals.rb +44 -27
  12. data/lib/servactory/context/workspace/outputs.rb +31 -23
  13. data/lib/servactory/dsl.rb +1 -1
  14. data/lib/servactory/info/builder.rb +2 -3
  15. data/lib/servactory/inputs/collection.rb +14 -21
  16. data/lib/servactory/inputs/input.rb +6 -103
  17. data/lib/servactory/inputs/tools/validation.rb +32 -57
  18. data/lib/servactory/inputs/validations/required.rb +3 -2
  19. data/lib/servactory/internals/collection.rb +5 -24
  20. data/lib/servactory/internals/internal.rb +4 -112
  21. data/lib/servactory/maintenance/attributes/base.rb +135 -0
  22. data/lib/servactory/maintenance/attributes/collection.rb +109 -0
  23. data/lib/servactory/maintenance/attributes/option_helper.rb +33 -12
  24. data/lib/servactory/maintenance/{attributes/options_collection.rb → options/collection.rb} +6 -7
  25. data/lib/servactory/maintenance/{attributes → options}/define_conflict.rb +1 -1
  26. data/lib/servactory/maintenance/{attributes → options}/define_method.rb +1 -1
  27. data/lib/servactory/maintenance/options/helper.rb +23 -0
  28. data/lib/servactory/maintenance/{attributes → options}/option.rb +50 -27
  29. data/lib/servactory/maintenance/options/registrar.rb +200 -0
  30. data/lib/servactory/maintenance/{attributes/validations → validations/checkers}/must.rb +25 -8
  31. data/lib/servactory/maintenance/{attributes/validations → validations/checkers}/type.rb +6 -5
  32. data/lib/servactory/maintenance/validations/concerns/error_builder.rb +50 -0
  33. data/lib/servactory/maintenance/validations/performer.rb +57 -0
  34. data/lib/servactory/maintenance/validations/support/type_validator.rb +36 -0
  35. data/lib/servactory/maintenance/{attributes → validations}/translator/must.rb +1 -1
  36. data/lib/servactory/maintenance/{attributes → validations}/translator/type.rb +1 -1
  37. data/lib/servactory/outputs/collection.rb +5 -24
  38. data/lib/servactory/outputs/output.rb +4 -112
  39. data/lib/servactory/result.rb +48 -39
  40. data/lib/servactory/tool_kit/dynamic_options/consists_of.rb +2 -4
  41. data/lib/servactory/tool_kit/dynamic_options/must.rb +2 -2
  42. data/lib/servactory/tool_kit/dynamic_options/schema.rb +7 -9
  43. data/lib/servactory/utils.rb +0 -8
  44. data/lib/servactory/version.rb +3 -3
  45. data/lib/servactory.rb +4 -0
  46. metadata +19 -22
  47. data/lib/servactory/maintenance/attributes/options/registrar.rb +0 -183
  48. data/lib/servactory/maintenance/attributes/tools/validation.rb +0 -84
  49. data/lib/servactory/maintenance/attributes/validations/concerns/error_builder.rb +0 -52
  50. 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 Attributes
6
- module Validations
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::Types.validate(
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 Types.validate
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,7 +2,7 @@
2
2
 
3
3
  module Servactory
4
4
  module Maintenance
5
- module Attributes
5
+ module Validations
6
6
  module Translator
7
7
  module Must
8
8
  module_function
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Servactory
4
4
  module Maintenance
5
- module Attributes
5
+ module Validations
6
6
  module Translator
7
7
  module Type
8
8
  module_function
@@ -2,30 +2,11 @@
2
2
 
3
3
  module Servactory
4
4
  module Outputs
5
- class Collection
6
- extend Forwardable
7
-
8
- def_delegators :@collection, :<<, :filter, :each, :map, :to_h, :merge, :find
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
- false
29
+ @attribute.input?
30
30
  end
31
31
 
32
32
  def internal?
33
- false
33
+ @attribute.internal?
34
34
  end
35
35
 
36
36
  def output?
37
- true
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
@@ -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 via method_missing.
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
- # Delegates method calls to stored outputs.
69
+ private
70
+
71
+ # Defines singleton accessor methods for output values on this instance.
68
72
  #
69
- # Supports both regular output access and predicate methods
70
- # when predicate_methods_enabled is true.
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
- # @param name [Symbol] Method name (output or predicate)
73
- # @param args [Array] Method arguments
74
- # @return [Object] Output value or predicate result
75
- def method_missing(name, *args)
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
- super
86
- end
81
+ next unless @predicate_methods_enabled
87
82
 
88
- # Checks if method corresponds to stored output.
89
- #
90
- # @param name [Symbol] Method name to check
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
- # Provides access to output attributes as if they were
303
- # defined on the Result instance itself.
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 ||= Outputs.new(
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.
@@ -88,8 +88,7 @@ module Servactory
88
88
  # Creates a ConsistsOf validator instance.
89
89
  #
90
90
  # @param option_name [Symbol] The option name (default: :consists_of)
91
- # @param collection_mode_class_names [Servactory::Configuration::CollectionMode::ClassNamesCollection]
92
- # Valid collection types
91
+ # @param collection_mode_class_names [Array<Class>] Valid collection types
93
92
  # @return [Servactory::Maintenance::Attributes::OptionHelper]
94
93
  def self.use(option_name = :consists_of, collection_mode_class_names:)
95
94
  instance = new(option_name, :type, false)
@@ -99,8 +98,7 @@ module Servactory
99
98
 
100
99
  # Assigns the list of valid collection class names.
101
100
  #
102
- # @param collection_mode_class_names [Servactory::Configuration::CollectionMode::ClassNamesCollection]
103
- # Collection types to accept
101
+ # @param collection_mode_class_names [Array<Class>] Collection types to accept
104
102
  # @return [void]
105
103
  def assign(collection_mode_class_names)
106
104
  @collection_mode_class_names = collection_mode_class_names
@@ -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::Attributes::OptionHelper]
158
+ # @return [Servactory::Maintenance::Options::Helper]
159
159
  def must(name)
160
- Servactory::Maintenance::Attributes::OptionHelper.new(
160
+ Servactory::Maintenance::Options::Helper.new(
161
161
  name: @option_name,
162
162
  equivalent: equivalent_with(name),
163
163
  meta: {
@@ -127,8 +127,7 @@ module Servactory
127
127
  # Creates a Schema validator instance.
128
128
  #
129
129
  # @param option_name [Symbol] The option name (default: :schema)
130
- # @param default_hash_mode_class_names [Servactory::Configuration::HashMode::ClassNamesCollection]
131
- # Valid Hash-like types
130
+ # @param default_hash_mode_class_names [Array<Class>] Valid Hash-like types
132
131
  # @return [Servactory::Maintenance::Attributes::OptionHelper]
133
132
  def self.use(option_name = :schema, default_hash_mode_class_names:)
134
133
  instance = new(option_name, :is, false)
@@ -138,8 +137,7 @@ module Servactory
138
137
 
139
138
  # Assigns the list of valid Hash-compatible class names.
140
139
  #
141
- # @param default_hash_mode_class_names [Servactory::Configuration::HashMode::ClassNamesCollection]
142
- # Hash-like types to accept
140
+ # @param default_hash_mode_class_names [Array<Class>] Hash-like types to accept
143
141
  # @return [void]
144
142
  def assign(default_hash_mode_class_names)
145
143
  @default_hash_mode_class_names = default_hash_mode_class_names
@@ -279,7 +277,7 @@ module Servactory
279
277
  return true
280
278
  end
281
279
 
282
- value = object.fetch(schema_key, nil)
280
+ value = object[schema_key]
283
281
  prepared_value = prepare_value_from(schema_value:, value:, required: attribute_required)
284
282
 
285
283
  [
@@ -299,7 +297,7 @@ module Servactory
299
297
  required || (
300
298
  !required && !fetch_default_from(schema_value).nil?
301
299
  ) || (
302
- !required && !object.fetch(schema_key, nil).nil?
300
+ !required && !object[schema_key].nil?
303
301
  )
304
302
  end
305
303
 
@@ -322,7 +320,7 @@ module Servactory
322
320
  # @param value [Hash] Schema definition
323
321
  # @return [Object, nil] Default value or nil
324
322
  def fetch_default_from(value)
325
- value.fetch(:default, nil)
323
+ value[:default]
326
324
  end
327
325
 
328
326
  ########################################################################
@@ -354,14 +352,14 @@ module Servactory
354
352
  )
355
353
  else
356
354
  # Apply scalar defaults.
357
- default_value = schema_value.fetch(:default, nil)
355
+ default_value = schema_value[:default]
358
356
 
359
357
  if !required && !default_value.nil? && !Servactory::Utils.value_present?(object_value)
360
358
  object[schema_key] = default_value
361
359
  end
362
360
 
363
361
  # Execute prepare callback if defined.
364
- unless (input_prepare = schema_value.fetch(:prepare, nil)).nil?
362
+ unless (input_prepare = schema_value[:prepare]).nil?
365
363
  object[schema_key] = input_prepare.call(value: object[schema_key])
366
364
  end
367
365
 
@@ -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)
@@ -3,9 +3,9 @@
3
3
  module Servactory
4
4
  module VERSION
5
5
  MAJOR = 3
6
- MINOR = 0
7
- PATCH = 4
8
- PRE = nil
6
+ MINOR = 1
7
+ PATCH = 0
8
+ PRE = "rc1"
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
11
11
  end
data/lib/servactory.rb CHANGED
@@ -16,6 +16,10 @@ loader.inflector.inflect(
16
16
  )
17
17
  loader.setup
18
18
 
19
+ # Eager load DSL to initialize Stroma::Registry.
20
+ # Registry must be populated before any service class is defined.
21
+ require_relative "servactory/dsl"
22
+
19
23
  module Servactory; end
20
24
 
21
25
  require "servactory/engine" if defined?(Rails::Engine)