domainic-attributer 0.1.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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +14 -0
  3. data/LICENSE +21 -0
  4. data/README.md +396 -0
  5. data/lib/domainic/attributer/attribute/callback.rb +68 -0
  6. data/lib/domainic/attributer/attribute/coercer.rb +93 -0
  7. data/lib/domainic/attributer/attribute/mixin/belongs_to_attribute.rb +68 -0
  8. data/lib/domainic/attributer/attribute/signature.rb +338 -0
  9. data/lib/domainic/attributer/attribute/validator.rb +128 -0
  10. data/lib/domainic/attributer/attribute.rb +256 -0
  11. data/lib/domainic/attributer/attribute_set.rb +208 -0
  12. data/lib/domainic/attributer/class_methods.rb +247 -0
  13. data/lib/domainic/attributer/dsl/attribute_builder/option_parser.rb +247 -0
  14. data/lib/domainic/attributer/dsl/attribute_builder.rb +233 -0
  15. data/lib/domainic/attributer/dsl/initializer.rb +130 -0
  16. data/lib/domainic/attributer/dsl/method_injector.rb +97 -0
  17. data/lib/domainic/attributer/dsl.rb +5 -0
  18. data/lib/domainic/attributer/instance_methods.rb +65 -0
  19. data/lib/domainic/attributer/undefined.rb +44 -0
  20. data/lib/domainic/attributer.rb +114 -0
  21. data/lib/domainic-attributer.rb +3 -0
  22. data/sig/domainic/attributer/attribute/callback.rbs +48 -0
  23. data/sig/domainic/attributer/attribute/coercer.rbs +59 -0
  24. data/sig/domainic/attributer/attribute/mixin/belongs_to_attribute.rbs +46 -0
  25. data/sig/domainic/attributer/attribute/signature.rbs +223 -0
  26. data/sig/domainic/attributer/attribute/validator.rbs +83 -0
  27. data/sig/domainic/attributer/attribute.rbs +150 -0
  28. data/sig/domainic/attributer/attribute_set.rbs +134 -0
  29. data/sig/domainic/attributer/class_methods.rbs +151 -0
  30. data/sig/domainic/attributer/dsl/attribute_builder/option_parser.rbs +130 -0
  31. data/sig/domainic/attributer/dsl/attribute_builder.rbs +156 -0
  32. data/sig/domainic/attributer/dsl/initializer.rbs +91 -0
  33. data/sig/domainic/attributer/dsl/method_injector.rbs +66 -0
  34. data/sig/domainic/attributer/dsl.rbs +1 -0
  35. data/sig/domainic/attributer/instance_methods.rbs +53 -0
  36. data/sig/domainic/attributer/undefined.rbs +14 -0
  37. data/sig/domainic/attributer.rbs +69 -0
  38. data/sig/domainic-attributer.rbs +1 -0
  39. data/sig/manifest.yaml +2 -0
  40. metadata +89 -0
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'domainic/attributer/attribute_set'
4
+ require 'domainic/attributer/dsl/attribute_builder'
5
+ require 'domainic/attributer/dsl/method_injector'
6
+ require 'domainic/attributer/undefined'
7
+
8
+ module Domainic
9
+ module Attributer
10
+ # A module providing class-level methods for attribute definition.
11
+ #
12
+ # This module extends classes that include Domainic::Attributer with methods for
13
+ # defining and managing attributes. It supports two types of attributes:
14
+ # 1. Arguments - Positional parameters that must be provided in a specific order
15
+ # 2. Options - Named parameters that can be provided in any order
16
+ #
17
+ # @example Defining arguments and options
18
+ # class Person
19
+ # include Domainic::Attributer
20
+ #
21
+ # argument :name, ->(value) { value.is_a?(String) }
22
+ # argument :age do |value|
23
+ # value.is_a?(Integer) && value >= 0
24
+ # end
25
+ #
26
+ # option :email, ->(value) { value.is_a?(String) }, default: nil
27
+ # option :role do |value|
28
+ # %w[admin user guest].include?(value)
29
+ # end
30
+ # end
31
+ #
32
+ # @author {https://aaronmallen.me Aaron Allen}
33
+ # @since 0.1.0
34
+ module ClassMethods
35
+ # @rbs @__attributes__: AttributeSet
36
+
37
+ # Define a positional argument attribute.
38
+ #
39
+ # Arguments are required by default and must be provided in the order they are defined.
40
+ # They can be type-validated and configured with additional options like defaults
41
+ # and visibility.
42
+ #
43
+ # @param attribute_name [String, Symbol] the name of the attribute
44
+ # @param type_validator [Proc, Object, nil] optional validation handler for type checking
45
+ # @param options [Hash] additional configuration options
46
+ #
47
+ # @option options [Array<Proc>, Proc] :callbacks handlers for attribute change events (priority over :callback,
48
+ # :on_change)
49
+ # @option options [Array<Proc>, Proc] :callback alias for :callbacks
50
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coerce handlers for value coercion (priority over
51
+ # :coercers, :coerce_with)
52
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coercers alias for :coerce
53
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coerce_with alias for :coerce
54
+ # @option options [Object] :default the default value (priority over :default_generator, :default_value)
55
+ # @option options [Object] :default_generator alias for :default
56
+ # @option options [Object] :default_value alias for :default
57
+ # @option options [String] :desc short description (overridden by :description)
58
+ # @option options [String] :description description text
59
+ # @option options [Boolean] :non_nil require non-nil values (priority over :non_null, :non_nullable, :not_nil,
60
+ # :not_nilable, :not_null, :not_nullable)
61
+ # @option options [Boolean] :non_null alias for :non_nil
62
+ # @option options [Boolean] :non_nullable alias for :non_nil
63
+ # @option options [Boolean] :not_nil alias for :non_nil
64
+ # @option options [Boolean] :not_nilable alias for :non_nil
65
+ # @option options [Boolean] :not_null alias for :non_nil
66
+ # @option options [Boolean] :not_nullable alias for :non_nil
67
+ # @option options [Boolean] :null inverse of :non_nil
68
+ # @option options [Array<Proc>, Proc] :on_change alias for :callbacks
69
+ # @option options [Boolean] :optional whether attribute is optional (overridden by :required)
70
+ # @option options [Integer] :position specify order position
71
+ # @option options [Symbol] :read read visibility (:public, :protected, :private) (priority over :read_access,
72
+ # :reader)
73
+ # @option options [Symbol] :read_access alias for :read
74
+ # @option options [Symbol] :reader alias for :read
75
+ # @option options [Boolean] :required whether attribute is required
76
+ # @option options [Array<Object>, Object] :validate validators for the attribute (priority over :validate_with,
77
+ # :validators)
78
+ # @option options [Array<Object>, Object] :validate_with alias for :validate
79
+ # @option options [Array<Object>, Object] :validators alias for :validate
80
+ # @option options [Symbol] :write_access write visibility (:public, :protected, :private) (priority over :writer)
81
+ # @option options [Symbol] :writer alias for :write_access
82
+ #
83
+ # @yield [DSL::AttributeBuilder] optional configuration block
84
+ # @return [void]
85
+ # @rbs (
86
+ # String | Symbol attribute_name,
87
+ # ?Attribute::Validator::handler type_validator,
88
+ # ?callbacks: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
89
+ # ?callback: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
90
+ # ?coerce: Array[Attribute::Coercer::handler] | Attribute::Coercer::handler,
91
+ # ?coercers: Array[Attribute::Coercer::handler],
92
+ # ?coerce_with: [Attribute::Coercer::handler] | Attribute::Coercer::handler,
93
+ # ?default: untyped,
94
+ # ?default_generator: untyped,
95
+ # ?default_value: untyped,
96
+ # ?desc: String?,
97
+ # ?description: String,
98
+ # ?non_nil: bool,
99
+ # ?non_null: bool,
100
+ # ?non_nullable: bool,
101
+ # ?not_nil: bool,
102
+ # ?not_nilable: bool,
103
+ # ?not_null: bool,
104
+ # ?not_nullable: bool,
105
+ # ?null: bool,
106
+ # ?on_change: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
107
+ # ?optional: bool,
108
+ # ?position: Integer?,
109
+ # ?read: Attribute::Signature::visibility_symbol,
110
+ # ?read_access: Attribute::Signature::visibility_symbol,
111
+ # ?reader: Attribute::Signature::visibility_symbol,
112
+ # ?required: bool,
113
+ # ?validate: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
114
+ # ?validate_with: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
115
+ # ?validators: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
116
+ # ?write_access: Attribute::Signature::visibility_symbol,
117
+ # ?writer: Attribute::Signature::visibility_symbol,
118
+ # ) ?{ (?) [self: DSL::AttributeBuilder] -> void } -> void
119
+ def argument(attribute_name, type_validator = Undefined, **options, &)
120
+ position = __attributes__.count { |_, attribute| attribute.signature.argument? }
121
+
122
+ attribute = DSL::AttributeBuilder.new(
123
+ self, attribute_name, :argument, type_validator, **options.merge(position:), &
124
+ ).build!
125
+
126
+ __attributes__.add(attribute)
127
+ DSL::MethodInjector.inject!(self, attribute)
128
+ end
129
+
130
+ # Define a named option attribute.
131
+ #
132
+ # Options are optional by default and can be provided in any order. They can be
133
+ # type-validated and configured with additional options like defaults and visibility.
134
+ #
135
+ # @overload option(attribute_name, type_validator = Undefined, **options, &block)
136
+ # @param attribute_name [String, Symbol] the name of the attribute
137
+ # @param type_validator [Proc, Object, nil] optional validation handler for type checking
138
+ # @param options [Hash] additional configuration options
139
+ #
140
+ # @option options [Array<Proc>, Proc] :callbacks handlers for attribute change events (priority over :callback,
141
+ # :on_change)
142
+ # @option options [Array<Proc>, Proc] :callback alias for :callbacks
143
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coerce handlers for value coercion (priority over
144
+ # :coercers, :coerce_with)
145
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coercers alias for :coerce
146
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coerce_with alias for :coerce
147
+ # @option options [Object] :default the default value (priority over :default_generator, :default_value)
148
+ # @option options [Object] :default_generator alias for :default
149
+ # @option options [Object] :default_value alias for :default
150
+ # @option options [String] :desc short description (overridden by :description)
151
+ # @option options [String] :description description text
152
+ # @option options [Boolean] :non_nil require non-nil values (priority over :non_null, :non_nullable, :not_nil,
153
+ # :not_nilable, :not_null, :not_nullable)
154
+ # @option options [Boolean] :non_null alias for :non_nil
155
+ # @option options [Boolean] :non_nullable alias for :non_nil
156
+ # @option options [Boolean] :not_nil alias for :non_nil
157
+ # @option options [Boolean] :not_nilable alias for :non_nil
158
+ # @option options [Boolean] :not_null alias for :non_nil
159
+ # @option options [Boolean] :not_nullable alias for :non_nil
160
+ # @option options [Boolean] :null inverse of :non_nil
161
+ # @option options [Array<Proc>, Proc] :on_change alias for :callbacks
162
+ # @option options [Boolean] :optional whether attribute is optional (overridden by :required)
163
+ # @option options [Integer] :position specify order position
164
+ # @option options [Symbol] :read read visibility (:public, :protected, :private) (priority over :read_access,
165
+ # :reader)
166
+ # @option options [Symbol] :read_access alias for :read
167
+ # @option options [Symbol] :reader alias for :read
168
+ # @option options [Boolean] :required whether attribute is required
169
+ # @option options [Array<Object>, Object] :validate validators for the attribute (priority over :validate_with,
170
+ # :validators)
171
+ # @option options [Array<Object>, Object] :validate_with alias for :validate
172
+ # @option options [Array<Object>, Object] :validators alias for :validate
173
+ # @option options [Symbol] :write_access write visibility (:public, :protected, :private)
174
+ # (priority over :writer)
175
+ # @option options [Symbol] :writer alias for :write_access
176
+ #
177
+ # @yield [DSL::AttributeBuilder] optional configuration block
178
+ # @return [void]
179
+ #
180
+ # @yield [DSL::AttributeBuilder] optional configuration block
181
+ # @return [void]
182
+ # @rbs (
183
+ # String | Symbol attribute_name,
184
+ # ?Attribute::Validator::handler type_validator,
185
+ # ?callbacks: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
186
+ # ?callback: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
187
+ # ?coerce: Array[Attribute::Coercer::handler] | Attribute::Coercer::handler,
188
+ # ?coercers: Array[Attribute::Coercer::handler],
189
+ # ?coerce_with: [Attribute::Coercer::handler] | Attribute::Coercer::handler,
190
+ # ?default: untyped,
191
+ # ?default_generator: untyped,
192
+ # ?default_value: untyped,
193
+ # ?desc: String?,
194
+ # ?description: String,
195
+ # ?non_nil: bool,
196
+ # ?non_null: bool,
197
+ # ?non_nullable: bool,
198
+ # ?not_nil: bool,
199
+ # ?not_nilable: bool,
200
+ # ?not_null: bool,
201
+ # ?not_nullable: bool,
202
+ # ?null: bool,
203
+ # ?on_change: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
204
+ # ?optional: bool,
205
+ # ?position: Integer?,
206
+ # ?read: Attribute::Signature::visibility_symbol,
207
+ # ?read_access: Attribute::Signature::visibility_symbol,
208
+ # ?reader: Attribute::Signature::visibility_symbol,
209
+ # ?required: bool,
210
+ # ?validate: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
211
+ # ?validate_with: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
212
+ # ?validators: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
213
+ # ?write_access: Attribute::Signature::visibility_symbol,
214
+ # ?writer: Attribute::Signature::visibility_symbol,
215
+ # ) ?{ (?) [self: DSL::AttributeBuilder] -> void } -> void
216
+ def option(attribute_name, ...)
217
+ attribute = DSL::AttributeBuilder.new(self, attribute_name, :option, ...).build! # steep:ignore
218
+
219
+ __attributes__.add(attribute)
220
+ DSL::MethodInjector.inject!(self, attribute)
221
+ end
222
+
223
+ private
224
+
225
+ # Handle class inheritance for attributes.
226
+ #
227
+ # Ensures that subclasses inherit a copy of their parent's attributes while
228
+ # maintaining proper ownership relationships.
229
+ #
230
+ # @param subclass [Class] the inheriting class
231
+ # @return [void]
232
+ # @rbs (Class | Module subclass) -> void
233
+ def inherited(subclass)
234
+ super
235
+ subclass.instance_variable_set(:@__attributes__, __attributes__.dup_with_base(subclass))
236
+ end
237
+
238
+ # Get the attribute set for this class.
239
+ #
240
+ # @return [AttributeSet] the set of attributes defined for this class
241
+ # @rbs () -> AttributeSet
242
+ def __attributes__
243
+ @__attributes__ ||= AttributeSet.new(self)
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Domainic
4
+ module Attributer
5
+ module DSL
6
+ class AttributeBuilder
7
+ # A class responsible for parsing and normalizing attribute options.
8
+ #
9
+ # This class handles the conversion of flexible DSL options into a normalized
10
+ # format for attribute creation. It supports multiple ways of specifying common
11
+ # options (like visibility, nullability, validation) and consolidates them
12
+ # into a consistent internal representation.
13
+ #
14
+ # @author {https://aaronmallen.me Aaron Allen}
15
+ # @since 0.1.0
16
+ class OptionParser
17
+ # @rbs!
18
+ # type options = {
19
+ # ?callbacks: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
20
+ # ?callback: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
21
+ # ?coerce: Array[Attribute::Coercer::handler] | Attribute::Coercer::handler,
22
+ # ?coercers: Array[Attribute::Coercer::handler],
23
+ # ?coerce_with: [Attribute::Coercer::handler] | Attribute::Coercer::handler,
24
+ # ?default: untyped,
25
+ # ?default_generator: untyped,
26
+ # ?default_value: untyped,
27
+ # ?desc: String?,
28
+ # ?description: String,
29
+ # ?non_nil: bool,
30
+ # ?non_null: bool,
31
+ # ?non_nullable: bool,
32
+ # ?not_nil: bool,
33
+ # ?not_nilable: bool,
34
+ # ?not_null: bool,
35
+ # ?not_nullable: bool,
36
+ # ?null: bool,
37
+ # ?on_change: Array[Attribute::Callback::handler] | Attribute::Callback::handler,
38
+ # ?optional: bool,
39
+ # ?position: Integer?,
40
+ # ?read: Attribute::Signature::visibility_symbol,
41
+ # ?read_access: Attribute::Signature::visibility_symbol,
42
+ # ?reader: Attribute::Signature::visibility_symbol,
43
+ # ?required: bool,
44
+ # ?validate: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
45
+ # ?validate_with: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
46
+ # ?validators: Array[Attribute::Validator::handler] | Attribute::Validator::handler,
47
+ # ?write_access: Attribute::Signature::visibility_symbol,
48
+ # ?writer: Attribute::Signature::visibility_symbol,
49
+ # } & Hash[Symbol, untyped]
50
+ #
51
+ # type result = {
52
+ # callbacks: Array[Attribute::Callback::handler],
53
+ # coercers: Array[Attribute::Coercer::handler],
54
+ # ?default: untyped,
55
+ # ?description: String,
56
+ # name: Symbol,
57
+ # ?nilable: bool,
58
+ # ?position: Integer?,
59
+ # ?required: bool,
60
+ # ?read: Attribute::Signature::visibility_symbol,
61
+ # type: Attribute::Signature::type_symbol,
62
+ # validators: Array[Attribute::Validator::handler],
63
+ # ?write: Attribute::Signature::visibility_symbol,
64
+ # }
65
+
66
+ # Alternative keys for reader visibility settings
67
+ ACCESSOR_READER_KEYS = %i[read read_access reader].freeze #: Array[Symbol]
68
+ private_constant :ACCESSOR_READER_KEYS
69
+
70
+ # Alternative keys for writer visibility settings
71
+ ACCESSOR_WRITER_KEYS = %i[write write_access writer].freeze #: Array[Symbol]
72
+ private_constant :ACCESSOR_WRITER_KEYS
73
+
74
+ # Alternative keys for change callbacks
75
+ CALLBACK_KEYS = %i[callback on_change callbacks].freeze #: Array[Symbol]
76
+ private_constant :CALLBACK_KEYS
77
+
78
+ # Alternative keys for coercion handlers
79
+ COERCER_KEYS = %i[coerce coercers coerce_with].freeze #: Array[Symbol]
80
+ private_constant :COERCER_KEYS
81
+
82
+ # Alternative keys for default value settings
83
+ DEFAULT_KEYS = %i[default_value default_generator default].freeze #: Array[Symbol]
84
+ private_constant :DEFAULT_KEYS
85
+
86
+ # Alternative keys for description
87
+ DESCRIPTION_KEYS = %i[desc description].freeze #: Array[Symbol]
88
+ private_constant :DESCRIPTION_KEYS
89
+
90
+ # Pattern for matching nilability-related keys
91
+ NILABLE_PATTERN = /\A(?:not_|non_)?(?:nil|null)\z/ #: Regexp
92
+ private_constant :NILABLE_PATTERN
93
+
94
+ # Keys that indicate non-nilable requirement
95
+ NON_NILABLE_KEYS = %i[
96
+ non_nil non_nilable not_nil not_nilable
97
+ non_null non_nullable not_null not_nullable
98
+ ].freeze #: Array[Symbol]
99
+ private_constant :NON_NILABLE_KEYS
100
+
101
+ # Alternative keys for validators
102
+ VALIDATOR_KEYS = %i[validate validate_with validators].freeze #: Array[Symbol]
103
+ private_constant :VALIDATOR_KEYS
104
+
105
+ # @rbs @options: options
106
+ # @rbs @result: result
107
+
108
+ # Parse attribute options into a normalized format.
109
+ #
110
+ # @param attribute_name [String, Symbol] the name of the attribute
111
+ # @param attribute_type [String, Symbol] the type of attribute
112
+ # @param options [Hash] the options to parse
113
+ #
114
+ # @return [Hash] normalized options suitable for attribute creation
115
+ # @rbs (String | Symbol attribute_name, String | Symbol attribute_type, options options) -> void
116
+ def self.parse!(attribute_name, attribute_type, options)
117
+ new(attribute_name, attribute_type, options).parse!
118
+ end
119
+
120
+ # Initialize a new OptionParser.
121
+ #
122
+ # @param attribute_name [String, Symbol] the name of the attribute
123
+ # @param attribute_type [String, Symbol] the type of attribute
124
+ # @param options [Hash] the options to parse
125
+ #
126
+ # @return [void]
127
+ # @rbs (String | Symbol attribute_name, String | Symbol attribute_type, options options) -> void
128
+ def initialize(attribute_name, attribute_type, options)
129
+ @options = options.transform_keys(&:to_sym)
130
+ @result = { callbacks: [], coercers: [], validators: [] }
131
+ @result[:name] = attribute_name.to_sym
132
+ @result[:type] = attribute_type.to_sym
133
+ @result[:position] = @options[:position] if @options.key?(:position)
134
+ end
135
+
136
+ # Parse the options into a normalized format.
137
+ #
138
+ # @return [Hash] normalized options suitable for attribute creation
139
+ # @rbs () -> result
140
+ def parse!
141
+ parse_options!
142
+ @result
143
+ end
144
+
145
+ private
146
+
147
+ # Find the last set value among multiple option keys.
148
+ #
149
+ # @param keys [Array<Symbol>] the keys to check
150
+ #
151
+ # @return [Object] the last set value or Undefined
152
+ # @rbs (Array[Symbol]) -> untyped
153
+ def find_last_option(keys)
154
+ keys.reverse_each do |key|
155
+ value = @options[key]
156
+ return value if value
157
+ end
158
+ Undefined
159
+ end
160
+
161
+ # Parse accessor (reader/writer) visibility options.
162
+ #
163
+ # @return [void]
164
+ # @rbs () -> void
165
+ def parse_accessor_options!
166
+ @result[:read] = find_last_option(ACCESSOR_READER_KEYS)
167
+ @result[:write] = find_last_option(ACCESSOR_WRITER_KEYS)
168
+ end
169
+
170
+ # Parse callback handler options.
171
+ #
172
+ # @return [void]
173
+ # @rbs () -> void
174
+ def parse_callbacks_options!
175
+ CALLBACK_KEYS.each do |key|
176
+ @result[:callbacks].concat(Array(@options[key])) if @options[key]
177
+ end
178
+ end
179
+
180
+ # Parse coercion handler options.
181
+ #
182
+ # @return [void]
183
+ # @rbs () -> void
184
+ def parse_coercers_options!
185
+ COERCER_KEYS.each do |key|
186
+ @result[:coercers].concat(Array(@options[key])) if @options[key]
187
+ end
188
+ end
189
+
190
+ # Parse default value options.
191
+ #
192
+ # @return [void]
193
+ # @rbs () -> void
194
+ def parse_default_options!
195
+ @result[:default] = find_last_option(DEFAULT_KEYS)
196
+ end
197
+
198
+ # Parse description options.
199
+ #
200
+ # @return [void]
201
+ # @rbs () -> void
202
+ def parse_description_options!
203
+ @result[:description] = find_last_option(DESCRIPTION_KEYS)
204
+ end
205
+
206
+ # Parse nilability options.
207
+ #
208
+ # @return [void]
209
+ # @rbs () -> void
210
+ def parse_nilable_options!
211
+ return unless @options.keys.any? { |key| key.match?(NILABLE_PATTERN) }
212
+
213
+ @result[:nilable] = !(NON_NILABLE_KEYS.any? { |k| @options[k] == true } || @options[:null] == false)
214
+ end
215
+
216
+ # Parse all option types.
217
+ #
218
+ # @return [void]
219
+ # @rbs () -> void
220
+ def parse_options!
221
+ private_methods.grep(/\Aparse_.*_options!\z/).each { |method| send(method) }
222
+ end
223
+
224
+ # Parse required/optional options.
225
+ #
226
+ # @return [void]
227
+ # @rbs () -> void
228
+ def parse_required_options!
229
+ return unless @options.key?(:optional) || @options.key?(:required)
230
+
231
+ @result[:required] = @options[:optional] == false || @options[:required] == true
232
+ end
233
+
234
+ # Parse validator options.
235
+ #
236
+ # @return [void]
237
+ # @rbs () -> void
238
+ def parse_validator_options!
239
+ VALIDATOR_KEYS.each do |key|
240
+ @result[:validators].concat(Array(@options.fetch(key, [])))
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
246
+ end
247
+ end