servactory 2.3.0 → 2.4.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/config/locales/en.yml +31 -3
  3. data/config/locales/ru.yml +31 -3
  4. data/lib/servactory/context/callable.rb +35 -11
  5. data/lib/servactory/context/store.rb +58 -0
  6. data/lib/servactory/context/workspace/internals.rb +2 -2
  7. data/lib/servactory/context/workspace/outputs.rb +2 -2
  8. data/lib/servactory/context/workspace.rb +12 -25
  9. data/lib/servactory/errors/input_error.rb +4 -2
  10. data/lib/servactory/errors/internal_error.rb +4 -2
  11. data/lib/servactory/errors/output_error.rb +4 -2
  12. data/lib/servactory/exceptions/input.rb +4 -2
  13. data/lib/servactory/exceptions/internal.rb +4 -2
  14. data/lib/servactory/exceptions/output.rb +4 -2
  15. data/lib/servactory/inputs/input.rb +36 -3
  16. data/lib/servactory/internals/internal.rb +32 -3
  17. data/lib/servactory/maintenance/attributes/options/registrar.rb +15 -1
  18. data/lib/servactory/maintenance/attributes/translator/must.rb +4 -3
  19. data/lib/servactory/maintenance/attributes/translator/type.rb +2 -2
  20. data/lib/servactory/maintenance/attributes/validations/inclusion.rb +1 -1
  21. data/lib/servactory/maintenance/attributes/validations/must.rb +16 -9
  22. data/lib/servactory/outputs/output.rb +32 -3
  23. data/lib/servactory/result.rb +1 -1
  24. data/lib/servactory/test_kit/result.rb +3 -3
  25. data/lib/servactory/tool_kit/dynamic_options/format.rb +130 -0
  26. data/lib/servactory/tool_kit/dynamic_options/max.rb +68 -0
  27. data/lib/servactory/tool_kit/dynamic_options/min.rb +68 -0
  28. data/lib/servactory/tool_kit/dynamic_options/must.rb +130 -0
  29. data/lib/servactory/utils.rb +30 -4
  30. data/lib/servactory/version.rb +1 -1
  31. data/lib/servactory.rb +2 -0
  32. metadata +9 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5662ba4d5b8ad475c0cd03c3b74d8ab74f4b319799ae16b7a125bb6be7493337
4
- data.tar.gz: ed21fb0f82de78b4672da98b7692d857da56d96fb4e855c39ada1b303b32535c
3
+ metadata.gz: 3996c6a138a1683fe3e46b04e9a57f9e135c93f3fd3855287374595e3b3111b3
4
+ data.tar.gz: 72e31e10893e67f5fd57ce54f0241ac35720071d6b1837bda85a953e717c8ae5
5
5
  SHA512:
6
- metadata.gz: 5b50b74907895549d97c97b09dfeada580bf98e1dd53d96eb25ebdde73da447177350f2cabff2278adb78353b798f1f64c694ffe9f3c950b2ba6242f1442db12
7
- data.tar.gz: bad8e985072c7a6c1b47a7392d04b7e9adeedfcfc4d269082c74c50c3f31a5060d09faac462bc07e45b5b5609a51528fc13fc5cbee316ba31aa8eed0a6eb8b0f
6
+ metadata.gz: ec9727d9cd881bfb898f6843488fe7676ba18746ae40fd88e6feb391352c2e6eebf89137ca7d0743577d92caadde20a673973268040c2482eece16af82db2d5b
7
+ data.tar.gz: a73916a75bcd4b681ad41fc23ba63546d1a7ae46ff738eeb0f36671f191bd1195c64778e9ea7ddbec80a06c0c14dd46741b43bd521c09a94f9b6eb0cc395ab1f
@@ -16,7 +16,16 @@ en:
16
16
  default_error: "[%{service_class_name}] Wrong value in `%{input_name}`, must be one of `%{input_inclusion}`"
17
17
  must:
18
18
  default_error: "[%{service_class_name}] Input `%{input_name}` must \"%{code}\""
