domainic-attributer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.md +32 -1
  4. data/README.md +42 -355
  5. data/docs/USAGE.md +723 -0
  6. data/lib/domainic/attributer/attribute/callback.rb +21 -9
  7. data/lib/domainic/attributer/attribute/coercer.rb +28 -13
  8. data/lib/domainic/attributer/attribute/mixin/belongs_to_attribute.rb +16 -13
  9. data/lib/domainic/attributer/attribute/signature.rb +43 -32
  10. data/lib/domainic/attributer/attribute/validator.rb +46 -16
  11. data/lib/domainic/attributer/attribute.rb +28 -18
  12. data/lib/domainic/attributer/attribute_set.rb +21 -19
  13. data/lib/domainic/attributer/class_methods.rb +136 -83
  14. data/lib/domainic/attributer/dsl/attribute_builder/option_parser.rb +64 -22
  15. data/lib/domainic/attributer/dsl/attribute_builder.rb +515 -26
  16. data/lib/domainic/attributer/dsl/initializer.rb +23 -18
  17. data/lib/domainic/attributer/dsl/method_injector.rb +16 -14
  18. data/lib/domainic/attributer/errors/aggregate_error.rb +36 -0
  19. data/lib/domainic/attributer/errors/callback_execution_error.rb +30 -0
  20. data/lib/domainic/attributer/errors/coercion_execution_error.rb +37 -0
  21. data/lib/domainic/attributer/errors/error.rb +19 -0
  22. data/lib/domainic/attributer/errors/validation_execution_error.rb +30 -0
  23. data/lib/domainic/attributer/instance_methods.rb +11 -8
  24. data/lib/domainic/attributer/undefined.rb +9 -7
  25. data/lib/domainic/attributer.rb +88 -27
  26. data/sig/domainic/attributer/attribute/callback.rbs +10 -7
  27. data/sig/domainic/attributer/attribute/coercer.rbs +14 -11
  28. data/sig/domainic/attributer/attribute/mixin/belongs_to_attribute.rbs +14 -12
  29. data/sig/domainic/attributer/attribute/signature.rbs +43 -32
  30. data/sig/domainic/attributer/attribute/validator.rbs +28 -13
  31. data/sig/domainic/attributer/attribute.rbs +27 -17
  32. data/sig/domainic/attributer/attribute_set.rbs +21 -19
  33. data/sig/domainic/attributer/class_methods.rbs +133 -80
  34. data/sig/domainic/attributer/dsl/attribute_builder/option_parser.rbs +62 -22
  35. data/sig/domainic/attributer/dsl/attribute_builder.rbs +515 -26
  36. data/sig/domainic/attributer/dsl/initializer.rbs +21 -19
  37. data/sig/domainic/attributer/dsl/method_injector.rbs +16 -14
  38. data/sig/domainic/attributer/errors/aggregate_error.rbs +28 -0
  39. data/sig/domainic/attributer/errors/callback_execution_error.rbs +23 -0
  40. data/sig/domainic/attributer/errors/coercion_execution_error.rbs +29 -0
  41. data/sig/domainic/attributer/errors/error.rbs +17 -0
  42. data/sig/domainic/attributer/errors/validation_execution_error.rbs +23 -0
  43. data/sig/domainic/attributer/instance_methods.rbs +11 -8
  44. data/sig/domainic/attributer/undefined.rbs +5 -3
  45. data/sig/domainic/attributer.rbs +88 -27
  46. metadata +19 -6
@@ -8,13 +8,15 @@ require 'domainic/attributer/undefined'
8
8
 
9
9
  module Domainic
10
10
  module Attributer
11
- # A class representing a managed attribute in the Domainic::Attributer system.
11
+ # A class representing a managed attribute in the {Domainic::Attributer} system
12
12
  #
13
13
  # This class serves as the core component of the attribute management system.
14
14
  # It coordinates type information, visibility settings, value coercion,
