serega 0.42.0 → 0.50.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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +124 -1207
  3. data/VERSION +1 -1
  4. data/lib/serega/attribute.rb +186 -131
  5. data/lib/serega/attribute_normalizer.rb +164 -345
  6. data/lib/serega/attribute_normalizers/batch.rb +45 -0
  7. data/lib/serega/attribute_normalizers/block.rb +81 -0
  8. data/lib/serega/attribute_normalizers/delegate.rb +34 -0
  9. data/lib/serega/attribute_normalizers/hash_access.rb +37 -0
  10. data/lib/serega/attribute_normalizers/preloads.rb +46 -0
  11. data/lib/serega/attribute_value_resolvers/batch.rb +5 -54
  12. data/lib/serega/attribute_value_resolvers/const.rb +2 -24
  13. data/lib/serega/attribute_value_resolvers/delegate.rb +17 -28
  14. data/lib/serega/attribute_value_resolvers/hash_access.rb +34 -52
  15. data/lib/serega/attribute_value_resolvers/keyword.rb +10 -25
  16. data/lib/serega/attribute_values.rb +46 -0
  17. data/lib/serega/batch_loader.rb +37 -0
  18. data/lib/serega/conditions.rb +56 -0
  19. data/lib/serega/config.rb +105 -144
  20. data/lib/serega/engine/pulls.rb +64 -0
  21. data/lib/serega/engine/run.rb +106 -0
  22. data/lib/serega/errors.rb +36 -8
  23. data/lib/serega/formatter.rb +98 -0
  24. data/lib/serega/plan/cache.rb +96 -0
  25. data/lib/serega/plan/per_ractor_cache.rb +23 -0
  26. data/lib/serega/plan.rb +101 -128
  27. data/lib/serega/plan_point.rb +44 -151
  28. data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +13 -80
  29. data/lib/serega/plugins/activerecord_preloads/lib/preloader.rb +8 -75
  30. data/lib/serega/plugins/context_metadata/context_metadata.rb +40 -123
  31. data/lib/serega/plugins/metadata/check_params.rb +80 -0
  32. data/lib/serega/plugins/metadata/meta_attribute.rb +40 -79
  33. data/lib/serega/plugins/metadata/metadata.rb +40 -168
  34. data/lib/serega/plugins/root/root.rb +91 -235
  35. data/lib/serega/plugins.rb +16 -49
  36. data/lib/serega/presenter.rb +61 -19
  37. data/lib/serega/result_builder.rb +68 -0
  38. data/lib/serega/result_code.rb +203 -0
  39. data/lib/serega/shareable.rb +52 -0
  40. data/lib/serega/source_group.rb +187 -0
  41. data/lib/serega/utils/collection_detector.rb +19 -13
  42. data/lib/serega/utils/deep_merge.rb +26 -0
  43. data/lib/serega/utils/enum_deep_dup.rb +10 -16
  44. data/lib/serega/utils/enum_deep_freeze.rb +8 -14
  45. data/lib/serega/utils/method_signature.rb +6 -15
  46. data/lib/serega/utils/parse_string_modifiers.rb +63 -0
  47. data/lib/serega/utils/ractor_local.rb +36 -0
  48. data/lib/serega/utils/serialized_attribute_error.rb +60 -20
  49. data/lib/serega/utils/to_hash.rb +5 -26
  50. data/lib/serega/validations/attribute/check_block.rb +3 -15
  51. data/lib/serega/validations/attribute/check_name.rb +4 -15
  52. data/lib/serega/validations/attribute/check_opt_base_serializer.rb +3 -15
  53. data/lib/serega/validations/attribute/check_opt_batch.rb +26 -56
  54. data/lib/serega/validations/attribute/check_opt_condition.rb +55 -0
  55. data/lib/serega/validations/attribute/check_opt_delegate.rb +10 -63
  56. data/lib/serega/validations/attribute/check_opt_format.rb +36 -0
  57. data/lib/serega/validations/attribute/check_opt_hash_access.rb +11 -59
  58. data/lib/serega/validations/attribute/check_opt_hide.rb +3 -14
  59. data/lib/serega/validations/attribute/check_opt_many.rb +18 -20
  60. data/lib/serega/validations/attribute/check_opt_method.rb +3 -25
  61. data/lib/serega/validations/attribute/check_opt_preload.rb +3 -26
  62. data/lib/serega/validations/attribute/check_opt_serializer.rb +4 -18
  63. data/lib/serega/validations/attribute/check_opt_value.rb +3 -21
  64. data/lib/serega/validations/check_attribute_params.rb +92 -71
  65. data/lib/serega/validations/check_batch_loader_params.rb +43 -62
  66. data/lib/serega/validations/check_formatter.rb +80 -0
  67. data/lib/serega/validations/check_serialize_keywords.rb +23 -0
  68. data/lib/serega/validations/initiate/check_modifiers.rb +14 -20
  69. data/lib/serega/validations/utils/check_allowed_keys.rb +3 -13
  70. data/lib/serega/validations/utils/check_hash_access_value.rb +44 -0
  71. data/lib/serega/validations/utils/check_opt_is_bool.rb +3 -13
  72. data/lib/serega/validations/utils/check_opt_is_hash.rb +3 -13
  73. data/lib/serega/validations/utils/check_opt_is_string_or_symbol.rb +3 -13
  74. data/lib/serega/version.rb +1 -4
  75. data/lib/serega.rb +459 -388
  76. data/sig/serega/plugins.rbs +49 -0
  77. data/sig/serega.rbs +142 -0
  78. metadata +42 -38
  79. data/lib/serega/data_builder.rb +0 -54
  80. data/lib/serega/engine/level.rb +0 -59
  81. data/lib/serega/engine/level_queue.rb +0 -56
  82. data/lib/serega/engine/loader.rb +0 -70
  83. data/lib/serega/helpers/serializer_class_helper.rb +0 -19
  84. data/lib/serega/object_serializer.rb +0 -125
  85. data/lib/serega/plugins/camel_case/camel_case.rb +0 -213
  86. data/lib/serega/plugins/depth_limit/depth_limit.rb +0 -206
  87. data/lib/serega/plugins/explicit_many_option/explicit_many_option.rb +0 -69
  88. data/lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb +0 -38
  89. data/lib/serega/plugins/formatters/formatters.rb +0 -322
  90. data/lib/serega/plugins/if/if.rb +0 -287
  91. data/lib/serega/plugins/if/validations/check_opt_if.rb +0 -72
  92. data/lib/serega/plugins/if/validations/check_opt_if_value.rb +0 -77
  93. data/lib/serega/plugins/if/validations/check_opt_unless.rb +0 -72
  94. data/lib/serega/plugins/if/validations/check_opt_unless_value.rb +0 -77
  95. data/lib/serega/plugins/metadata/validations/check_block.rb +0 -47
  96. data/lib/serega/plugins/metadata/validations/check_opt_const.rb +0 -39
  97. data/lib/serega/plugins/metadata/validations/check_opt_hide_empty.rb +0 -35
  98. data/lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb +0 -35
  99. data/lib/serega/plugins/metadata/validations/check_opt_value.rb +0 -61
  100. data/lib/serega/plugins/metadata/validations/check_opts.rb +0 -59
  101. data/lib/serega/plugins/metadata/validations/check_path.rb +0 -50
  102. data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +0 -111
  103. data/lib/serega/plugins/string_modifiers/string_modifiers.rb +0 -63
  104. data/lib/serega/utils/symbol_name.rb +0 -39
  105. data/lib/serega/validations/attribute/check_opt_const.rb +0 -40
  106. data/lib/serega/validations/check_initiate_params.rb +0 -57
  107. data/lib/serega/validations/check_serialize_params.rb +0 -54