19
- syntax_error: "[%{service_class_name}] Syntax error inside `%{code}` of `%{input_name}` input"
19
+ syntax_error: "[%{service_class_name}] Syntax error inside `%{code}` of `%{input_name}` input: %{exception_message}"
20
+ dynamic_options:
21
+ format:
22
+ default: "[%{service_class_name}] Input `%{input_name}` does not match `%{format_name}` format"
23
+ wrong_pattern: "[%{service_class_name}] Input `%{input_name}` does not match `%{format_name}` format"
24
+ unknown: "[%{service_class_name}] Unknown `%{format_name}` format specified for input `%{input_name}`"
25
+ min:
26
+ default: "[%{service_class_name}] Input `%{input_name}` received value `%{value}`, which is less than `%{option_value}`"
27
+ max:
28
+ default: "[%{service_class_name}] Input `%{input_name}` received value `%{value}`, which is greater than `%{option_value}`"
20
29
  required:
21
30
  default_error:
22
31
  default: "[%{service_class_name}] Required input `%{input_name}` is missing"
@@ -25,6 +34,7 @@ en:
25
34
  default_error:
26
35
  default: "[%{service_class_name}] Wrong type of input `%{input_name}`, expected `%{expected_type}`, got `%{given_type}`"
27
36
  for_collection:
37
+ wrong_type: "[%{service_class_name}] Wrong input collection type `%{input_name}`, expected `%{expected_type}`, got `%{given_type}`"
28
38
  wrong_element_type: "[%{service_class_name}] Wrong type in input collection `%{input_name}`, expected `%{expected_type}`, got `%{given_type}`"
29
39
  for_hash:
30
40
  wrong_element_type: "[%{service_class_name}] Wrong type in input hash `%{input_name}`, expected `%{expected_type}` for `%{key_name}`, got `%{given_type}`"
@@ -42,7 +52,16 @@ en:
42
52
  default_error: "[%{service_class_name}] Wrong value in `%{internal_name}`, must be one of `%{internal_inclusion}`"
43
53
  must:
44
54
  default_error: "[%{service_class_name}] Internal attribute `%{internal_name}` must \"%{code}\""
45
- syntax_error: "[%{service_class_name}] Syntax error inside `%{code}` of `%{internal_name}` internal attribute"
55
+ syntax_error: "[%{service_class_name}] Syntax error inside `%{code}` of `%{internal_name}` internal attribute: %{exception_message}"
56
+ dynamic_options:
57
+ format:
58
+ default: "[%{service_class_name}] Internal attribute `%{internal_name}` does not match `%{format_name}` format"
59
+ wrong_pattern: "[%{service_class_name}] Internal attribute `%{internal_name}` does not match `%{format_name}` format"
60
+ unknown: "[%{service_class_name}] Unknown `%{format_name}` format specified for output attribute `%{internal_name}`"
61
+ min:
62
+ default: "[%{service_class_name}] Internal attribute `%{internal_name}` received value `%{value}`, which is less than `%{option_value}`"
63
+ max:
64
+ default: "[%{service_class_name}] Internal attribute `%{internal_name}` received value `%{value}`, which is greater than `%{option_value}`"
46
65
  type:
47
66
  default_error:
48
67
  default: "[%{service_class_name}] Wrong type of internal attribute `%{internal_name}`, expected `%{expected_type}`, got `%{given_type}`"
@@ -60,7 +79,16 @@ en:
60
79
  default_error: "[%{service_class_name}] Wrong value in `%{output_name}`, must be one of `%{output_inclusion}`"
61
80
  must:
62
81
  default_error: "[%{service_class_name}] Output attribute `%{output_name}` must \"%{code}\""