15
15
  # validation, and change notifications for an attribute. Each instance
16
- # represents a single attribute definition within a class.
16
+ # represents a single attribute definition within a class
17
17
  #
18
+ # @api private
19
+ # @!visibility private
18
20
  # @author {https://aaronmallen.me Aaron Allen}
19
21
  # @since 0.1.0
20
22
  class Attribute
@@ -43,22 +45,30 @@ module Domainic
43
45
  # @rbs @signature: Signature
44
46
  # @rbs @validator: Validator
45
47
 
48
+ # Get the class or module this attribute belongs to
49
+ #
46
50
  # @return [Class, Module] the class or module this attribute belongs to
47
51
  attr_reader :base #: __todo__
48
52
 
53
+ # Get the description of the attribute
54
+ #
49
55
  # @return [String, nil] the description of the attribute
50
56
  attr_reader :description #: String?
51
57
 
58
+ # Get the name of the attribute
59
+ #
52
60
  # @return [Symbol] the name of the attribute
53
61
  attr_reader :name #: Symbol
54
62
 
63
+ # Get the signature configuration for this attribute
64
+ #
55
65
  # @return [Signature] the signature configuration for this attribute
56
66
  attr_reader :signature #: Signature
57
67
 
58
- # Initialize a new Attribute instance.
68
+ # Initialize a new {Attribute} instance
59
69
  #
60
70
  # @param base [Class, Module] the class or module this attribute belongs to
61
- # @param options [Hash] the options to create the attribute with
71
+ # @param options [Hash{Symbol => Object}] the options to create the attribute with
62
72
  # @option options [Array<Proc>, Proc] :callbacks callbacks to trigger on value changes
63
73
  # @option options [Array<Proc, Symbol>, Proc, Symbol] :coercers handlers for value coercion
64
74
  # @option options [Object] :default the default value or generator
@@ -73,8 +83,7 @@ module Domainic
73
83
  # @option options [Symbol] :write the write visibility
74
84
  #
75
85
  # @raise [ArgumentError] if the configuration is invalid
76
- # @return [void]
77
- #
86
+ # @return [Attribute] the new Attribute instance
78
87
  # @rbs (
79
88
  # __todo__ base,
80
89
  # ?callbacks: Array[Callback::handler] | Callback::handler,
@@ -98,7 +107,7 @@ module Domainic
98
107
  raise ArgumentError, e.message
99
108
  end
100
109
 
101
- # Apply a value to the attribute on an instance.
110
+ # Apply a value to the attribute on an instance
102
111
  #
103
112
  # This method applies all attribute constraints (coercion, validation) to a value
104
113
  # and sets it on the given instance. It manages the complete lifecycle of setting
@@ -119,7 +128,7 @@ module Domainic
119
128
  old_value = instance.instance_variable_get(:"@#{name}")
120
129
 
121
130
  coerced_value = value == Undefined ? generate_default(instance) : value
122
- coerced_value = @coercer.call(instance, coerced_value) unless coerced_value == Undefined
131
+ coerced_value = @coercer.call(instance, coerced_value)
123
132
 
124
133
  @validator.call(instance, coerced_value)
125
134
 
@@ -128,7 +137,7 @@ module Domainic
128
137
  @callback.call(instance, old_value, coerced_value)
129
138
  end
130
139
 
131
- # Check if this attribute has a default value.
140
+ # Check if this attribute has a default value
132
141
  #
133
142
  # @return [Boolean] true if a default value is set
134
143
  # @rbs () -> bool
@@ -136,10 +145,11 @@ module Domainic
136
145
  @default != Undefined
137
146
  end
138
147
 
139
- # Create a duplicate instance for a new base class.
148
+ # Create a duplicate instance for a new base class
140
149
  #
141
150
  # @param new_base [Class, Module] the new base class
142
151
  #
152
+ # @raise [ArgumentError] if the new base is invalid
143
153
  # @return [Attribute] the duplicated instance
