servactory 1.9.6 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/config/locales/en.yml +19 -4
  3. data/config/locales/ru.yml +21 -6
  4. data/lib/servactory/{methods/method.rb → actions/action.rb} +2 -2
  5. data/lib/servactory/{methods/aliases_for_make → actions/aliases}/collection.rb +2 -2
  6. data/lib/servactory/{methods/method_collection.rb → actions/collection.rb} +3 -3
  7. data/lib/servactory/{methods → actions}/dsl.rb +9 -9
  8. data/lib/servactory/{methods/shortcuts_for_make → actions/shortcuts}/collection.rb +2 -2
  9. data/lib/servactory/actions/stages/collection.rb +20 -0
  10. data/lib/servactory/actions/stages/stage.rb +30 -0
  11. data/lib/servactory/{methods → actions}/tools/runner.rb +1 -1
  12. data/lib/servactory/{methods → actions}/workspace.rb +4 -2
  13. data/lib/servactory/base.rb +1 -1
  14. data/lib/servactory/configuration/dsl.rb +4 -2
  15. data/lib/servactory/configuration/factory.rb +12 -4
  16. data/lib/servactory/configuration/setup.rb +24 -8
  17. data/lib/servactory/context/workspace/inputs.rb +43 -7
  18. data/lib/servactory/context/workspace/outputs.rb +1 -1
  19. data/lib/servactory/context/workspace.rb +0 -4
  20. data/lib/servactory/dsl.rb +18 -1
  21. data/lib/servactory/inputs/collection.rb +1 -1
  22. data/lib/servactory/inputs/dsl.rb +2 -0
  23. data/lib/servactory/inputs/input.rb +106 -88
  24. data/lib/servactory/inputs/tools/distributor.rb +24 -0
  25. data/lib/servactory/inputs/tools/rules.rb +3 -3
  26. data/lib/servactory/inputs/tools/{find_unnecessary.rb → unnecessary.rb} +4 -4
  27. data/lib/servactory/inputs/tools/validation.rb +5 -7
  28. data/lib/servactory/inputs/validations/base.rb +1 -1
  29. data/lib/servactory/inputs/validations/inclusion.rb +15 -10
  30. data/lib/servactory/inputs/validations/must.rb +26 -17
  31. data/lib/servactory/inputs/validations/required.rb +16 -11
  32. data/lib/servactory/inputs/validations/type.rb +19 -69
  33. data/lib/servactory/inputs/workspace.rb +6 -3
  34. data/lib/servactory/internals/dsl.rb +6 -1
  35. data/lib/servactory/internals/internal.rb +81 -14
  36. data/lib/servactory/internals/validations/base.rb +1 -1
  37. data/lib/servactory/internals/validations/type.rb +6 -43
  38. data/lib/servactory/maintenance/attributes/define_conflict.rb +15 -0
  39. data/lib/servactory/maintenance/attributes/define_method.rb +17 -0
  40. data/lib/servactory/maintenance/attributes/option.rb +121 -0
  41. data/lib/servactory/maintenance/attributes/option_helper.rb +17 -0
  42. data/lib/servactory/maintenance/attributes/option_helpers_collection.rb +20 -0
  43. data/lib/servactory/maintenance/attributes/options_collection.rb +48 -0
  44. data/lib/servactory/maintenance/collection_mode/class_names_collection.rb +16 -0
  45. data/lib/servactory/maintenance/hash_mode/class_names_collection.rb +16 -0
  46. data/lib/servactory/maintenance/validations/collection.rb +66 -0
  47. data/lib/servactory/maintenance/validations/object_schema.rb +116 -0
  48. data/lib/servactory/maintenance/validations/types.rb +181 -0
  49. data/lib/servactory/outputs/dsl.rb +6 -1
  50. data/lib/servactory/outputs/output.rb +79 -19
  51. data/lib/servactory/outputs/validations/base.rb +1 -1
  52. data/lib/servactory/outputs/validations/type.rb +6 -45
  53. data/lib/servactory/version.rb +5 -4
  54. data/lib/servactory.rb +1 -1
  55. metadata +56 -30
  56. data/lib/servactory/inputs/define_input_conflict.rb +0 -13
  57. data/lib/servactory/inputs/define_input_method.rb +0 -15
  58. data/lib/servactory/inputs/option.rb +0 -98
  59. data/lib/servactory/inputs/option_helper.rb +0 -15
  60. data/lib/servactory/inputs/option_helpers_collection.rb +0 -18
  61. data/lib/servactory/inputs/options_collection.rb +0 -46
  62. data/lib/servactory/methods/stage.rb +0 -28
  63. data/lib/servactory/methods/stage_collection.rb +0 -18
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servactory
4
+ module Maintenance
5
+ module Validations
6
+ class ObjectSchema
7
+ RESERVED_ATTRIBUTES = %i[type required default].freeze
8
+ private_constant :RESERVED_ATTRIBUTES
9
+
10
+ attr_reader :errors
11
+
12
+ def self.validate(...)
13
+ new(...).validate
14
+ end
15
+
16
+ def initialize(object:, schema:)
17
+ @object = object
18
+ @schema = schema.fetch(:is)
19
+
20
+ @errors = []
21
+ end
22
+
23
+ def validate
24
+ validate_for(object: @object, schema: @schema)
25
+
26
+ self
27
+ end
28
+
29
+ def valid?
30
+ @errors.empty?
31
+ end
32
+
33
+ private
34
+
35
+ def validate_for(object:, schema:, root_schema_key: nil) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
36
+ unless object.respond_to?(:fetch)
37
+ add_error(key_name: root_schema_key, expected_type: Hash.name, given_type: object.class.name)
38
+ return
39
+ end
40
+
41
+ schema.each do |schema_key, schema_value|
42
+ attribute_type = schema_value.fetch(:type, String)
43
+
44
+ if attribute_type == Hash
45
+ validate_for(
46
+ object: object.fetch(schema_key, {}),
47
+ schema: schema_value.except(*RESERVED_ATTRIBUTES),
48
+ root_schema_key: schema_key
49
+ )
50
+ else
51
+ is_success = validate_with(
52
+ object: object,
53
+ schema_key: schema_key,
54
+ schema_value: schema_value,
55
+ attribute_type: attribute_type,
56
+ attribute_required: schema_value.fetch(:required, true)
57
+ )
58
+
59
+ next if is_success
60
+
61
+ add_error(
62
+ key_name: schema_key,
63
+ expected_type: attribute_type,
64
+ given_type: object.fetch(schema_key, nil).class.name
65
+ )
66
+ end
67
+ end
68
+ end
69
+
70
+ def validate_with(object:, schema_key:, schema_value:, attribute_type:, attribute_required:) # rubocop:disable Metrics/MethodLength
71
+ unless should_be_checked_for?(
72
+ object: object,
73
+ schema_key: schema_key,
74
+ schema_value: schema_value,
75
+ required: attribute_required
76
+ ) # do
77
+ return true
78
+ end
79
+
80
+ value = object.fetch(schema_key, nil)
81
+ prepared_value = prepare_value_from(schema_value: schema_value, value: value, required: attribute_required)
82
+
83
+ Array(attribute_type).any? { |type| prepared_value.is_a?(type) }
84
+ end
85
+
86
+ def should_be_checked_for?(object:, schema_key:, schema_value:, required:)
87
+ required || (
88
+ !required && !fetch_default_from(schema_value).nil?
89
+ ) || (
90
+ !required && !object.fetch(schema_key, nil).nil?
91
+ )
92
+ end
93
+
94
+ def prepare_value_from(schema_value:, value:, required:)
95
+ if !required && !fetch_default_from(schema_value).nil? && value.blank?
96
+ fetch_default_from(schema_value)
97
+ else
98
+ value
99
+ end
100
+ end
101
+
102
+ def fetch_default_from(value)
103
+ value.fetch(:default, nil)
104
+ end
105
+
106
+ def add_error(key_name:, expected_type:, given_type:)
107
+ @errors << {
108
+ key_name: key_name,
109
+ expected_type: expected_type,
110
+ given_type: given_type
111
+ }
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servactory
4
+ module Maintenance
5
+ module Validations
6
+ class Types # rubocop:disable Metrics/ClassLength
7
+ DEFAULT_MESSAGE = lambda do | # rubocop:disable Metrics/BlockLength
8
+ service_class_name:,
9
+ attribute_system_name:,
10
+ attribute:,
11
+ value:,
12
+ key_name:,
13
+ expected_type:,
14
+ given_type:
15
+ | # do
16
+ if attribute.collection_mode?
17
+ collection_message = attribute.consists_of.fetch(:message)
18
+
19
+ if collection_message.is_a?(Proc)
20
+ collection_message.call(
21
+ "#{attribute_system_name}_name": attribute.name,
22
+ expected_type: expected_type,
23
+ given_type: given_type
24
+ )
25
+ elsif collection_message.is_a?(String) && collection_message.present?
26
+ collection_message
27
+ elsif value.is_a?(attribute.types.fetch(0, Array))
28
+ I18n.t(
29
+ "servactory.#{attribute_system_name.to_s.pluralize}.checks.type.default_error.for_collection.wrong_element_type", # rubocop:disable Layout/LineLength
30
+ service_class_name: service_class_name,
31
+ "#{attribute_system_name}_name": attribute.name,
32
+ expected_type: expected_type,
33
+ given_type: given_type
34
+ )
35
+ else
36
+ I18n.t(
37
+ "servactory.#{attribute_system_name.to_s.pluralize}.checks.type.default_error.for_collection.wrong_type", # rubocop:disable Layout/LineLength
38
+ service_class_name: service_class_name,
39
+ "#{attribute_system_name}_name": attribute.name,
40
+ expected_type: attribute.types.fetch(0, Array),
41
+ given_type: value.class.name
42
+ )
43
+ end
44
+ elsif attribute.hash_mode? && key_name.present?
45
+ hash_message = attribute.schema.fetch(:message)
46
+
47
+ if hash_message.is_a?(Proc)
48
+ hash_message.call(
49
+ "#{attribute_system_name}_name": attribute.name,
50
+ key_name: key_name,
51
+ expected_type: expected_type,
52
+ given_type: given_type
53
+ )
54
+ elsif hash_message.is_a?(String) && hash_message.present?
55
+ hash_message
56
+ else
57
+ I18n.t(
58
+ "servactory.#{attribute_system_name.to_s.pluralize}.checks.type.default_error.for_hash.wrong_element_type", # rubocop:disable Layout/LineLength
59
+ service_class_name: service_class_name,
60
+ "#{attribute_system_name}_name": attribute.name,
61
+ key_name: key_name,
62
+ expected_type: expected_type,
63
+ given_type: given_type
64
+ )
65
+ end
66
+ else
67
+ I18n.t(
68
+ "servactory.#{attribute_system_name.to_s.pluralize}.checks.type.default_error.default",
69
+ service_class_name: service_class_name,
70
+ "#{attribute_system_name}_name": attribute.name,
71
+ expected_type: expected_type,
72
+ given_type: given_type
73
+ )
74
+ end
75
+ end
76
+
77
+ private_constant :DEFAULT_MESSAGE
78
+
79
+ def self.validate!(...)
80
+ new(...).validate!
81
+ end
82
+
83
+ def initialize(context:, attribute:, types:, value:, error_callback:)
84
+ @context = context
85
+ @attribute = attribute
86
+ @types = types
87
+ @value = value
88
+ @error_callback = error_callback
89
+ end
90
+
91
+ def validate! # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
92
+ collection_validator = nil
93
+ object_schema_validator = nil
94
+
95
+ return if prepared_types.any? do |type|
96
+ if @attribute.collection_mode?
97
+ collection_validator = Servactory::Maintenance::Validations::Collection.validate(
98
+ value: @value,
99
+ types: @attribute.types,
100
+ type: type
101
+ )
102
+
103
+ collection_validator.valid?
104
+ elsif @attribute.hash_mode?
105
+ object_schema_validator = Servactory::Maintenance::Validations::ObjectSchema.validate(
106
+ object: @value,
107
+ schema: @attribute.schema
108
+ )
109
+
110
+ object_schema_validator.valid?
111
+ else
112
+ @value.is_a?(type)
113
+ end
114
+ end
115
+
116
+ if (first_error = collection_validator&.errors&.first).present?
117
+ return @error_callback.call(
118
+ message: DEFAULT_MESSAGE,
119
+ service_class_name: @context.class.name,
120
+ attribute_system_name: attribute_system_name,
121
+ attribute: @attribute,
122
+ value: @value,
123
+ key_name: nil,
124
+ expected_type: first_error.fetch(:expected_type),
125
+ given_type: first_error.fetch(:given_type)
126
+ )
127
+ end
128
+
129
+ if (first_error = object_schema_validator&.errors&.first).present?
130
+ return @error_callback.call(
131
+ message: DEFAULT_MESSAGE,
132
+ service_class_name: @context.class.name,
133
+ attribute_system_name: attribute_system_name,
134
+ attribute: @attribute,
135
+ value: @value,
136
+ key_name: first_error.fetch(:key_name),
137
+ expected_type: first_error.fetch(:expected_type),
138
+ given_type: first_error.fetch(:given_type)
139
+ )
140
+ end
141
+
142
+ @error_callback.call(
143
+ message: DEFAULT_MESSAGE,
144
+ service_class_name: @context.class.name,
145
+ attribute_system_name: attribute_system_name,
146
+ attribute: @attribute,
147
+ value: @value,
148
+ key_name: nil,
149
+ expected_type: prepared_types.join(", "),
150
+ given_type: @value.class.name
151
+ )
152
+ end
153
+
154
+ private
155
+
156
+ def attribute_system_name
157
+ @attribute.class.name.demodulize.downcase.to_sym
158
+ end
159
+
160
+ def prepared_types
161
+ @prepared_types ||=
162
+ if @attribute.collection_mode?
163
+ prepared_types_from(Array(@attribute.consists_of.fetch(:type, [])))
164
+ else
165
+ prepared_types_from(@types)
166
+ end
167
+ end
168
+
169
+ def prepared_types_from(types)
170
+ types.map do |type|
171
+ if type.is_a?(String)
172
+ Object.const_get(type)
173
+ else
174
+ type
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
@@ -17,7 +17,12 @@ module Servactory
17
17
  private