@@ -1,31 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Serega
4
- # @private
5
- module SeregaValidations
6
- # @private
7
- module Attribute
4
+ module SeregaValidations # :nodoc:
5
+ module Attribute # :nodoc:
8
6
  #
9
7
  # Attribute `:serializer` option validator
10
8
  #
11
- # @private
12
- class CheckOptSerializer
9
+ class CheckOptSerializer # :nodoc:
13
10
  class << self
14
- #
15
11
  # Checks attribute :serializer option
16
- #
17
- # @param opts [Hash] Attribute options
18
- # @param block [nil, Proc] Attribute block (defines a nested serializer)
19
- #
20
- # @raise [SeregaError] SeregaError that option has invalid value
21
- #
22
- # @return [void]
23
- #
24
- def call(opts, block = nil)
12
+ def call(opts)
25
13
  return unless opts.key?(:serializer)
26
14
 
27
- raise SeregaError, "Option :serializer can not be used together with block" if block
28
-
29
15
  value = opts[:serializer]
30
16
  return if valid_serializer?(value)
31
17
 
@@ -1,40 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Serega
4
- # @private
5
- module SeregaValidations
6
- # @private
7
- module Attribute
4
+ module SeregaValidations # :nodoc:
5
+ module Attribute # :nodoc:
8
6
  #