144
154
  # @rbs (__todo__ new_base) -> Attribute
145
155
  def dup_with_base(new_base)
@@ -148,7 +158,7 @@ module Domainic
148
158
  dup.tap { |duped| duped.instance_variable_set(:@base, new_base) }
149
159
  end
150
160
 
151
- # Generate the default value for this attribute.
161
+ # Generate the default value for this attribute
152
162
  #
153
163
  # @param instance [Object] the instance to generate the default for
154
164
  #
@@ -158,11 +168,11 @@ module Domainic
158
168
  @default.is_a?(Proc) ? instance.instance_exec(&@default) : @default
159
169
  end
160
170
 
161
- # Merge this attribute's configuration with another.
171
+ # Merge this attribute's configuration with another
162
172
  #
163
173
  # @param other [Attribute] the attribute to merge with
164
174
  #
165
- # @raise [ArgumentError] if other is not an Attribute
175
+ # @raise [ArgumentError] if other is not an {Attribute}
166
176
  # @return [Attribute] a new attribute with merged configuration
167
177
  # @rbs (Attribute other) -> Attribute
168
178
  def merge(other)
@@ -173,7 +183,7 @@ module Domainic
173
183
 
174
184
  private
175
185
 
176
- # Apply initialization options to create attribute components.
186
+ # Apply initialization options to create attribute components
177
187
  #
178
188
  # @param base [Class, Module] the base class
179
189
  # @param options [Hash] the initialization options
@@ -193,7 +203,7 @@ module Domainic
193
203
  @validator = Validator.new(self, options.fetch(:validators, []))
194
204
  end
195
205
 
196
- # Initialize a copy of this attribute.
206
+ # Initialize a copy of this attribute
197
207
  #
198
208
  # @param source [Attribute] the source attribute
199
209
  #
@@ -211,7 +221,7 @@ module Domainic
211
221
  super
212
222
  end
213
223
 
214
- # Get this attribute's configuration as options.
224
+ # Get this attribute's configuration as options
215
225
  #
216
226
  # @return [Hash] the configuration options
217
227
  # @rbs () -> initialize_options
@@ -226,7 +236,7 @@ module Domainic
226
236
  }.merge(signature.send(:to_options)) #: initialize_options
227
237
  end
228
238
 
229
- # Validate and apply initialization options.
239
+ # Validate and apply initialization options
230
240
  #
231
241
  # @param base [Class, Module] the base class
232
242
  # @param options [Hash] the initialization options
@@ -238,7 +248,7 @@ module Domainic
238
248
  apply_initialize_options!(base, options)
239
249
  end
240
250
 
241
- # Validate initialization options.
251
+ # Validate initialization options
242
252
  #
243
253
  # @param base [Class, Module] the base class
244
254
  # @param options [Hash] the initialization options
@@ -5,14 +5,16 @@ require 'forwardable'
5
5
 
6
6
  module Domainic
7
7
  module Attributer
8
- # A class representing an ordered collection of attributes.
8
+ # A class responsible for managing an ordered collection of attributes
9
9
  #
10
10
  # This class manages a set of attributes for a given class or module. It maintains
11
11
  # attributes in a specific order determined by their type (argument vs option),
12
12
  # default values, and position. The collection supports standard operations like
13
13
  # adding, selecting, and merging attributes while maintaining proper ownership
14
- # relationships with their base class.
14
+ # relationships with their base class
15
15
  #
16
+ # @api private
17
+ # @!visibility private
16
18
  # @author {https://aaronmallen.me Aaron Allen}
17
19
  # @since 0.1.0
18
20
  class AttributeSet
@@ -21,12 +23,12 @@ module Domainic
21
23
  # @rbs @base: __todo__
22
24
  # @rbs @lookup: Hash[Symbol, Attribute]
23
25
 
24
- # Initialize a new AttributeSet.
26
+ # Initialize a new AttributeSet
25
27
  #