18
18
 
19
19
  def output(name, **options)
20
- collection_of_outputs << Output.new(name, **options)
20
+ collection_of_outputs << Output.new(
21
+ name,
22
+ collection_mode_class_names: config.collection_mode_class_names,
23
+ hash_mode_class_names: config.hash_mode_class_names,
24
+ **options
25
+ )
21
26
  end
22
27
 
23
28
  def collection_of_outputs
@@ -4,36 +4,96 @@ module Servactory
4
4
  module Outputs
5
5
  class Output
6
6
  attr_reader :name,
7
- :types,
8
- :required,
9
- :default
7
+ :collection_mode_class_names,
8
+ :hash_mode_class_names
10
9
 
11
- def initialize(name, type:, **options)
10
+ def initialize(
11
+ name,
12
+ collection_mode_class_names:,
13
+ hash_mode_class_names:,
14
+ **options
15
+ )
12
16
  @name = name
13
- @types = Array(type)
17
+ @collection_mode_class_names = collection_mode_class_names
18
+ @hash_mode_class_names = hash_mode_class_names
14
19
 
15
- @required = options.fetch(:required, true)
16
- @default = required? ? nil : options.fetch(:default, nil)
20
+ add_basic_options_with(options)
17
21
  end
18
22
 
19
- def options_for_checks
20
- {
21
- types: types,
22
- required: required,
23
- default: default
24
- }
23
+ def method_missing(name, *args, &block)
24
+ option = collection_of_options.find_by(name: name)
25
+
26
+ return super if option.nil?
27
+
28
+ option.body
29
+ end
30
+
31
+ def respond_to_missing?(name, *)
32
+ collection_of_options.names.include?(name) || super
33
+ end
34
+
35
+ def add_basic_options_with(options)
36
+ # Check Class: Servactory::Outputs::Validations::Type
37
+ add_types_option_with(options)
38
+ add_collection_option_with(options)
39
+ add_hash_option_with(options)
40
+ end
41
+
42
+ def add_types_option_with(options)
43
+ collection_of_options << Servactory::Maintenance::Attributes::Option.new(
44
+ name: :types,
45
+ attribute: self,
46
+ validation_class: Servactory::Internals::Validations::Type,
47
+ original_value: Array(options.fetch(:type)),
48
+ need_for_checks: true,
49
+ body_fallback: nil,
50
+ with_advanced_mode: false
51
+ )
25
52
  end