63
- syntax_error: "[%{service_class_name}] Syntax error inside `%{code}` of `%{output_name}` output attribute"
82
+ syntax_error: "[%{service_class_name}] Syntax error inside `%{code}` of `%{output_name}` output attribute: %{exception_message}"
83
+ dynamic_options:
84
+ format:
85
+ default: "[%{service_class_name}] Output attribute `%{output_name}` does not match `%{format_name}` format"
86
+ wrong_pattern: "[%{service_class_name}] Output attribute `%{output_name}` does not match `%{format_name}` format"
87
+ unknown: "[%{service_class_name}] Unknown `%{format_name}` format specified for output attribute `%{output_name}`"
88
+ min:
89
+ default: "[%{service_class_name}] Output attribute `%{output_name}` received value `%{value}`, which is less than `%{option_value}`"
90
+ max:
91
+ default: "[%{service_class_name}] Output attribute `%{output_name}` received value `%{value}`, which is greater than `%{option_value}`"
64
92
  type:
65
93
  default_error:
66
94
  default: "[%{service_class_name}] Wrong type of output attribute `%{output_name}`, expected `%{expected_type}`, got `%{given_type}`"
@@ -16,7 +16,16 @@ ru:
16
16
  default_error: "[%{service_class_name}] Неправильное значение в `%{input_name}`, должно быть одним из `%{input_inclusion}`"
17
17
  must:
18
18
  default_error: "[%{service_class_name}] Инпут `%{input_name}` должен \"%{code}\""
19
- syntax_error: "[%{service_class_name}] Синтаксическая ошибка внутри `%{code}` инпута `%{input_name}`"
19
+ syntax_error: "[%{service_class_name}] Синтаксическая ошибка внутри `%{code}` инпута `%{input_name}`: %{exception_message}"
20
+ dynamic_options:
21
+ format:
22
+ default: "[%{service_class_name}] Инпут `%{input_name}` не соответствует формату `%{format_name}`"
23
+ wrong_pattern: "[%{service_class_name}] Инпут `%{input_name}` не соответствует формату `%{format_name}`"
24
+ unknown: "[%{service_class_name}] Указан неизвестный формат `%{format_name}` у инпута `%{input_name}`"
25
+ min:
26
+ default: "[%{service_class_name}] Инпут `%{input_name}` получил значение `%{value}`, которое меньше `%{option_value}`"
27
+ max:
28
+ default: "[%{service_class_name}] Инпут `%{input_name}` получил значение `%{value}`, которое больше `%{option_value}`"
20
29
  required:
21
30
  default_error:
22
31
  default: "[%{service_class_name}] Обязательный инпут `%{input_name}` отсутствует"
@@ -25,6 +34,7 @@ ru:
25
34
  default_error:
26
35
  default: "[%{service_class_name}] Неправильный тип инпута `%{input_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
27
36
  for_collection:
37
+ wrong_type: "[%{service_class_name}] Неправильный тип коллекции инпута `%{input_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
28
38
  wrong_element_type: "[%{service_class_name}] Неправильный тип в коллекции инпута `%{input_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
29
39
  for_hash:
30
40
  wrong_element_type: "[%{service_class_name}] Неправильный тип в хеше инпута `%{input_name}`, для `%{key_name}` ожидалось `%{expected_type}`, получено `%{given_type}`"
@@ -43,7 +53,16 @@ ru:
43
53
  default_error: "[%{service_class_name}] Неправильное значение в `%{internal_name}`, должно быть одним из `%{internal_inclusion}`"
44
54
  must:
45
55
  default_error: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` должен \"%{code}\""
46
- syntax_error: "[%{service_class_name}] Синтаксическая ошибка внутри `%{code}` внутреннего атрибута `%{internal_name}`"
56
+ syntax_error: "[%{service_class_name}] Синтаксическая ошибка внутри `%{code}` внутреннего атрибута `%{internal_name}`: %{exception_message}"
57
+ dynamic_options:
58
+ format:
59
+ default: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` не соответствует формату `%{format_name}`"
60
+ wrong_pattern: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` не соответствует формату `%{format_name}`"
61
+ unknown: "[%{service_class_name}] Указан неизвестный формат `%{format_name}` у внутреннего атрибута `%{internal_name}`"
62
+ min:
63
+ default: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` получил значение `%{value}`, которое меньше `%{option_value}`"
64
+ max:
65
+ default: "[%{service_class_name}] Внутренний атрибут `%{internal_name}` получил значение `%{value}`, которое больше `%{option_value}`"
47
66
  type:
48
67
  default_error:
49
68
  default: "[%{service_class_name}] Неправильный тип внутреннего атрибута `%{internal_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
@@ -61,7 +80,16 @@ ru:
61
80
  default_error: "[%{service_class_name}] Неправильное значение в `%{output_name}`, должно быть одним из `%{output_inclusion}`"
62
81
  must:
63
82
  default_error: "[%{service_class_name}] Выходящий атрибут `%{output_name}` должен \"%{code}\""
64
- syntax_error: "[%{service_class_name}] Синтаксическая ошибка внутри `%{code}` выходящего атрибута `%{output_name}`"
83
+ syntax_error: "[%{service_class_name}] Синтаксическая ошибка внутри `%{code}` выходящего атрибута `%{output_name}`: %{exception_message}"
84
+ dynamic_options:
85
+ format:
86
+ default: "[%{service_class_name}] Выходящий атрибут `%{output_name}` не соответствует формату `%{format_name}`"
87
+ wrong_pattern: "[%{service_class_name}] Выходящий атрибут `%{output_name}` не соответствует формату `%{format_name}`"
88
+ unknown: "[%{service_class_name}] Указан неизвестный формат `%{format_name}` у выходящего атрибута `%{output_name}`"
89
+ min:
90
+ default: "[%{service_class_name}] Выходящий атрибут `%{output_name}` получил значение `%{value}`, которое меньше `%{option_value}`"
91
+ max:
92
+ default: "[%{service_class_name}] Выходящий атрибут `%{output_name}` получил значение `%{value}`, которое больше `%{option_value}`"
65
93
  type:
66
94
  default: "[%{service_class_name}] Неправильный тип выходящего атрибута `%{output_name}`, ожидалось `%{expected_type}`, получено `%{given_type}`"
67
95
  for_collection:
@@ -3,9 +3,43 @@
3
3
  module Servactory
4
4
  module Context
5
5
  module Callable
6
- def call!(arguments = {}) # rubocop:disable Metrics/MethodLength
6
+ def call!(arguments = {})
7
+ prepare_result_class
8
+
9
+ context = send(:new)
10
+
11
+ _call!(context, **arguments)
12
+
13
+ self::Result.success_for(context: context)
14
+ rescue config.success_class => e
15
+ self::Result.success_for(context: e.context)
16
+ end
17
+
18
+ def call(arguments = {})
19
+ prepare_result_class
20
+
7
21
  context = send(:new)
8
22
 
23
+ _call!(context, **arguments)
24
+
25
+ self::Result.success_for(context: context)
26
+ rescue config.success_class => e
27
+ self::Result.success_for(context: e.context)
28
+ rescue config.failure_class => e
29
+ self::Result.failure_for(exception: e)
30
+ end
31
+
32
+ private
33
+
34
+ def prepare_result_class
35
+ return if Object.const_defined?("#{name}::Result")
36
+
37
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
38
+ Result = Class.new(Servactory::Result)
39
+ RUBY
40
+ end
41
+
42
+ def _call!(context, **arguments)
9
43
  context.send(
10
44
  :_call!,
11
45
  incoming_arguments: arguments.symbolize_keys,
@@ -14,16 +48,6 @@ module Servactory
14
48
  collection_of_outputs: collection_of_outputs,
15
49
  collection_of_stages: collection_of_stages
16
50
  )
17
-
18
- Servactory::Result.success_for(context: context)
19
- rescue config.success_class => e
20
- Servactory::Result.success_for(context: e.context)
21
- end
22
-
23
- def call(arguments = {})
24
- call!(arguments)
25
- rescue config.failure_class => e
26
- Servactory::Result.failure_for(exception: e)
27
51
  end
28
52
  end