26
28
  # @param base [Class, Module] the class or module this set belongs to
27
29
  # @param attributes [Array<Attribute>] initial attributes to add
28
30
  #
29
- # @return [void]
31
+ # @return [AttributeSet] the new AttributeSet instance
30
32
  # @rbs (__todo__ base, ?Array[Attribute] attributes) -> void
31
33
  def initialize(base, attributes = [])
32
34
  @base = base
@@ -34,7 +36,7 @@ module Domainic
34
36
  attributes.each { |attribute| add(attribute) }
35
37
  end
36
38
 
37
- # Get an attribute by name.
39
+ # Get an attribute by name
38
40
  #
39
41
  # @param attribute_name [String, Symbol] the name of the attribute
40
42
  #
@@ -44,16 +46,16 @@ module Domainic
44
46
  @lookup[attribute_name.to_sym]
45
47
  end
46
48
 
47
- # Add an attribute to the set.
49
+ # Add an attribute to the set
48
50
  #
49
51
  # If an attribute with the same name exists, the attributes are merged.
50
52
  # If the attribute belongs to a different base class, it is duplicated
51
53
  # with the correct base. After adding, attributes are sorted by type
52
- # and position.
54
+ # and position
53
55
  #
54
56
  # @param attribute [Attribute] the attribute to add
55
57
  #
56
- # @raise [ArgumentError] if attribute is invalid
58
+ # @raise [ArgumentError] if attribute is not a valid {Attribute}
57
59
  # @return [void]
58
60
  # @rbs (Attribute attribute) -> void
59
61
  def add(attribute)
@@ -71,7 +73,7 @@ module Domainic
71
73
  nil
72
74
  end
73
75
 
74
- # Check if an attribute exists in the set.
76
+ # Check if an attribute exists in the set
75
77
  #
76
78
  # @param attribute_name [String, Symbol] the name to check
77
79
  #
@@ -80,7 +82,7 @@ module Domainic
80
82
  @lookup.key?(attribute_name.to_sym)
81
83
  end
82
84
 
83
- # Get all attribute names.
85
+ # Get all attribute names
84
86
  #
85
87
  # @return [Array<Symbol>] the attribute names
86
88
  # @rbs () -> Array[Symbol]
@@ -88,7 +90,7 @@ module Domainic
88
90
  @lookup.keys
89
91
  end
90
92
 
91
- # Get all attributes.
93
+ # Get all attributes
92
94
  #
93
95
  # @return [Array<Attribute>] the attributes
94
96
  # @rbs () -> Array[Attribute]
@@ -99,7 +101,7 @@ module Domainic
99
101
  # @rbs! def count: () ?{ (Symbol, Attribute) -> boolish } -> Integer
100
102
  def_delegators :@lookup, :count
101
103
 
102
- # Create a duplicate set for a new base class.
104
+ # Create a duplicate set for a new base class
103
105
  #
104
106
  # @param new_base [Class, Module] the new base class
105
107
  #
@@ -115,7 +117,7 @@ module Domainic
115
117
  end
116
118
  end
117
119
 
118
- # Iterate over attribute name/value pairs.
120
+ # Iterate over attribute name/value pairs
119
121
  #
120
122
  # @yield [name, attribute] each name/attribute pair
121
123
  # @yieldparam name [Symbol] the attribute name
@@ -132,7 +134,7 @@ module Domainic
132
134
  # @rbs! def empty?: () -> bool
133
135
  def_delegators :@lookup, :empty?
134
136
 
135
- # Create a new set excluding specified attributes.
137
+ # Create a new set excluding specified attributes
136
138
  #
137
139
  # @param attribute_names [Array<String, Symbol>] names to exclude
138
140
  #
@@ -145,7 +147,7 @@ module Domainic
145
147
  # @rbs! def length: () -> Integer
146
148
  def_delegators :@lookup, :length