26
53
 
27
- def required?
28
- Servactory::Utils.true?(required)
54
+ def add_collection_option_with(options) # rubocop:disable Metrics/MethodLength
55
+ collection_of_options << Servactory::Maintenance::Attributes::Option.new(
56
+ name: :consists_of,
57
+ attribute: self,
58
+ validation_class: Servactory::Internals::Validations::Type,
59
+ define_methods: [
60
+ Servactory::Maintenance::Attributes::DefineMethod.new(
61
+ name: :collection_mode?,
62
+ content: ->(**) { collection_mode_class_names.include?(options.fetch(:type)) }
63
+ )
64
+ ],
65
+ need_for_checks: false,
66
+ body_key: :type,
67
+ body_value: String,
68
+ body_fallback: String,
69
+ **options
70
+ )
29
71
  end
30
72
 
31
- def optional?
32
- !required?
73
+ def add_hash_option_with(options) # rubocop:disable Metrics/MethodLength
74
+ collection_of_options << Servactory::Maintenance::Attributes::Option.new(
75
+ name: :schema,
76
+ attribute: self,
77
+ validation_class: Servactory::Inputs::Validations::Type,
78
+ define_methods: [
79
+ Servactory::Maintenance::Attributes::DefineMethod.new(
80
+ name: :hash_mode?,
81
+ content: ->(**) { hash_mode_class_names.include?(options.fetch(:type)) }
82
+ )
83
+ ],
84
+ need_for_checks: false,
85
+ body_key: :is,
86
+ body_fallback: {},
87
+ **options
88
+ )
33
89
  end