29
53
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servactory
4
+ module Context
5
+ class Store
6
+ def initialize(context)
7
+ @context = context
8
+ end
9
+
10
+ def fetch_internal(name)
11
+ internals.fetch(name, nil)
12
+ end
13
+
14
+ def assign_internal(name, value)
15
+ assign_attribute(:internals, name, value)
16
+ end
17
+
18
+ def fetch_output(name)
19
+ outputs.fetch(name, nil)
20
+ end
21
+
22
+ def assign_output(name, value)
23
+ assign_attribute(:outputs, name, value)
24
+ end
25
+
26
+ def outputs
27
+ @outputs ||= context_data.fetch(:outputs)
28
+ end
29
+
30
+ private
31
+
32
+ def assign_attribute(section, name, value)
33
+ context_data[section].merge!({ name => value })
34
+ end
35
+
36
+ def internals
37
+ @internals ||= context_data.fetch(:internals)
38
+ end
39
+
40
+ def context_data
41
+ @context_data ||= state.fetch(context_id)
42
+ end
43
+
44
+ def state
45
+ {
46
+ context_id => {
47
+ internals: {},
48
+ outputs: {}
49
+ }
50
+ }
51
+ end
52
+
53
+ def context_id
54
+ @context_id ||= "context_#{@context.object_id}"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -50,7 +50,7 @@ module Servactory
50
50
  value: value
51
51
  )
52
52
 
53
- @context.send(:assign_servactory_service_storage_internal, internal.name, value)
53
+ @context.send(:servactory_service_store).assign_internal(internal.name, value)
54
54
  end
55
55
 
56
56
  def getter_with(name:, &block) # rubocop:disable Lint/UnusedMethodArgument
@@ -59,7 +59,7 @@ module Servactory
59
59
 
60
60
  return yield if internal.nil?
61
61
 
62
- internal_value = @context.send(:fetch_servactory_service_storage_internal, internal.name)
62
+ internal_value = @context.send(:servactory_service_store).fetch_internal(internal.name)
63
63
 
64
64
  if name.to_s.end_with?("?")
65
65
  Servactory::Utils.query_attribute(internal_value)
@@ -50,7 +50,7 @@ module Servactory
50
50
  value: value
51
51
  )
52
52
 
53
- @context.send(:assign_servactory_service_storage_output, output.name, value)
53
+ @context.send(:servactory_service_store).assign_output(output.name, value)
54
54
  end
55
55
 
56
56
  def getter_with(name:, &block) # rubocop:disable Lint/UnusedMethodArgument
@@ -59,7 +59,7 @@ module Servactory
59
59
 
60
60
  return yield if output.nil?
61
61
 
62
- output_value = @context.send(:fetch_servactory_service_storage_output, output.name)
62
+ output_value = @context.send(:servactory_service_store).fetch_output(output.name)
63
63
 
64
64
  if name.to_s.end_with?("?")
65
65
  Servactory::Utils.query_attribute(output_value)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Servactory
4
4
  module Context
5
- module Workspace # rubocop:disable Metrics/ModuleLength
5
+ module Workspace
6
6
  def inputs
7
7
  @inputs ||= Inputs.new(
8
8
  context: self,
@@ -29,24 +29,27 @@ module Servactory
29
29
  raise self.class.config.success_class.new(context: self)
30
30
  end
31
31
 
32
- def fail_input!(input_name, message:)
32
+ def fail_input!(input_name, message:, meta: nil)
33
33
  raise self.class.config.input_exception_class.new(
34
34
  input_name: input_name,
35
- message: message
35
+ message: message,
36
+ meta: meta
36
37
  )
37
38
  end
38
39
 
39
- def fail_internal!(internal_name, message:)
40
+ def fail_internal!(internal_name, message:, meta: nil)
40
41
  raise self.class.config.internal_exception_class.new(
41
42
  internal_name: internal_name,
42
- message: message
43
+ message: message,
44
+ meta: meta
43
45
  )
44
46
  end
45
47
 
46
- def fail_output!(output_name, message:)
48
+ def fail_output!(output_name, message:, meta: nil)
47
49
  raise self.class.config.output_exception_class.new(
48
50
  output_name: output_name,
49
- message: message
51
+ message: message,
52
+ meta: meta
50
53
  )
51
54
  end
52
55
 
@@ -104,24 +107,8 @@ module Servactory
104
107
  )