147
149
 
148
- # Merge another set into this one.
150
+ # Merge another set into this one
149
151
  #
150
152
  # @param other [AttributeSet] the set to merge
151
153
  #
@@ -155,7 +157,7 @@ module Domainic
155
157
  self.class.new(other.instance_variable_get(:@base), attributes + other.attributes)
156
158
  end
157
159
 
158
- # Create a new set with rejected attributes.
160
+ # Create a new set with rejected attributes
159
161
  #
160
162
  # @yield [name, attribute] each name/attribute pair
161
163
  # @yieldparam name [Symbol] the attribute name
@@ -167,7 +169,7 @@ module Domainic
167
169
  self.class.new(@base, @lookup.reject(...).values)
168
170
  end
169
171
 
170
- # Create a new set with selected attributes.
172
+ # Create a new set with selected attributes
171
173
  #
172
174
  # @yield [name, attribute] each name/attribute pair
173
175
  # @yieldparam name [Symbol] the attribute name
@@ -184,10 +186,10 @@ module Domainic
184
186
 
185
187
  private
186
188
 
187
- # Sort attributes by type and position.
189
+ # Sort attributes by type and position
188
190
  #
189
191
  # Attributes are sorted first by type (required arguments, defaulted arguments,
190
- # then options), and then by their position within those groups.
192
+ # then options), and then by their position within those groups
191
193
  #
192
194
  # @return [void]
193
195
  # @rbs () -> void
@@ -7,81 +7,110 @@ require 'domainic/attributer/undefined'
7
7
 
8
8
  module Domainic
9
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:
10
+ # This module extends classes that include {Domainic::Attributer} with methods for defining and managing attributes.
11
+ # It supports two types of attributes:
14
12
  # 1. Arguments - Positional parameters that must be provided in a specific order
15
13
  # 2. Options - Named parameters that can be provided in any order
16
14
  #
15
+ # @note This module is automatically extended when {Domainic::Attributer} is included in a class
16
+ #
17
17
  # @example Defining arguments and options
18
18
  # class Person
19
19
  # include Domainic::Attributer
20
20
  #
21
- # argument :name, ->(value) { value.is_a?(String) }
22
- # argument :age do |value|
23
- # value.is_a?(Integer) && value >= 0
21
+ # argument :name, String
22
+ # argument :age, Integer do
23
+ # validate_with ->(val) { val >= 0 }
24
24
  # end
25
25
  #
26
- # option :email, ->(value) { value.is_a?(String) }, default: nil
27
- # option :role do |value|
28
- # %w[admin user guest].include?(value)
26
+ # option :email, String, default: nil
27
+ # option :role do
28
+ # validate_with ->(val) { %w[admin user guest].include?(val) }
29
29
  # end
30
30
  # end
31
31
  #
32
+ # person = Person.new('Alice', 30, email: 'alice123@gmail.com', role: 'user')
33
+ # # => #<Person:0x0000000104bc5f98 @age=30, @email="alice123@gmail.com", @name="Alice", @role="user">
34
+ #
32
35
  # @author {https://aaronmallen.me Aaron Allen}
33
36
  # @since 0.1.0
34
37
  module ClassMethods
35
38
  # @rbs @__attributes__: AttributeSet