9
7
  # Attribute `:value` option validator
10
8
  #
11
- # @private
12
- class CheckOptValue
9
+ class CheckOptValue # :nodoc:
13
10
  class << self
14
- #
15
11
  # Checks attribute :value option
16
- #
17
- # @param opts [Hash] Attribute options
18
- #
19
- # @raise [SeregaError] SeregaError that option has invalid value
20
- #
21
- # @return [void]
22
- #
23
12
  def call(opts)
24
13
  return unless opts.key?(:value)
25
14
 
26
- check_usage_with_other_params(opts)
27
-
28
15
  check_value(opts[:value])
29
16
  end
30
17
 
31
18
  private
32
19
 
33
- def check_usage_with_other_params(opts)
34
- raise SeregaError, "Option :value can not be used together with option :method" if opts.key?(:method)
35
- raise SeregaError, "Option :value can not be used together with option :const" if opts.key?(:const)
36
- end
37
-
38
20
  def check_value(value)
39
21
  check_value_type(value)
40
22
  signature = SeregaUtils::MethodSignature.call(value, pos_limit: 2, keyword_args: %i[ctx batches])
@@ -4,92 +4,113 @@ class Serega
4
4
  #
5
5
  # Validations
6
6
  #
7
- # @private
8
- module SeregaValidations
7
+ module SeregaValidations # :nodoc:
9
8
  #
10
9
  # Validations for attribute params
11
10
  #
12
- # @private
13
- class CheckAttributeParams
11
+ class CheckAttributeParams # :nodoc:
12
+ # Options of `Serega.attribute`
13
+ ATTRIBUTE_KEYS = %i[
14
+ method value serializer many hide const delegate default format preload batch
15
+ base_serializer hash_access if unless if_value unless_value
16
+ ].freeze
17
+
18
+ # Options that can't be given together, `block` for the attribute
19
+ # block. Each option lists every option it conflicts with, and the error
20
+ # names the option that comes first here. :hash_access with :delegate is
21
+ # left to CheckOptHashAccess, which points to the delegate sub-options.
22
+ CONFLICTS = {
23
+ method: %i[value const delegate batch],
24
+ value: %i[method const delegate hash_access],
25
+ const: %i[method value delegate batch hash_access preload],
26
+ delegate: %i[method value const batch],
27
+ batch: %i[method const delegate hash_access],
28
+ hash_access: %i[value const batch],
29
+ preload: %i[const],
30
+ serializer: %i[block if_value unless_value],
31
+ if_value: %i[serializer block],
32
+ unless_value: %i[serializer block]
33
+ }.freeze
34
+
35
+ # Validated attribute name
36
+ attr_reader :name
37
+
38
+ # Validated attribute options
39
+ attr_reader :opts
40
+
41
+ # Validated attribute block
42
+ attr_reader :block
43
+
44
+ # Initializes attribute params validator
45
+ def initialize(serializer_class, name, opts, block)
46
+ @serializer_class = serializer_class
47
+ @name = name
48
+ @opts = opts
49
+ @block = block
50
+ end
51
+
14
52
  #
15
- # Validations for attribute params instance methods
53
+ # Validates attribute params
16
54
  #
17
- # @private
18
- module InstanceMethods
19
- # @return [Symbol] validated attribute name
20
- attr_reader :name
21
-
22
- # @return [Hash] validated attribute options
23
- attr_reader :opts
24
-
25
- # @return [nil, Proc] validated attribute block
26
- attr_reader :block
27
-
28
- #
29
- # Initializes attribute params validator
30
- #
31
- # @param name [Symbol] attribute name
32
- # @param opts [Hash] attribute options
33
- # @param block [nil, Proc] block provided to attribute
34
- #
35
- # @return [void]
36
- #
37
- def initialize(name, opts, block)
38
- @name = name
39
- @opts = opts
40
- @block = block
41
- end
55
+ def validate
56
+ check_name if check_attribute_name
57
+ check_opts
58
+ check_block
59
+ end
42
60
 
