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.
- checksums.yaml +4 -4
- data/.yardopts +11 -0
- data/CHANGELOG.md +32 -1
- data/README.md +42 -355
- data/docs/USAGE.md +723 -0
- data/lib/domainic/attributer/attribute/callback.rb +21 -9
- data/lib/domainic/attributer/attribute/coercer.rb +28 -13
- data/lib/domainic/attributer/attribute/mixin/belongs_to_attribute.rb +16 -13
- data/lib/domainic/attributer/attribute/signature.rb +43 -32
- data/lib/domainic/attributer/attribute/validator.rb +46 -16
- data/lib/domainic/attributer/attribute.rb +28 -18
- data/lib/domainic/attributer/attribute_set.rb +21 -19
- data/lib/domainic/attributer/class_methods.rb +136 -83
- data/lib/domainic/attributer/dsl/attribute_builder/option_parser.rb +64 -22
- data/lib/domainic/attributer/dsl/attribute_builder.rb +515 -26
- data/lib/domainic/attributer/dsl/initializer.rb +23 -18
- data/lib/domainic/attributer/dsl/method_injector.rb +16 -14
- data/lib/domainic/attributer/errors/aggregate_error.rb +36 -0
- data/lib/domainic/attributer/errors/callback_execution_error.rb +30 -0
- data/lib/domainic/attributer/errors/coercion_execution_error.rb +37 -0
- data/lib/domainic/attributer/errors/error.rb +19 -0
- data/lib/domainic/attributer/errors/validation_execution_error.rb +30 -0
- data/lib/domainic/attributer/instance_methods.rb +11 -8
- data/lib/domainic/attributer/undefined.rb +9 -7
- data/lib/domainic/attributer.rb +88 -27
- data/sig/domainic/attributer/attribute/callback.rbs +10 -7
- data/sig/domainic/attributer/attribute/coercer.rbs +14 -11
- data/sig/domainic/attributer/attribute/mixin/belongs_to_attribute.rbs +14 -12
- data/sig/domainic/attributer/attribute/signature.rbs +43 -32
- data/sig/domainic/attributer/attribute/validator.rbs +28 -13
- data/sig/domainic/attributer/attribute.rbs +27 -17
- data/sig/domainic/attributer/attribute_set.rbs +21 -19
- data/sig/domainic/attributer/class_methods.rbs +133 -80
- data/sig/domainic/attributer/dsl/attribute_builder/option_parser.rbs +62 -22
- data/sig/domainic/attributer/dsl/attribute_builder.rbs +515 -26
- data/sig/domainic/attributer/dsl/initializer.rbs +21 -19
- data/sig/domainic/attributer/dsl/method_injector.rbs +16 -14
- data/sig/domainic/attributer/errors/aggregate_error.rbs +28 -0
- data/sig/domainic/attributer/errors/callback_execution_error.rbs +23 -0
- data/sig/domainic/attributer/errors/coercion_execution_error.rbs +29 -0
- data/sig/domainic/attributer/errors/error.rbs +17 -0
- data/sig/domainic/attributer/errors/validation_execution_error.rbs +23 -0
- data/sig/domainic/attributer/instance_methods.rbs +11 -8
- data/sig/domainic/attributer/undefined.rbs +5 -3
- data/sig/domainic/attributer.rbs +88 -27
- 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 [
|
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)
|
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
|
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 [
|
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
|
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
|
-
#
|
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,
|
22
|
-
# argument :age do
|
23
|
-
#
|
21
|
+
# argument :name, String
|
22
|
+
# argument :age, Integer do
|
23
|
+
# validate_with ->(val) { val >= 0 }
|
24
24
|
# end
|
25
25
|
#
|
26
|
-
# option :email,
|
27
|
-
# option :role do
|
28
|
-
# %w[admin user guest].include?(
|
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
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
# @
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
# @
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
# :
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
# :
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
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
|
-
# @
|
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
|
-
#
|
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
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|