34
90
 
35
- def default_value_present?
36
- !default.nil?
91
+ def collection_of_options
92
+ @collection_of_options ||= Servactory::Maintenance::Attributes::OptionsCollection.new
93
+ end
94
+
95
+ def options_for_checks
96
+ collection_of_options.options_for_checks
37
97
  end
38
98
  end
39
99
  end
@@ -6,7 +6,7 @@ module Servactory
6
6
  class Base
7
7
  protected
8
8
 
9
- def raise_error_with(message, **attributes)
9
+ def raise_error_with(message:, **attributes)
10
10
  message = message.call(**attributes) if message.is_a?(Proc)
11
11
 
12
12
  raise @context.class.config.output_error_class.new(message: message)
@@ -4,24 +4,10 @@ module Servactory
4
4
  module Outputs
5
5
  module Validations
6
6
  class Type < Base
7
- DEFAULT_MESSAGE = lambda do |service_class_name:, output:, expected_type:, given_type:|
8
- I18n.t(
9
- "servactory.outputs.checks.type.default_error",
10
- service_class_name: service_class_name,
11
- output_name: output.name,
12
- expected_type: expected_type,
13
- given_type: given_type
14
- )
15
- end
16
-
17
- private_constant :DEFAULT_MESSAGE
18
-
19
7
  def self.validate!(...)