43
- #
44
- # Validates attribute params
45
- #
46
- def validate
47
- check_name if check_attribute_name
48
- check_opts
49
- check_block
50
- end
61
+ private
51
62
 
52
- private
63
+ def check_name
64
+ Attribute::CheckName.call(name)
65
+ end
53
66
 
54
- def check_name
55
- Attribute::CheckName.call(name)
56
- end
67
+ def check_opts
68
+ Utils::CheckAllowedKeys.call(opts, ATTRIBUTE_KEYS, :attribute)
69
+ check_conflicts
57
70
 
58
- # Patched in:
59
- # - plugin :context_metadata (checks context metadata option which is :meta by default)
60
- # - plugin :formatters (checks :format option)
61
- # - plugin :if (checks :if, :if_value, :unless, :unless_value options)
62
- def check_opts
63
- Utils::CheckAllowedKeys.call(opts, allowed_opts_keys, :attribute)
64
-
65
- Attribute::CheckOptBaseSerializer.call(opts, block)
66
- Attribute::CheckOptConst.call(opts)
67
- Attribute::CheckOptDelegate.call(opts)
68
- Attribute::CheckOptHashAccess.call(opts)
69
- Attribute::CheckOptHide.call(opts)
70
- Attribute::CheckOptMethod.call(opts)
71
- Attribute::CheckOptMany.call(opts, block)
72
- Attribute::CheckOptPreload.call(opts)
73
- Attribute::CheckOptSerializer.call(opts, block)
74
- Attribute::CheckOptValue.call(opts)
75
- Attribute::CheckOptBatch.call(self.class.serializer_class, opts)
76
- end
71
+ Attribute::CheckOptBaseSerializer.call(opts, block)
72
+ Attribute::CheckOptCondition.call(opts, :if)
73
+ Attribute::CheckOptCondition.call(opts, :unless)
74
+ Attribute::CheckOptCondition.call(opts, :if_value)
75
+ Attribute::CheckOptCondition.call(opts, :unless_value)
76
+ Attribute::CheckOptDelegate.call(opts)
77
+ Attribute::CheckOptFormat.call(opts, @serializer_class)
78
+ Attribute::CheckOptHashAccess.call(opts)
79
+ Attribute::CheckOptHide.call(opts)
80
+ Attribute::CheckOptMethod.call(opts)
81
+ Attribute::CheckOptMany.call(opts, block, require_many)
82
+ Attribute::CheckOptPreload.call(opts)
83
+ Attribute::CheckOptSerializer.call(opts)
84
+ Attribute::CheckOptValue.call(opts)
85
+ Attribute::CheckOptBatch.call(@serializer_class, name, opts)
86
+ end
77
87
 
78
- def check_block
79
- Attribute::CheckBlock.call(block)
80
- end
88
+ def check_block
89
+ Attribute::CheckBlock.call(block)
90
+ end
81
91
 
82
- def allowed_opts_keys
83
- self.class.serializer_class.config.attribute_keys
84
- end
92
+ def check_conflicts
93
+ CONFLICTS.each do |option, others|
94
+ next unless opts.key?(option)
85
95
 
86
- def check_attribute_name
87
- self.class.serializer_class.config.check_attribute_name
96
+ other = others.find { |key| (key == :block) ? block : opts.key?(key) }
97
+ raise SeregaError, conflict_message(option, other) if other
88
98
  end
89
99
  end
90
100
 
91
- include InstanceMethods
92
- extend Serega::SeregaHelpers::SerializerClassHelper
101
+ def conflict_message(option, other)
102
+ return "Option #{option.inspect} can not be used together with block" if other == :block
103
+
104
+ "Option #{option.inspect} can not be used together with option #{other.inspect}"
105
+ end
106
+
107
+ def check_attribute_name
108
+ @serializer_class.config.check_attribute_name
109
+ end
110
+
111
+ def require_many
112
+ @serializer_class.config.require_many
113
+ end
93
114
  end
94
115
  end
95
116
  end