36
39
 
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]
40
+ # Define a positional argument attribute
41
+ #
42
+ # Arguments are required by default and must be provided in the order they are defined unless they have a default
43
+ # value. They can be type-validated and configured with additional options like defaults and visibility
44
+ #
45
+ # @see DSL::AttributeBuilder
46
+ #
47
+ # @example Using the options API
48
+ # class Person
49
+ # argument :name, String
50
+ # argument :age, ->(val) { val.is_a?(Integer) && val >= 0 }
51
+ # argument :role, default: 'user'
52
+ # end
53
+ #
54
+ # @example Using the block API
55
+ # class Person
56
+ # argument :name, String do
57
+ # validate_with ->(val) { val.length >= 3 }
58
+ # end
59
+ #
60
+ # argument :age, Integer do
61
+ # coerce_with ->(val) { val.to_i }
62
+ # validate_with ->(val) { val >= 0 }
63
+ # end
64
+ #
65
+ # argument :role, String do
66
+ # validate_with ->(val) { VALID_USER_ROLES.include?(val) }
67
+ # default 'user'
68
+ # end
69
+ # end
70
+ #
71
+ # @overload argument(attribute_name, type_validator = nil, **options)
72
+ # @param attribute_name [String, Symbol] the name of the attribute
73
+ # @param type_validator [Proc, Object, nil] optional validation handler for type checking
74
+ # @param options [Hash{Symbol => Object}] additional configuration options
75
+ # @option options [Array<Proc>, Proc] :callbacks handlers for attribute change events (priority over
76
+ # :callback, :on_change)
77
+ # @option options [Array<Proc>, Proc] :callback alias for :callbacks
78
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coerce handlers for value coercion (priority over
79
+ # :coercers, :coerce_with)
80
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coercers alias for :coerce
81
+ # @option options [Array<Proc, Symbol>, Proc, Symbol] :coerce_with alias for :coerce
82
+ # @option options [Object] :default the default value (priority over :default_generator, :default_value)
83
+ # @option options [Object] :default_generator alias for :default
84
+ # @option options [Object] :default_value alias for :default
85
+ # @option options [String] :desc short description (overridden by :description)
86
+ # @option options [String] :description description text
87
+ # @option options [Boolean] :non_nil require non-nil values (priority over :non_null, :non_nullable, :not_nil,
88
+ # :not_nilable, :not_null, :not_nullable)
89
+ # @option options [Boolean] :non_null alias for :non_nil
90
+ # @option options [Boolean] :non_nullable alias for :non_nil
91
+ # @option options [Boolean] :not_nil alias for :non_nil
92
+ # @option options [Boolean] :not_nilable alias for :non_nil
93
+ # @option options [Boolean] :not_null alias for :non_nil
94
+ # @option options [Boolean] :not_nullable alias for :non_nil
95
+ # @option options [Boolean] :null inverse of :non_nil
96
+ # @option options [Array<Proc>, Proc] :on_change alias for :callbacks
97
+ # @option options [Boolean] :optional whether attribute is optional (overridden by :required)
98
+ # @option options [Integer] :position specify order position
99
+ # @option options [Symbol] :read read visibility (:public, :protected, :private) (priority over :read_access,
100
+ # :reader)
101
+ # @option options [Symbol] :read_access alias for :read
102
+ # @option options [Symbol] :reader alias for :read
103
+ # @option options [Boolean] :required whether attribute is required
104
+ # @option options [Array<Object>, Object] :validate validators for the attribute (priority over
105
+ # :validate_with, :validators)
106
+ # @option options [Array<Object>, Object] :validate_with alias for :validate
107
+ # @option options [Array<Object>, Object] :validators alias for :validate
108
+ # @option options [Symbol] :write_access write visibility (:public, :protected, :private) (priority over
109
+ # :writer)
110
+ # @option options [Symbol] :writer alias for :write_access
111
+ #
112
+ # @yield [DSL::AttributeBuilder] configuration block for additional attribute settings
113
+ # @return [void]
85
114
  # @rbs (
86
115
  # String | Symbol attribute_name,
87
116
  # ?Attribute::Validator::handler type_validator,
@@ -127,18 +156,45 @@ module Domainic
127
156
  DSL::MethodInjector.inject!(self, attribute)
128
157
  end
129
158
 
130
- # Define a named option attribute.
159
+ # Define a named option attribute
131
160
  #
132
161
  # 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.
162
+ # type-validated and configured with additional options like defaults and visibility
163
+ #
164
+ # @see DSL::AttributeBuilder
165
+ # @see DSL::AttributeBuilder::OptionParser#initialize
166
+ #
167
+ # @example Using the options API
168
+ # class Person
169
+ # option :email, String
170
+ # option :age, ->(val) { val.is_a?(Integer) && val >= 0 }
171
+ # option :role, default: 'user'
172
+ # end
134
173
  #
135
- # @overload option(attribute_name, type_validator = Undefined, **options, &block)
174
+ # @example Using the block API
175
+ # class Person
176
+ # option :email, String do
177
+ # coerce_with ->(val) { val.downcase }
178
+ # validate_with ->(val) { URI::MailTo::EMAIL_REGEXP.match?(val) }
179
+ # end
180
+ #
181
+ # option :age, Integer do
182
+ # coerce_with ->(val) { val.to_i }
183
+ # validate_with ->(val) { val >= 0 }
184
+ # end
185
+ #
186
+ # option :role, String do
187
+ # validate_with ->(val) { VALID_USER_ROLES.include?(val) }
188
+ # default 'user'
189
+ # end
190
+ # end
191
+ #
192
+ # @overload option(attribute_name, type_validator = nil, **options)
136
193
  # @param attribute_name [String, Symbol] the name of the attribute
137
194
  # @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)
195
+ # @param options [Hash{Symbol => Object}] additional configuration options
196
+ # @option options [Array<Proc>, Proc] :callbacks handlers for attribute change events (priority over
197
+ # :callback, :on_change)
142
198
  # @option options [Array<Proc>, Proc] :callback alias for :callbacks
143
199
  # @option options [Array<Proc, Symbol>, Proc, Symbol] :coerce handlers for value coercion (priority over
144
200
  # :coercers, :coerce_with)
@@ -166,18 +222,15 @@ module Domainic
166
222
  # @option options [Symbol] :read_access alias for :read
167
223
  # @option options [Symbol] :reader alias for :read
168
224
  # @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)
225
+ # @option options [Array<Object>, Object] :validate validators for the attribute (priority over
226
+ # :validate_with, :validators)
171
227
  # @option options [Array<Object>, Object] :validate_with alias for :validate
172
228
  # @option options [Array<Object>, Object] :validators alias for :validate
173
- # @option options [Symbol] :write_access write visibility (:public, :protected, :private)
174
- # (priority over :writer)
229
+ # @option options [Symbol] :write_access write visibility (:public, :protected, :private) (priority over
230
+ # :writer)
175
231
  # @option options [Symbol] :writer alias for :write_access
176
232
  #
177
- # @yield [DSL::AttributeBuilder] optional configuration block
178
- # @return [void]
179
- #
180
- # @yield [DSL::AttributeBuilder] optional configuration block
233
+ # @yield [DSL::AttributeBuilder] configuration block for additional attribute settings
181
234
  # @return [void]
182
235
  # @rbs (
183
236
  # String | Symbol attribute_name,
@@ -222,10 +275,18 @@ module Domainic
222
275
 
223
276
  private
224
277
 
225
- # Handle class inheritance for attributes.
278
+ # Get the attribute set for this class
279
+ #
280
+ # @return [AttributeSet] the set of attributes defined for this class
281
+ # @rbs () -> AttributeSet
282
+ def __attributes__
283
+ @__attributes__ ||= AttributeSet.new(self)
284
+ end
285
+
286
+ # Handle class inheritance for attributes
226
287
  #
227
288
  # Ensures that subclasses inherit a copy of their parent's attributes while
228
- # maintaining proper ownership relationships.
289
+ # maintaining proper ownership relationships
229
290
  #
230
291
  # @param subclass [Class] the inheriting class
231
292
  # @return [void]
@@ -234,14 +295,6 @@ module Domainic
234
295
  super
235
296
  subclass.instance_variable_set(:@__attributes__, __attributes__.dup_with_base(subclass))
236
297
  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
298
  end
246
299
  end
247
300
  end