105
108
  end
106
109
 
107
- def servactory_service_storage
108
- @servactory_service_storage ||= { internals: {}, outputs: {} }
109
- end
110
-
111
- def assign_servactory_service_storage_internal(key, value)
112
- servactory_service_storage[:internals].merge!({ key => value })
113
- end
114
-
115
- def fetch_servactory_service_storage_internal(key)
116
- servactory_service_storage.fetch(:internals).fetch(key, nil)
117
- end
118
-
119
- def assign_servactory_service_storage_output(key, value)
120
- servactory_service_storage[:outputs].merge!({ key => value })
121
- end
122
-
123
- def fetch_servactory_service_storage_output(key)
124
- servactory_service_storage.fetch(:outputs).fetch(key, nil)
110
+ def servactory_service_store
111
+ @servactory_service_store ||= Store.new(self)
125
112
  end
126
113
  end
127
114
  end
@@ -5,11 +5,13 @@ module Servactory
5
5
  # DEPRECATED: This class will be deleted after release 2.4.
6
6
  class InputError < Servactory::Exceptions::Base
7
7
  attr_reader :message,
8
- :input_name
8
+ :input_name,
9
+ :meta
9
10
 
10
- def initialize(message:, input_name: nil)
11
+ def initialize(message:, input_name: nil, meta: nil)
11
12
  @message = message
12
13
  @input_name = input_name&.to_sym
14
+ @meta = meta
13
15
 
14
16
  super(message)
15
17
  end
@@ -5,11 +5,13 @@ module Servactory
5
5
  # DEPRECATED: This class will be deleted after release 2.4.
6
6
  class InternalError < Servactory::Exceptions::Base
7
7
  attr_reader :message,
8
- :internal_name
8
+ :internal_name,
9
+ :meta
9
10
 
10
- def initialize(message:, internal_name: nil)
11
+ def initialize(message:, internal_name: nil, meta: nil)
11
12
  @message = message
12
13
  @internal_name = internal_name&.to_sym
14
+ @meta = meta
13
15
 
14
16
  super(message)
15
17
  end
@@ -5,11 +5,13 @@ module Servactory
5
5
  # DEPRECATED: This class will be deleted after release 2.4.
6
6
  class OutputError < Servactory::Exceptions::Base
7
7
  attr_reader :message,
8
- :output_name
8
+ :output_name,
9
+ :meta
9
10
 
10
- def initialize(message:, output_name: nil)
11
+ def initialize(message:, output_name: nil, meta: nil)
11
12
  @message = message
12
13
  @output_name = output_name&.to_sym
14
+ @meta = meta
13
15
 
14
16
  super(message)
15
17
  end
@@ -4,11 +4,13 @@ module Servactory
4
4
  module Exceptions
5
5
  class Input < Base
6
6
  attr_reader :message,
7
- :input_name
7
+ :input_name,
8
+ :meta
8
9
 
9
- def initialize(message:, input_name: nil)
10
+ def initialize(message:, input_name: nil, meta: nil)
10
11
  @message = message
11
12
  @input_name = input_name&.to_sym
13
+ @meta = meta
12
14
 
13
15
  super(message)
14
16
  end
@@ -4,11 +4,13 @@ module Servactory
4
4
  module Exceptions
5
5
  class Internal < Base
6
6
  attr_reader :message,
7
- :internal_name
7
+ :internal_name,
8
+ :meta
8
9
 
9
- def initialize(message:, internal_name: nil)
10
+ def initialize(message:, internal_name: nil, meta: nil)
10
11
  @message = message
11
12
  @internal_name = internal_name&.to_sym
