domainic-attributer 0.1.0 → 0.2.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 (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