@@ -1,83 +1,64 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Serega
4
- # @private
5
- module SeregaValidations
4
+ module SeregaValidations # :nodoc:
6
5
  #
7
6
  # Batch loader parameters validators
8
7
  #
9
- # @private
10
- class CheckBatchLoaderParams
11
- #
12
- # batch_loader parameters validation instance methods
13
- #
14
- # @private
15
- module InstanceMethods
16
- # @return [Symbol] validated batch_loader name
17
- attr_reader :name
8
+ class CheckBatchLoaderParams # :nodoc:
9
+ # Validated batch_loader name
10
+ attr_reader :name
18
11
 
19
- # @return [nil, #call] validated batch_loader value or block
20
- attr_reader :batch_loader
12
+ # Validated batch_loader value or block
13
+ attr_reader :batch_loader
21
14
 
22
- # Instantiates batch loader params checker
23
- # @param name [Symbol, String] Batch loader name
24
- # @param batch_loader [Proc, #call] Batch loader
25
- def initialize(name, batch_loader)
26
- @name = name
27
- @batch_loader = batch_loader
28
- end
29
-
30
- #
31
- # Checks batch loader parameters
32
- #
33
- # @raise [SeregaError] SeregaError that batch loader has invalid arguments
34
- #
35
- # @return [void]
36
- #
37
- def validate
38
- check_name
39
- check_loader
40
- end
15
+ # Instantiates batch loader params checker
16
+ def initialize(name, batch_loader)
17
+ @name = name
18
+ @batch_loader = batch_loader
19
+ end
41
20
 
42
- private
21
+ # Checks batch loader parameters
22
+ def validate
23
+ check_name
24
+ check_loader
25
+ end
43
26
 
44
- def check_name
45
- raise SeregaError, name_type_error if !name.is_a?(Symbol) && !name.is_a?(String)
46
- end
27
+ private
47
28
 
48
- def check_loader
49
- check_batch_loader_type
50
- check_batch_loader_args
51
- end
29
+ def check_name
30
+ raise SeregaError, name_type_error if !name.is_a?(Symbol) && !name.is_a?(String)
31
+ end
52
32
 
53
- def check_batch_loader_type
54
- raise SeregaError, type_error if !batch_loader.is_a?(Proc) && !batch_loader.respond_to?(:call)
55
- end
33
+ def check_loader
34
+ check_batch_loader_type
35
+ check_batch_loader_args
36
+ end
56
37
 
57
- def check_batch_loader_args
58
- signature = SeregaUtils::MethodSignature.call(batch_loader, pos_limit: 2, keyword_args: [:ctx])
59
- raise SeregaError, arguments_error unless %w[1 2 1_ctx].include?(signature)
60
- end
38
+ def check_batch_loader_type
39
+ raise SeregaError, type_error if !batch_loader.is_a?(Proc) && !batch_loader.respond_to?(:call)
40
+ end
61
41
 
62
- def name_type_error
63
- "Batch loader name must be a Symbol or String"
64
- end
42
+ def check_batch_loader_args
43
+ signature = SeregaUtils::MethodSignature.call(batch_loader, pos_limit: 2, keyword_args: [:ctx])
44
+ raise SeregaError, arguments_error unless %w[1 2 1_ctx].include?(signature)
45
+ end
65
46
 
66
- def type_error
67
- "Batch loader value must be a Proc or respond to #call"
68
- end
47
+ def name_type_error
48
+ "Batch loader name must be a Symbol or String"
49
+ end
69
50
 
70
- def arguments_error
71
- <<~ERR.strip
72
- Batch loader arguments should have one of this signatures:
73
- - (objects) # one argument
74
- - (objects, :ctx) # one argument and one :ctx keyword argument
75
- ERR
76
- end
51
+ def type_error
52
+ "Batch loader value must be a Proc or respond to #call"
77
53
  end
78
54
 
79
- include InstanceMethods
80
- extend Serega::SeregaHelpers::SerializerClassHelper
55
+ def arguments_error
56
+ <<~ERR.strip
57
+ Batch loader arguments should have one of this signatures:
58
+ - (objects) # one argument
59
+ - (objects, :ctx) # one argument and one :ctx keyword argument
60
+ ERR
61
+ end
81
62
  end
82
63
  end