13
+ @meta = meta
12
14
 
13
15
  super(message)
14
16
  end
@@ -4,11 +4,13 @@ module Servactory
4
4
  module Exceptions
5
5
  class Output < Base
6
6
  attr_reader :message,
7
- :output_name
7
+ :output_name,
8
+ :meta
8
9
 
9
- def initialize(message:, output_name: nil)
10
+ def initialize(message:, output_name: nil, meta: nil)
10
11
  @message = message
11
12
  @output_name = output_name&.to_sym
13
+ @meta = meta
12
14
 
13
15
  super(message)
14
16
  end
@@ -3,6 +3,29 @@
3
3
  module Servactory
4
4
  module Inputs
5
5
  class Input
6
+ class Work
7
+ attr_reader :name,
8
+ :internal_name,
9
+ :types,
10
+ :inclusion
11
+
12
+ def initialize(input) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
13
+ @name = input.name
14
+ @internal_name = input.internal_name
15
+ @types = input.types
16
+ @inclusion = input.inclusion.slice(:in) if input.inclusion_present?
17
+
18
+ define_singleton_method(:system_name) { input.system_name }
19
+ define_singleton_method(:i18n_name) { input.i18n_name }
20
+ define_singleton_method(:optional?) { input.optional? }
21
+ define_singleton_method(:required?) { input.required? }
22
+ # The methods below are required to support the internal work.
23
+ define_singleton_method(:input?) { true }
24
+ define_singleton_method(:internal?) { false }
25
+ define_singleton_method(:output?) { false }
26
+ end
27
+ end
28
+
6
29
  attr_reader :name,
7
30
  :internal_name,
8
31
  :collection_of_options
@@ -40,7 +63,10 @@ module Servactory
40
63
  end
41
64
 
42
65
  def register_options(helpers:, options:) # rubocop:disable Metrics/MethodLength
66
+ advanced_helpers = options.except(*Servactory::Maintenance::Attributes::Options::Registrar::RESERVED_OPTIONS)
67
+
43
68
  options = apply_helpers_for_options(helpers: helpers, options: options) if helpers.present?
69
+ options = apply_helpers_for_options(helpers: advanced_helpers, options: options) if advanced_helpers.present?
44
70
 
