servactory 1.4.4 → 1.4.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54a713971d52bebd38a97f473eb942be19f5c4029604aa26f0729cb1dc40f24a
4
- data.tar.gz: 1b368e874cdf3c502328fe3dbf71758a3c0821140c1b0e9a595f6622b41ec1bc
3
+ metadata.gz: 995ff46dfe5e3620a05d0bbe4b21f515de2b63e593f971e1ec906721cd4bfb6d
4
+ data.tar.gz: 9df30c884f28760025da0a9f1e68ccb12a42e5cea702602c086fd0b31212da62
5
5
  SHA512:
6
- metadata.gz: c2e412f4e06a1a21aa70a43a0f898f6d5fc0adcca1eaf7922edb80aa719313b9c2325d83ef41e34eda9c8cacc988e60b076938e23b1ff1e709d50aee9ce0f0b1
7
- data.tar.gz: d871cef64e8249b89572f6b97e9fdd9410632d20a393ea77d59f36481acc7f0207bfa26e6c79749a2031962927b965955986f257ce298d554d8289f2f85bfaf4
6
+ metadata.gz: 6bf7a7a0b667c3dce0926747b36fa85dc7cb6452e54cf7a51367918f8530cd09996a0d21e5d19d0fc06bc91cdfa3c00f2f0a464b9816738b9ea935b88c0d997b
7
+ data.tar.gz: 8b29bf3059b7420492c63321737eca8b9f79deea94ce52dfb5dd203c70f0a8fecbbeb29b55e2eb73a687220f85cbb71a5bd85664cd5b45a404e2cbe7ed168a42
data/README.md CHANGED
@@ -14,10 +14,13 @@ A set of tools for building reliable services of any complexity.
14
14
  - [Preparation](#preparation)
15
15
  - [Usage](#usage)
16
16
  - [Minimal example](#minimal-example)
17
+ - [Call](#call)
18
+ - [Result](#result)
17
19
  - [Input attributes](#input-attributes)
18
20
  - [Isolated usage](#isolated-usage)
19
21
  - [As an internal argument](#isolated-usage)
20
22
  - [Optional inputs](#optional-inputs)
23
+ - [As (internal name)](#as-internal-name)
21
24
  - [An array of specific values](#an-array-of-specific-values)
22
25
  - [Inclusion](#inclusion)
23
26
  - [Must](#must)
@@ -25,7 +28,7 @@ A set of tools for building reliable services of any complexity.
25
28
  - [Internal attributes](#internal-attributes)
26
29
  - [Stage](#stage)
27
30
  - [Failures](#failures)
28
- - [Result](#result)
31
+ - [I18n](#i18n)
29
32
  - [Testing](#testing)
30
33
  - [Thanks](#thanks)
31
34
  - [Contributing](#contributing)
@@ -111,6 +114,47 @@ end
111
114
 
112
115
  [More examples](https://github.com/afuno/servactory/tree/main/examples/usual)
113
116
 
117
+ ### Call
118
+
119
+ Services can only be called via `.call` and `.call!` methods.
120
+
121
+ The `.call` method will only fail if it catches an exception in the input arguments.
122
+ Internal and output attributes, as well as methods for failures - all this will be collected in the result.
123
+
124
+ The `.call!` method will fail if it catches any exception.
125
+
126
+ #### Via .call
127
+
128
+ ```ruby
129
+ UsersService::Accept.call(user: User.first)
130
+ ```
131
+
132
+ #### Via .call!
133
+
134
+ ```ruby
135
+ UsersService::Accept.call!(user: User.first)
136
+ ```
137
+
138
+ ### Result
139
+
140
+ All services have the result of their work. For example, in case of success this call:
141
+
142
+ ```ruby
143
+ service_result = UsersService::Accept.call!(user: User.first)
144
+ ```
145
+
146
+ Will return this:
147
+
148
+ ```ruby
149
+ #<Servactory::Result:0x0000000107ad9e88 @user="...">
150
+ ```
151
+
152
+ And then you can work with this result, for example, in this way:
153
+
154
+ ```ruby
155
+ Notification::SendJob.perform_later(service_result.user.id)
156
+ ```
157
+
114
158
  ### Input attributes
115
159
 
116
160
  #### Isolated usage
@@ -163,7 +207,7 @@ class UsersService::Create < ApplicationService::Base
163
207
  end
164
208
  ```
165
209
 
166
- #### As
210
+ #### As (internal name)
167
211
 
168
212
  This option changes the name of the input within the service.
169
213
 
@@ -346,25 +390,11 @@ def check!
346
390
  end
347
391
  ```
348
392
 
349
- ### Result
350
-
351
- All services have the result of their work. For example, in case of success this call:
352
-
353
- ```ruby
354
- service_result = NotificationService::Create.call!(user: User.first)
355
- ```
356
-
357
- Will return this:
393
+ ## I18n
358
394
 
359
- ```ruby
360
- #<Servactory::Result:0x0000000112c00748 @notification=...>
361
- ```
362
-
363
- And then you can work with this result, for example, in this way:
395
+ All texts are stored in the localization file. All texts can be changed or supplemented by new locales.
364
396
 
365
- ```ruby
366
- Notification::SendJob.perform_later(service_result.notification.id)
367
- ```
397
+ [See en.yml file](https://github.com/afuno/servactory/tree/main/config/locales/en.yml)
368
398
 
369
399
  ## Testing
370
400
 
@@ -0,0 +1,33 @@
1
+ en:
2
+ servactory:
3
+ input_arguments:
4
+ checks:
5
+ inclusion:
6
+ default_error: "[%{service_class_name}] Wrong value in `%{input_name}`, must be one of `%{input_inclusion}`"
7
+ must:
8
+ default_error: "[%{service_class_name}] Input `%{input_name}` must \"%{code}\""
9
+ syntax_error: "[%{service_class_name}] Syntax error inside `%{code}` of `%{input_name}` input"
10
+ required:
11
+ default_error:
12
+ default: "[%{service_class_name}] Required input `%{input_name}` is missing"
13
+ for_array: "[%{service_class_name}] Required element in input array `%{input_name}` is missing"
14
+ type:
15
+ default_error:
16
+ default: "[%{service_class_name}] Wrong type of input `%{input_name}`, expected `%{expected_type}`, got `%{given_type}`"
17
+ for_array: "[%{service_class_name}] Wrong type in input array `%{input_name}`, expected `%{expected_type}`"
18
+ tools:
19
+ find_unnecessary:
20
+ error: "[%{service_class_name}] Unexpected attributes: `%{unnecessary_attributes}`"
21
+ rules:
22
+ error: "[%{service_class_name}] Conflict in `%{input_name}` input options: `%{conflict_code}`"
23
+ internal_arguments:
24
+ checks:
25
+ type:
26
+ default_error: "[%{service_class_name}] Wrong type of internal argument `%{internal_argument_name}`, expected `%{expected_type}`, got `%{given_type}`"
27
+ output_arguments:
28
+ checks:
29
+ type:
30
+ default_error: "[%{service_class_name}] Wrong type of output argument `%{output_argument_name}`, expected `%{expected_type}`, got `%{given_type}`"
31
+ tools:
32
+ conflicts:
33
+ error: "[%{service_class_name}] Conflict between internal and output attributes `%{overlapping_attributes}`"
@@ -28,6 +28,29 @@ module Servactory
28
28
  )
29
29
  end
30
30
 
31
+ def call(arguments = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
32
+ @context_store = Store.new(self)
33
+
34
+ assign_data_with(arguments)
35
+
36
+ input_arguments_workbench.find_unnecessary!
37
+ input_arguments_workbench.check_rules!
38
+ output_arguments_workbench.find_conflicts_in!(
39
+ collection_of_internal_arguments: collection_of_internal_arguments
40
+ )
41
+
42
+ prepare_data
43
+
44
+ input_arguments_workbench.check!
45
+
46
+ stage_handyman.run_methods!
47
+
48
+ Servactory::Result.prepare_for(
49
+ context: context_store.context,
50
+ collection_of_output_arguments: collection_of_output_arguments
51
+ )
52
+ end
53
+
31
54
  private
32
55
 
33
56
  attr_reader :context_store
@@ -6,7 +6,7 @@ module Servactory
6
6
  class Errors
7
7
  # NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
8
8
  extend Forwardable
9
- def_delegators :@collection, :<<, :filter, :reject, :empty?, :first
9
+ def_delegators :@collection, :<<, :to_a, :filter, :reject, :empty?, :first
10
10
 
11
11
  def initialize(collection = Set.new)
12
12
  @collection = collection
@@ -9,7 +9,7 @@ module Servactory
9
9
  def add_error(message, **arguments)
10
10
  message = message.call(**arguments) if message.is_a?(Proc)
11
11
 
12
- errors.add(message)
12
+ errors << message
13
13
  end
14
14
 
15
15
  private
@@ -6,7 +6,7 @@ module Servactory
6
6
  class Errors
7
7
  # NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
8
8
  extend Forwardable
9
- def_delegators :@collection, :add, :to_a
9
+ def_delegators :@collection, :<<, :to_a
10
10
 
11
11
  def initialize(*)
12
12
  @collection = Set.new
@@ -4,8 +4,14 @@ module Servactory
4
4
  module InputArguments
5
5
  module Checks
6
6
  class Inclusion < Base
7
- DEFAULT_MESSAGE = lambda do |service_class_name:, input:|
8
- "[#{service_class_name}] Wrong value in `#{input.name}`, must be one of `#{input.inclusion[:in]}`"
7
+ DEFAULT_MESSAGE = lambda do |service_class_name:, input:, value:|
8
+ I18n.t(
9
+ "servactory.input_arguments.checks.inclusion.default_error",
10
+ service_class_name: service_class_name,
11
+ input_name: input.name,
12
+ input_inclusion: input.inclusion[:in],
13
+ value: value
14
+ )
9
15
  end
10
16
 
11
17
  private_constant :DEFAULT_MESSAGE
@@ -36,7 +42,8 @@ module Servactory
36
42
  add_error(
37
43
  DEFAULT_MESSAGE,
38
44
  service_class_name: @context.class.name,
39
- input: @input
45
+ input: @input,
46
+ value: @value
40
47
  )
41
48
  end
42
49
  end
@@ -4,12 +4,28 @@ module Servactory
4
4
  module InputArguments
5
5
  module Checks
6
6
  class Must < Base
7
- DEFAULT_MESSAGE = lambda do |service_class_name:, input:, code:|
8
- "[#{service_class_name}] Input `#{input.name}` " \
9
- "must \"#{code.to_s.humanize(capitalize: false, keep_id_suffix: true)}\""
7
+ DEFAULT_MESSAGE = lambda do |service_class_name:, input:, value:, code:|
8
+ I18n.t(
9
+ "servactory.input_arguments.checks.must.default_error",
10
+ service_class_name: service_class_name,
11
+ input_name: input.name,
12
+ value: value,
13
+ code: code
14
+ )
15
+ end
16
+
17
+ SYNTAX_ERROR_MESSAGE = lambda do |service_class_name:, input:, value:, code:, exception_message:|
18
+ I18n.t(
19
+ "servactory.input_arguments.checks.must.syntax_error",
20
+ service_class_name: service_class_name,
21
+ input_name: input.name,
22
+ value: value,
23
+ code: code,
24
+ exception_message: exception_message
25
+ )
10
26
  end
11
27
 
12
- private_constant :DEFAULT_MESSAGE
28
+ private_constant :DEFAULT_MESSAGE, :SYNTAX_ERROR_MESSAGE
13
29
 
14
30
  def self.check(context:, input:, value:, check_key:, check_options:)
15
31
  return unless should_be_checked_for?(input, check_key)
@@ -39,9 +55,10 @@ module Servactory
39
55
  next if message.blank?
40
56
 
41
57
  add_error(
42
- DEFAULT_MESSAGE,
58
+ message,
43
59
  service_class_name: @context.class.name,
44
60
  input: @input,
61
+ value: @value,
45
62
  code: code
46
63
  )
47
64
  end
@@ -58,16 +75,13 @@ module Servactory
58
75
 
59
76
  message.presence || DEFAULT_MESSAGE
60
77
  rescue StandardError => e
61
- message_text =
62
- "[#{@context.class.name}] Syntax error inside `#{code}` of `#{@input.name}` input"
63
-
64
- puts "#{message_text}: #{e}"
65
-
66
78
  add_error(
67
- message_text,
79
+ SYNTAX_ERROR_MESSAGE,
68
80
  service_class_name: @context.class.name,
69
81
  input: @input,
70
- code: code
82
+ value: @value,
83
+ code: code,
84
+ exception_message: e.message
71
85
  )
72
86
  end
73
87
  end
@@ -5,11 +5,14 @@ module Servactory
5
5
  module Checks
6
6
  class Required < Base
7
7
  DEFAULT_MESSAGE = lambda do |service_class_name:, input:, value:|
8
- if input.array? && value.present?
9
- "[#{service_class_name}] Required element in input array `#{input.name}` is missing"
10
- else
11
- "[#{service_class_name}] Required input `#{input.name}` is missing"
12
- end
8
+ i18n_key = "servactory.input_arguments.checks.required.default_error."
9
+ i18n_key += input.array? && value.present? ? "for_array" : "default"
10
+
11
+ I18n.t(
12
+ i18n_key,
13
+ service_class_name: service_class_name,
14
+ input_name: input.name
15
+ )
13
16
  end
14
17
 
15
18
  private_constant :DEFAULT_MESSAGE
@@ -13,12 +13,22 @@ module Servactory
13
13
  elsif array_message.is_a?(String) && array_message.present?
14
14
  array_message
15
15
  else
16
- "[#{service_class_name}] Wrong type in input array `#{input.name}`, expected `#{expected_type}`"
16
+ I18n.t(
17
+ "servactory.input_arguments.checks.type.default_error.for_array",
18
+ service_class_name: service_class_name,
19
+ input_name: input.name,
20
+ expected_type: expected_type,
21
+ given_type: given_type
22
+ )
17
23
  end
18
24
  else
19
- "[#{service_class_name}] Wrong type of input `#{input.name}`, " \
20
- "expected `#{expected_type}`, " \
21
- "got `#{given_type}`"
25
+ I18n.t(
26
+ "servactory.input_arguments.checks.type.default_error.default",
27
+ service_class_name: service_class_name,
28
+ input_name: input.name,
29
+ expected_type: expected_type,
30
+ given_type: given_type
31
+ )
22
32
  end
23
33
  end
24
34
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servactory
4
+ module InputArguments
5
+ class DefineInputConflict
6
+ attr_reader :content
7
+
8
+ def initialize(content:)
9
+ @content = content
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servactory
4
+ module InputArguments
5
+ class DefineInputMethod
6
+ attr_reader :name,
7
+ :content
8
+
9
+ def initialize(name:, content:)
10
+ @name = name.to_sym
11
+ @content = content
12
+ end
13
+ end
14
+ end
15
+ end
@@ -55,22 +55,19 @@ module Servactory
55
55
  name: :required,
56
56
  input: self,
57
57
  check_class: Servactory::InputArguments::Checks::Required,
58
- define_input_methods: lambda do
59
- <<-RUBY
60
- def required?
61
- Servactory::Utils.boolean?(required[:is])
62
- end
63
-
64
- def optional?
65
- !required?
66
- end
67
- RUBY
68
- end,
69
- define_conflicts: lambda do
70
- <<-RUBY
71
- return :required_vs_default if required? && default_value_present?
72
- RUBY
73
- end,
58
+ define_input_methods: [
59
+ DefineInputMethod.new(
60
+ name: :required?,
61
+ content: ->(value:) { Servactory::Utils.boolean?(value[:is]) }
62
+ ),
63
+ DefineInputMethod.new(
64
+ name: :optional?,
65
+ content: ->(value:) { !Servactory::Utils.boolean?(value[:is]) }
66
+ )
67
+ ],
68
+ define_input_conflicts: [
69
+ DefineInputConflict.new(content: -> { return :required_vs_default if required? && default_value_present? })
70
+ ],
74
71
  need_for_checks: true,
75
72
  value_key: :is,
76
73
  value_fallback: true,
@@ -95,13 +92,12 @@ module Servactory
95
92
  name: :default,
96
93
  input: self,
97
94
  check_class: Servactory::InputArguments::Checks::Type,
98
- define_input_methods: lambda do
99
- <<-RUBY
100
- def default_value_present?
101
- !default.nil?
102
- end
103
- RUBY
104
- end,
95
+ define_input_methods: [
96
+ DefineInputMethod.new(
97
+ name: :default_value_present?,
98
+ content: ->(value:) { !value.nil? }
99
+ )
100
+ ],
105
101
  need_for_checks: true,
106
102
  value_fallback: nil,
107
103
  with_advanced_mode: false,
@@ -114,19 +110,16 @@ module Servactory
114
110
  name: :array,
115
111
  input: self,
116
112
  check_class: Servactory::InputArguments::Checks::Type,
117
- define_input_methods: lambda do
118
- <<-RUBY
119
- def array?
120
- Servactory::Utils.boolean?(array[:is])
121
- end
122
- RUBY
123
- end,
124
- define_conflicts: lambda do
125
- <<-RUBY
126
- return :array_vs_array if array? && types.include?(Array)
127
- return :array_vs_inclusion if array? && inclusion_present?
128
- RUBY
129
- end,
113
+ define_input_methods: [
114
+ DefineInputMethod.new(
115
+ name: :array?,
116
+ content: ->(value:) { Servactory::Utils.boolean?(value[:is]) }
117
+ )
118
+ ],
119
+ define_input_conflicts: [
120
+ DefineInputConflict.new(content: -> { return :array_vs_array if array? && types.include?(Array) }),
121
+ DefineInputConflict.new(content: -> { return :array_vs_inclusion if array? && inclusion_present? })
122
+ ],
130
123
  need_for_checks: false,
131
124
  value_key: :is,
132
125
  value_fallback: false,
@@ -139,13 +132,12 @@ module Servactory
139
132
  name: :inclusion,
140
133
  input: self,
141
134
  check_class: Servactory::InputArguments::Checks::Inclusion,
142
- define_input_methods: lambda do
143
- <<-RUBY
144
- def inclusion_present?
145
- inclusion[:in].is_a?(Array) && inclusion[:in].present?
146
- end
147
- RUBY
148
- end,
135
+ define_input_methods: [
136
+ DefineInputMethod.new(
137
+ name: :inclusion_present?,
138
+ content: ->(value:) { value[:in].is_a?(Array) && value[:in].present? }
139
+ )
140
+ ],
149
141
  need_for_checks: true,
150
142
  value_key: :in,
151
143
  value_fallback: nil,
@@ -158,13 +150,12 @@ module Servactory
158
150
  name: :must,
159
151
  input: self,
160
152
  check_class: Servactory::InputArguments::Checks::Must,
161
- define_input_methods: lambda do
162
- <<-RUBY
163
- def must_present?
164
- must.present?
165
- end
166
- RUBY
167
- end,
153
+ define_input_methods: [
154
+ DefineInputMethod.new(
155
+ name: :must_present?,
156
+ content: ->(value:) { value.present? }
157
+ )
158
+ ],
168
159
  need_for_checks: true,
169
160
  value_key: :is,
170
161
  value_fallback: nil,
@@ -178,13 +169,12 @@ module Servactory
178
169
  name: :internal,
179
170
  input: self,
180
171
  check_class: nil,
181
- define_input_methods: lambda do
182
- <<-RUBY
183
- def internal?
184
- Servactory::Utils.boolean?(internal[:is])
185
- end
186
- RUBY
187
- end,
172
+ define_input_methods: [
173
+ DefineInputMethod.new(
174
+ name: :internal?,
175
+ content: ->(value:) { Servactory::Utils.boolean?(value[:is]) }
176
+ )
177
+ ],
188
178
  need_for_checks: false,
189
179
  value_key: :is,
190
180
  value_fallback: false,
@@ -197,9 +187,7 @@ module Servactory
197
187
  end
198
188
 
199
189
  def conflict_code
200
- instance_eval(collection_of_options.defined_conflicts)
201
-
202
- nil
190
+ collection_of_options.defined_conflict_code
203
191
  end
204
192
 
205
193
  def with_conflicts?
@@ -9,7 +9,8 @@ module Servactory
9
9
 
10
10
  attr_reader :name,
11
11
  :check_class,
12
- :define_conflicts,
12
+ :define_input_methods,
13
+ :define_input_conflicts,
13
14
  :need_for_checks,
14
15
  :value_key,
15
16
  :value
@@ -24,13 +25,14 @@ module Servactory
24
25
  original_value: nil,
25
26
  value_key: nil,
26
27
  define_input_methods: nil,
27
- define_conflicts: nil,
28
+ define_input_conflicts: nil,
28
29
  with_advanced_mode: true,
29
30
  **options
30
31
  ) # do
31
32
  @name = name.to_sym
32
33
  @check_class = check_class
33
- @define_conflicts = define_conflicts
34
+ @define_input_methods = define_input_methods
35
+ @define_input_conflicts = define_input_conflicts
34
36
  @need_for_checks = need_for_checks
35
37
  @value_key = value_key
36
38
 
@@ -41,7 +43,7 @@ module Servactory
41
43
  with_advanced_mode: with_advanced_mode
42
44
  )
43
45
 
44
- input.instance_eval(define_input_methods.call) if define_input_methods.present?
46
+ prepare_input_methods_for(input)
45
47
  end
46
48
  # rubocop:enable Metrics/MethodLength
47
49
 
@@ -73,6 +75,22 @@ module Servactory
73
75
  DEFAULT_VALUE.call(key: value_key, value: value)
74
76
  end
75
77
  end
78
+
79
+ def prepare_input_methods_for(input)
80
+ input.instance_eval(define_input_methods_template) if define_input_methods_template.present?
81
+ end
82
+
83
+ def define_input_methods_template
84
+ return if @define_input_methods.blank?
85
+
86
+ @define_input_methods_template ||= @define_input_methods.map do |define_input_method|
87
+ <<-RUBY
88
+ def #{define_input_method.name}
89
+ #{define_input_method.content.call(value: @value)}
90
+ end
91
+ RUBY
92
+ end.join("\n")
93
+ end
76
94
  end
77
95
  end
78
96
  end
@@ -5,7 +5,7 @@ module Servactory
5
5
  class OptionsCollection
6
6
  # NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
7
7
  extend Forwardable
8
- def_delegators :@collection, :<<, :filter, :each, :map
8
+ def_delegators :@collection, :<<, :filter, :each, :map, :flat_map
9
9
 
10
10
  def initialize(*)
11
11
  @collection = Set.new
@@ -27,8 +27,12 @@ module Servactory
27
27
  end
28
28
  end
29
29
 
30
- def defined_conflicts
31
- map { |option| option.define_conflicts&.call }.reject(&:blank?).uniq.join
30
+ def defined_conflict_code
31
+ flat_map do |option|
32
+ option.define_input_conflicts&.map do |define_input_conflict|
33
+ define_input_conflict.content.call
34
+ end
35
+ end.reject(&:blank?).first
32
36
  end
33
37
  end
34
38
  end
@@ -17,8 +17,13 @@ module Servactory
17
17
  def check!
18
18
  return if unnecessary_attributes.empty?
19
19
 
20
- raise Servactory.configuration.input_argument_error_class,
21
- "[#{@context.class.name}] Unexpected attributes: `#{unnecessary_attributes.join(', ')}`"
20
+ message_text = I18n.t(
21
+ "servactory.input_arguments.tools.find_unnecessary.error",
22
+ service_class_name: @context.class.name,
23
+ unnecessary_attributes: unnecessary_attributes.join(", ")
24
+ )
25
+
26
+ raise Servactory.configuration.input_argument_error_class, message_text
22
27
  end
23
28
 
24
29
  private
@@ -28,9 +28,14 @@ module Servactory
28
28
  end
29
29
 
30
30
  def raise_error_for(input_argument)
31
- raise Servactory.configuration.input_argument_error_class,
32
- "[#{@context.class.name}] Conflict in `#{input_argument.name}` input " \
33
- "options: `#{input_argument.conflict_code}`"
31
+ message_text = I18n.t(
32
+ "servactory.input_arguments.tools.rules.error",
33
+ service_class_name: @context.class.name,
34
+ input_name: input_argument.name,
35
+ conflict_code: input_argument.conflict_code
36
+ )
37
+
38
+ raise Servactory.configuration.input_argument_error_class, message_text
34
39
  end
35
40
  end
36
41
  end
@@ -5,8 +5,13 @@ module Servactory
5
5
  module Checks
6
6
  class Type < Base
7
7
  DEFAULT_MESSAGE = lambda do |service_class_name:, internal_argument:, expected_type:, given_type:|
8
- "The \"#{internal_argument.name}\" internal argument on \"#{service_class_name}\" must be of type " \
9
- "\"#{expected_type}\" but was \"#{given_type}\""
8
+ I18n.t(
9
+ "servactory.internal_arguments.checks.type.default_error",
10
+ service_class_name: service_class_name,
11
+ internal_argument_name: internal_argument.name,
12
+ expected_type: expected_type,
13
+ given_type: given_type
14
+ )
10
15
  end
11
16
 
12
17
  private_constant :DEFAULT_MESSAGE
@@ -5,8 +5,13 @@ module Servactory
5
5
  module Checks
6
6
  class Type < Base
7
7
  DEFAULT_MESSAGE = lambda do |service_class_name:, output_argument:, expected_type:, given_type:|
8
- "The \"#{output_argument.name}\" output argument on \"#{service_class_name}\" must be of type " \
9
- "\"#{expected_type}\" but was \"#{given_type}\""
8
+ I18n.t(
9
+ "servactory.output_arguments.checks.type.default_error",
10
+ service_class_name: service_class_name,
11
+ output_argument_name: output_argument.name,
12
+ expected_type: expected_type,
13
+ given_type: given_type
14
+ )
10
15
  end
11
16
 
12
17
  private_constant :DEFAULT_MESSAGE
@@ -17,9 +17,13 @@ module Servactory
17
17
  def check!
18
18
  return if overlapping_attributes.empty?
19
19
 
20
- raise Servactory.configuration.output_argument_error_class,
21
- "The \"#{@context.class.name}\" service contains internal attributes that " \
22
- "conflict with outputs: \"#{overlapping_attributes.join(', ')}\""
20
+ message_text = I18n.t(
21
+ "servactory.output_arguments.tools.conflicts.error",
22
+ service_class_name: @context.class.name,
23
+ overlapping_attributes: overlapping_attributes.join(", ")
24
+ )
25
+
26
+ raise Servactory.configuration.output_argument_error_class, message_text
23
27
  end
24
28
 
25
29
  private
@@ -9,13 +9,24 @@ module Servactory
9
9
  private
10
10
 
11
11
  def prepare_for(context:, collection_of_output_arguments:)
12
+ prepare_outputs_with(context: context, collection_of_output_arguments: collection_of_output_arguments)
13
+ prepare_statuses_with(context: context)
14
+
15
+ self
16
+ end
17
+
18
+ def prepare_outputs_with(context:, collection_of_output_arguments:)
12
19
  collection_of_output_arguments.each do |output|
13
20
  self.class.attr_reader(:"#{output.name}")
14
21
 
15
22
  instance_variable_set(:"@#{output.name}", context.instance_variable_get(:"@#{output.name}"))
16
23
  end
24
+ end
17
25
 
18
- self
26
+ def prepare_statuses_with(context:)
27
+ define_singleton_method(:errors) { context.errors }
28
+ define_singleton_method(:success?) { context.errors.empty? }
29
+ define_singleton_method(:failure?) { !context.errors.empty? }
19
30
  end
20
31
  end
21
32
  end
@@ -4,7 +4,7 @@ module Servactory
4
4
  module VERSION
5
5
  MAJOR = 1
6
6
  MINOR = 4
7
- PATCH = 4
7
+ PATCH = 6
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
10
10
  end
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 1.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Sokolov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-15 00:00:00.000000000 Z
11
+ date: 2023-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: zeitwerk
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.6'
19
+ version: '7.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.6'
26
+ version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activesupport
28
+ name: i18n
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '7.0'
33
+ version: '1.13'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '7.0'
40
+ version: '1.13'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: zeitwerk
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '13.0'
48
- type: :development
47
+ version: '2.6'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '13.0'
54
+ version: '2.6'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rbs
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -159,6 +173,7 @@ extra_rdoc_files: []
159
173
  files:
160
174
  - README.md
161
175
  - Rakefile
176
+ - config/locales/en.yml
162
177
  - lib/servactory.rb
163
178
  - lib/servactory/base.rb
164
179
  - lib/servactory/configuration/dsl.rb
@@ -183,6 +198,8 @@ files:
183
198
  - lib/servactory/input_arguments/checks/required.rb
184
199
  - lib/servactory/input_arguments/checks/type.rb
185
200
  - lib/servactory/input_arguments/collection.rb
201
+ - lib/servactory/input_arguments/define_input_conflict.rb
202
+ - lib/servactory/input_arguments/define_input_method.rb
186
203
  - lib/servactory/input_arguments/dsl.rb
187
204
  - lib/servactory/input_arguments/input_argument.rb
188
205
  - lib/servactory/input_arguments/option.rb