83
64
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaValidations # :nodoc:
5
+ #
6
+ # Validator for formatters defined with `Serega.formatter` or given
7
+ # directly as the attribute :format option
8
+ #
9
+ class CheckFormatter # :nodoc:
10
+ class << self
11
+ # Checks the formatter is a callable with valid parameters, a method
12
+ # name, or an Array of a method name and its arguments. The attribute
13
+ # :format option also accepts a Hash with one of them as :use and the
14
+ # :allow_nil option.
15
+ def call(formatter_name, formatter)
16
+ if formatter.is_a?(Hash) && !formatter_name
17
+ Utils::CheckAllowedKeys.call(formatter, %i[use allow_nil], :formatter)
18
+ Utils::CheckOptIsBool.call(formatter, :allow_nil)
19
+ formatter = formatter[:use]
20
+ end
21
+
22
+ check_value(formatter_name, formatter)
23
+ end
24
+
25
+ private
26
+
27
+ def check_value(formatter_name, formatter)
28
+ return if formatter.is_a?(Symbol)
29
+ return if formatter.is_a?(Array) && formatter.first.is_a?(Symbol)
30
+ raise SeregaError, invalid_formatter(formatter_name) unless formatter.respond_to?(:call)
31
+
32
+ signature = SeregaUtils::MethodSignature.call(formatter, pos_limit: 2, keyword_args: [:ctx])
33
+ raise SeregaError, signature_error unless valid_signature?(signature)
34
+ end
35
+
36
+ def valid_signature?(signature)
37
+ case signature
38
+ when "1" # (value)
39
+ true
40
+ when "2" # (value, context)
41
+ true
42
+ when "1_ctx" # (value, :ctx)
43
+ true
44
+ else
45
+ false
46
+ end
47
+ end
48
+
49
+ def invalid_formatter(formatter_name)
50
+ return invalid_format_option unless formatter_name
51
+
52
+ <<~ERROR.strip
53
+ Invalid formatter #{formatter_name.inspect}. A formatter must be one of:
54
+ - a callable, for example ->(value) { value.round(2) }
55
+ - a method name, for example :to_s
56
+ - an Array of a method name and its arguments, for example [:round, 2]
57
+ ERROR
58
+ end
59
+
60
+ def invalid_format_option
61
+ <<~ERROR.strip
62
+ Invalid attribute option :format. It must be a formatter name or one of:
63
+ - a callable, for example ->(value) { value.round(2) }
64
+ - an Array of a method name and its arguments, for example [:round, 2]
65
+ - a Hash with one of them or a method name as :use and the :allow_nil option, for example {use: :to_s, allow_nil: true}
66
+ ERROR
67
+ end
68
+
69
+ def signature_error
70
+ <<~ERROR.strip
71
+ Invalid formatter parameters, valid parameters signatures:
72
+ - (value) # one positional parameter
73
+ - (value, context) # two positional parameters
74
+ - (value, :ctx) # one positional parameter and :ctx keyword
75
+ ERROR
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaValidations # :nodoc:
5
+ #
6
+ # Validator for the :context and :many serialization options
7
+ #
8
+ class CheckSerializeKeywords # :nodoc:
9
+ class << self
10
+ # Checks the context is a Hash and many is a boolean, when given
11
+ def call(context, many)
12
+ unless context.nil? || context.is_a?(Hash)
13
+ raise SeregaError, "Invalid option :context => #{context.inspect}. Must have a Hash value"
14
+ end
15
+
16
+ return if many.nil? || many.equal?(true) || many.equal?(false)
17
+
18
+ raise SeregaError, "Invalid option :many => #{many.inspect}. Must have a boolean value"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,34 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Serega
4
- # @private
5
- module SeregaValidations
4
+ module SeregaValidations # :nodoc:
6
5
  #
7
6
  # Validations that take place when initializing serializer
8
7
  #
9
- # @private
10
- module Initiate
8
+ module Initiate # :nodoc:
11
9
  #
12
10
  # Modifiers validation
13
11
  #
14
- # @private
15
- class CheckModifiers
12
+ class CheckModifiers # :nodoc:
16
13
  #