45
71
  options_registrar = Servactory::Maintenance::Attributes::Options::Registrar.register(
46
72
  attribute: self,
@@ -62,15 +88,22 @@ module Servactory
62
88
  @collection_of_options = options_registrar.collection
63
89
  end
64
90
 
65
- def apply_helpers_for_options(helpers:, options:)
91
+ def apply_helpers_for_options(helpers:, options:) # rubocop:disable Metrics/MethodLength
66
92
  prepared_options = {}
67
93
 
68
- helpers.each do |helper|
94
+ helpers.each do |(helper, values)|
69
95
  found_helper = @option_helpers.find_by(name: helper)
70
96
 
71
97
  next if found_helper.blank?
72
98
 
73
- prepared_options.merge!(found_helper.equivalent)
99
+ prepared_option =
100
+ if found_helper.equivalent.is_a?(Proc)
101
+ values.is_a?(Hash) ? found_helper.equivalent.call(**values) : found_helper.equivalent.call(values)
102
+ else
103
+ found_helper.equivalent
104
+ end
105
+
106
+ prepared_options.deep_merge!(prepared_option)
74
107
  end
75
108
 
76
109
  options.merge(prepared_options)
@@ -3,6 +3,25 @@
3
3
  module Servactory
4
4
  module Internals
5
5
  class Internal
6
+ class Work
7
+ attr_reader :name,
8
+ :types,
9
+ :inclusion
10
+
11
+ def initialize(internal)
12
+ @name = internal.name
13
+ @types = internal.types
14
+ @inclusion = internal.inclusion.slice(:in) if internal.inclusion_present?
15
+
16
+ define_singleton_method(:system_name) { internal.system_name }
17
+ define_singleton_method(:i18n_name) { internal.i18n_name }
18
+ # The methods below are required to support the internal work.
19
+ define_singleton_method(:input?) { false }
20
+ define_singleton_method(:internal?) { true }
21
+ define_singleton_method(:output?) { false }
22
+ end
23
+ end
24
+
6
25
  attr_reader :name,
7
26
  :collection_of_options
8
27
 
@@ -35,7 +54,10 @@ module Servactory
35
54
  end
36
55
 
37
56
  def register_options(helpers:, options:) # rubocop:disable Metrics/MethodLength
57
+ advanced_helpers = options.except(*Servactory::Maintenance::Attributes::Options::Registrar::RESERVED_OPTIONS)
58
+
38
59
  options = apply_helpers_for_options(helpers: helpers, options: options) if helpers.present?
60
+ options = apply_helpers_for_options(helpers: advanced_helpers, options: options) if advanced_helpers.present?
39
61
 
40
62
  options_registrar = Servactory::Maintenance::Attributes::Options::Registrar.register(
41
63
  attribute: self,
@@ -54,15 +76,22 @@ module Servactory
54
76
  @collection_of_options = options_registrar.collection
55
77
  end
56
78
 
57
- def apply_helpers_for_options(helpers:, options:)
79
+ def apply_helpers_for_options(helpers:, options:) # rubocop:disable Metrics/MethodLength
58
80
  prepared_options = {}
59
81
 
60
- helpers.each do |helper|
82
+ helpers.each do |(helper, values)|
61
83
  found_helper = @option_helpers.find_by(name: helper)
62
84
 
63
85
  next if found_helper.blank?
64
86
 
65
- prepared_options.merge!(found_helper.equivalent)
87
+ prepared_option =
88
+ if found_helper.equivalent.is_a?(Proc)
89
+ values.is_a?(Hash) ? found_helper.equivalent.call(**values) : found_helper.equivalent.call(values)
90
+ else
91
+ found_helper.equivalent
92
+ end
93
+
94
+ prepared_options.deep_merge!(prepared_option)
66
95
  end
67
96
 
68
97
  options.merge(prepared_options)
@@ -5,6 +5,17 @@ module Servactory
5
5
  module Attributes
6
6
  module Options
7
7
  class Registrar # rubocop:disable Metrics/ClassLength
8
+ RESERVED_OPTIONS = %i[
9
+ type
10
+ required
11
+ default
12
+ collection
13
+ hash
14
+ inclusion
15
+ must
16
+ prepare
17
+ ].freeze
18
+
8
19
  DEFAULT_FEATURES = {
9
20
  required: false,
10
21
  types: false,
@@ -121,7 +132,10 @@ module Servactory
121
132
  define_methods: [
122
133
  Servactory::Maintenance::Attributes::DefineMethod.new(
123
134
  name: :collection_mode?,
124
- content: ->(**) { @collection_mode_class_names.include?(@options.fetch(:type)) }
135
+ content: lambda do |**|
136
+ @collection_mode_class_names.include?(@options.fetch(:type)) &&
137
+ @options.fetch(:consists_of, true) != false
138
+ end
125
139
  )
126
140
  ],
127
141
  define_conflicts: [
@@ -7,8 +7,8 @@ module Servactory
7
7
  module Must
8
8
  module_function
9
9
 
10
- def default_message
11
- lambda do |service_class_name:, value:, code:, input: nil, internal: nil, output: nil|
10
+ def default_message # rubocop:disable Metrics/MethodLength
11
+ lambda do |service_class_name:, value:, code:, input: nil, internal: nil, output: nil, reason: nil|
12
12
  attribute = Servactory::Utils.define_attribute_with(input: input, internal: internal, output: output)
13
13
 
14
14
  I18n.t(
@@ -16,7 +16,8 @@ module Servactory
16
16
  service_class_name: service_class_name,
17
17
  "#{attribute.system_name}_name": attribute.name,
18
18
  value: value,
19
- code: code
19
+ code: code,
20
+ reason: reason
20
21
  )
21
22
  end
22
23
  end