20
8
  new(...).validate!
21
9
  end
22
10
 
23
- ##########################################################################
24
-
25
11
  def initialize(context:, output:, value:)
26
12
  super()
27
13
 
@@ -31,39 +17,14 @@ module Servactory
31
17
  end
32
18
 
33
19
  def validate!
34
- return unless should_be_checked?
35
-
36
- return if prepared_types.any? { |type| @value.is_a?(type) }
37
-
38
- raise_error_with(
39
- DEFAULT_MESSAGE,
40
- service_class_name: @context.class.name,
41
- output: @output,
42
- expected_type: prepared_types.join(", "),
43
- given_type: @value.class.name
20
+ Servactory::Maintenance::Validations::Types.validate!(
21
+ context: @context,
22
+ attribute: @output,
23
+ types: @output.types,
24
+ value: @value,
25
+ error_callback: ->(**args) { raise_error_with(**args) }
44
26
  )
45
27
  end
46
-
47
- private
48
-
49
- def should_be_checked?
50
- @output.required? || (
51
- @output.optional? && !@output.default.nil?
52
- ) || (
53
- @output.optional? && !@value.nil?
54
- )
55
- end
56
-
57
- def prepared_types
58
- @prepared_types ||=
59
- Array(@output.types).map do |type|
60
- if type.is_a?(String)
61
- Object.const_get(type)
62
- else
63
- type
64
- end
65
- end
66
- end
67
28
  end
68
29
  end
69
30
  end
@@ -2,10 +2,11 @@
2
2
 
3
3
  module Servactory
4
4
  module VERSION
5
- MAJOR = 1
6
- MINOR = 9
7
- PATCH = 6
5
+ MAJOR = 2
6
+ MINOR = 0
7
+ PATCH = 1
8
+ PRE = nil
8
9
 
9
- STRING = [MAJOR, MINOR, PATCH].join(".")
10
+ STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
10
11
  end
11
12
  end
data/lib/servactory.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "zeitwerk"
4
4
 
5
- require "active_support/core_ext/string"
5
+ require "active_support/all"
6
6
 
7
7
  loader = Zeitwerk::Loader.for_gem
8
8
  loader.inflector.inflect(