17
- # Validates provided fields names are existing attributes
18
- #
19
- # @param serializer_class [Serega]
20
- # @param only [Hash, nil] `only` modifier
21
- # @param with [Hash, nil] `with` modifier
22
- # @param except [Hash, nil] `except` modifier
23
- #
24
- # @raise [Serega::AttributeNotExist] when some checked modifier has not existing attribute
25
- #
26
- # @return [void]
14
+ # Instantiates modifiers validator
27
15
  #
16
+ def initialize
17
+ @parents_names = nil
18
+ @error_attributes = nil
19
+ end
20
+
21
+ # Validates provided fields names are existing attributes
28
22
  def call(serializer_class, only, with, except)
29
- validate(serializer_class, only) if only
30
- validate(serializer_class, with) if with
31
- validate(serializer_class, except) if except
23
+ validate(serializer_class, only)
24
+ validate(serializer_class, with)
25
+ validate(serializer_class, except)
32
26
 
33
27
  raise_errors(serializer_class) if any_error?
34
28
  end
@@ -85,7 +79,7 @@ class Serega
85
79
  end
86
80
 
87
81
  def any_error?
88
- defined?(@error_attributes)
82
+ !@error_attributes.nil?
89
83
  end
90
84
  end
91
85
  end
@@ -1,26 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Serega
4
- # @private
5
- module SeregaValidations
4
+ module SeregaValidations # :nodoc:
6
5
  #
7
6
  # Validations Utilities
8
7
  #
9
- # @private
10
- module Utils
8
+ module Utils # :nodoc:
11
9
  #
12
10
  # Utility to check all hash keys are allowed
13
11
  #
14
- # @private
15
- class CheckAllowedKeys
12
+ class CheckAllowedKeys # :nodoc:
16
13
  # Checks hash keys are allowed
17
- #
18
- # @param opts [Hash] Some options Hash
19
- # @param allowed_keys [Array] Allowed hash keys
20
- #
21
- # @raise [Serega::SeregaError] error when any hash key is not allowed
22
- #
23
- # @return [void]
24
14
  def self.call(opts, allowed_keys, parameter_name)
25
15
  opts.each_key do |key|
26
16
  next if allowed_keys.include?(key)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module SeregaValidations # :nodoc:
5
+ module Utils # :nodoc:
6
+ #
7
+ # Validator of a hash access value: the attribute :hash_access option and
8
+ # the delegate :to_hash_access and :hash_access sub-options
9
+ #
10
+ class CheckHashAccessValue # :nodoc:
11
+ class << self
12
+ # Checks that the `key` value is a Boolean, a Symbol mode or a Hash
13
+ # with :mode and :allow_missing_key
14
+ def call(opts, key)
15
+ return unless opts.key?(key)
16
+
17
+ value = opts[key]
18
+ case value
19
+ when true, false then nil
20
+ when Symbol then check_mode(value)
21
+ when Hash
22
+ CheckAllowedKeys.call(value, %i[mode allow_missing_key], key)
23
+ check_mode(value[:mode]) if value.key?(:mode)
24
+ CheckOptIsBool.call(value, :allow_missing_key)
25
+ else
26
+ raise SeregaError,
27
+ "Invalid option #{key.inspect} => #{value.inspect}." \
28
+ " It must be a Boolean, a Symbol mode (:symbol, :string)" \
29
+ " or a Hash with :mode and :allow_missing_key keys"
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def check_mode(mode)
36
+ return if AttributeValueResolvers::HashAccessResolver::MODES.include?(mode)
37
+
38
+ raise SeregaError, "Invalid :hash_access mode #{mode.inspect}. Allowed modes: :symbol, :string"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,23 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Serega
4
- # @private
5
- module SeregaValidations
6
- # @private
7
- module Utils
4
+ module SeregaValidations # :nodoc:
5
+ module Utils # :nodoc:
8
6
  #
9
7
  # Utility to check hash key value is boolean
10
8
  #
11
- # @private
12
- class CheckOptIsBool
9
+ class CheckOptIsBool # :nodoc:
13
10
  # Checks hash key has boolean value
14
- #
15
- # @param opts [Hash] Some options Hash
16
- # @param key [Object] Hash key
17
- #
18
- # @raise [Serega::SeregaError] error when provided key exists and value is not boolean
19
- #
20
- # @return [void]
21
11
  def self.call(opts, key)
22
12
  return unless opts.key?(key)
23
13