domainic-attributer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +14 -0
- data/LICENSE +21 -0
- data/README.md +396 -0
- data/lib/domainic/attributer/attribute/callback.rb +68 -0
- data/lib/domainic/attributer/attribute/coercer.rb +93 -0
- data/lib/domainic/attributer/attribute/mixin/belongs_to_attribute.rb +68 -0
- data/lib/domainic/attributer/attribute/signature.rb +338 -0
- data/lib/domainic/attributer/attribute/validator.rb +128 -0
- data/lib/domainic/attributer/attribute.rb +256 -0
- data/lib/domainic/attributer/attribute_set.rb +208 -0
- data/lib/domainic/attributer/class_methods.rb +247 -0
- data/lib/domainic/attributer/dsl/attribute_builder/option_parser.rb +247 -0
- data/lib/domainic/attributer/dsl/attribute_builder.rb +233 -0
- data/lib/domainic/attributer/dsl/initializer.rb +130 -0
- data/lib/domainic/attributer/dsl/method_injector.rb +97 -0
- data/lib/domainic/attributer/dsl.rb +5 -0
- data/lib/domainic/attributer/instance_methods.rb +65 -0
- data/lib/domainic/attributer/undefined.rb +44 -0
- data/lib/domainic/attributer.rb +114 -0
- data/lib/domainic-attributer.rb +3 -0
- data/sig/domainic/attributer/attribute/callback.rbs +48 -0
- data/sig/domainic/attributer/attribute/coercer.rbs +59 -0
- data/sig/domainic/attributer/attribute/mixin/belongs_to_attribute.rbs +46 -0
- data/sig/domainic/attributer/attribute/signature.rbs +223 -0
- data/sig/domainic/attributer/attribute/validator.rbs +83 -0
- data/sig/domainic/attributer/attribute.rbs +150 -0
- data/sig/domainic/attributer/attribute_set.rbs +134 -0
- data/sig/domainic/attributer/class_methods.rbs +151 -0
- data/sig/domainic/attributer/dsl/attribute_builder/option_parser.rbs +130 -0
- data/sig/domainic/attributer/dsl/attribute_builder.rbs +156 -0
- data/sig/domainic/attributer/dsl/initializer.rbs +91 -0
- data/sig/domainic/attributer/dsl/method_injector.rbs +66 -0
- data/sig/domainic/attributer/dsl.rbs +1 -0
- data/sig/domainic/attributer/instance_methods.rbs +53 -0
- data/sig/domainic/attributer/undefined.rbs +14 -0
- data/sig/domainic/attributer.rbs +69 -0
- data/sig/domainic-attributer.rbs +1 -0
- data/sig/manifest.yaml +2 -0
- metadata +89 -0
@@ -0,0 +1,256 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'domainic/attributer/attribute/callback'
|
4
|
+
require 'domainic/attributer/attribute/coercer'
|
5
|
+
require 'domainic/attributer/attribute/signature'
|
6
|
+
require 'domainic/attributer/attribute/validator'
|
7
|
+
require 'domainic/attributer/undefined'
|
8
|
+
|
9
|
+
module Domainic
|
10
|
+
module Attributer
|
11
|
+
# A class representing a managed attribute in the Domainic::Attributer system.
|
12
|
+
#
|
13
|
+
# This class serves as the core component of the attribute management system.
|
14
|
+
# It coordinates type information, visibility settings, value coercion,
|
15
|
+
# validation, and change notifications for an attribute. Each instance
|
16
|
+
# represents a single attribute definition within a class.
|
17
|
+
#
|
18
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
19
|
+
# @since 0.1.0
|
20
|
+
class Attribute
|
21
|
+
# @rbs!
|
22
|
+
# type initialize_options = {
|
23
|
+
# ?callbacks: Array[Callback::handler] | Callback::handler,
|
24
|
+
# ?coercers: Array[Coercer::handler] | Coercer::handler,
|
25
|
+
# ?default: untyped,
|
26
|
+
# ?description: String?,
|
27
|
+
# name: String | Symbol,
|
28
|
+
# ?nilable: bool,
|
29
|
+
# ?position: Integer?,
|
30
|
+
# ?read: Signature::visibility_symbol,
|
31
|
+
# ?required: bool,
|
32
|
+
# type: Signature::type_symbol,
|
33
|
+
# ?validators: Array[Validator::handler] | Validator::handler,
|
34
|
+
# ?write: Signature::visibility_symbol
|
35
|
+
# }
|
36
|
+
|
37
|
+
# @rbs @base: __todo__
|
38
|
+
# @rbs @callback: Callback
|
39
|
+
# @rbs @coercer: Coercer
|
40
|
+
# @rbs @default: untyped
|
41
|
+
# @rbs @description: String?
|
42
|
+
# @rbs @name: Symbol
|
43
|
+
# @rbs @signature: Signature
|
44
|
+
# @rbs @validator: Validator
|
45
|
+
|
46
|
+
# @return [Class, Module] the class or module this attribute belongs to
|
47
|
+
attr_reader :base #: __todo__
|
48
|
+
|
49
|
+
# @return [String, nil] the description of the attribute
|
50
|
+
attr_reader :description #: String?
|
51
|
+
|
52
|
+
# @return [Symbol] the name of the attribute
|
53
|
+
attr_reader :name #: Symbol
|
54
|
+
|
55
|
+
# @return [Signature] the signature configuration for this attribute
|
56
|
+
attr_reader :signature #: Signature
|
57
|
+
|
58
|
+
# Initialize a new Attribute instance.
|
59
|
+
#
|
60
|
+
# @param base [Class, Module] the class or module this attribute belongs to
|
61
|
+
# @param options [Hash] the options to create the attribute with
|
62
|
+
# @option options [Array<Proc>, Proc] :callbacks callbacks to trigger on value changes
|
63
|
+
# @option options [Array<Proc, Symbol>, Proc, Symbol] :coercers handlers for value coercion
|
64
|
+
# @option options [Object] :default the default value or generator
|
65
|
+
# @option options [String] :description a description of the attribute
|
66
|
+
# @option options [String, Symbol] :name the name of the attribute
|
67
|
+
# @option options [Boolean] :nilable (true) whether the attribute can be nil
|
68
|
+
# @option options [Integer] :position the position for ordered attributes
|
69
|
+
# @option options [Symbol] :read the read visibility
|
70
|
+
# @option options [Boolean] :required (false) whether the attribute is required
|
71
|
+
# @option options [Symbol] :type the type of attribute
|
72
|
+
# @option options [Array<Proc, Object>, Proc, Object] :validators handlers for value validation
|
73
|
+
# @option options [Symbol] :write the write visibility
|
74
|
+
#
|
75
|
+
# @raise [ArgumentError] if the configuration is invalid
|
76
|
+
# @return [void]
|
77
|
+
#
|
78
|
+
# @rbs (
|
79
|
+
# __todo__ base,
|
80
|
+
# ?callbacks: Array[Callback::handler] | Callback::handler,
|
81
|
+
# ?coercers: Array[Coercer::handler] | Coercer::handler,
|
82
|
+
# ?default: untyped,
|
83
|
+
# ?description: String?,
|
84
|
+
# name: String | Symbol,
|
85
|
+
# ?nilable: bool,
|
86
|
+
# ?position: Integer?,
|
87
|
+
# ?read: Signature::visibility_symbol,
|
88
|
+
# ?required: bool,
|
89
|
+
# type: Signature::type_symbol,
|
90
|
+
# ?validators: Array[Validator::handler] | Validator::handler,
|
91
|
+
# ?write: Signature::visibility_symbol
|
92
|
+
# ) -> void
|
93
|
+
def initialize(base, **options)
|
94
|
+
options = options.transform_keys(&:to_sym)
|
95
|
+
# @type var options: initialize_options
|
96
|
+
validate_and_apply_initialize_options!(base, options)
|
97
|
+
rescue StandardError => e
|
98
|
+
raise ArgumentError, e.message
|
99
|
+
end
|
100
|
+
|
101
|
+
# Apply a value to the attribute on an instance.
|
102
|
+
#
|
103
|
+
# This method applies all attribute constraints (coercion, validation) to a value
|
104
|
+
# and sets it on the given instance. It manages the complete lifecycle of setting
|
105
|
+
# an attribute value including:
|
106
|
+
# 1. Handling default values
|
107
|
+
# 2. Coercing the value
|
108
|
+
# 3. Validating the result
|
109
|
+
# 4. Setting the value
|
110
|
+
# 5. Triggering callbacks
|
111
|
+
#
|
112
|
+
# @param instance [Object] the instance to set the value on
|
113
|
+
# @param value [Object] the value to set
|
114
|
+
#
|
115
|
+
# @raise [ArgumentError] if the value is invalid
|
116
|
+
# @return [void]
|
117
|
+
# @rbs (untyped instance, untyped value) -> void
|
118
|
+
def apply!(instance, value = Undefined)
|
119
|
+
old_value = instance.instance_variable_get(:"@#{name}")
|
120
|
+
|
121
|
+
coerced_value = value == Undefined ? generate_default(instance) : value
|
122
|
+
coerced_value = @coercer.call(instance, coerced_value) unless coerced_value == Undefined
|
123
|
+
|
124
|
+
@validator.call(instance, coerced_value)
|
125
|
+
|
126
|
+
instance.instance_variable_set(:"@#{name}", coerced_value == Undefined ? nil : coerced_value)
|
127
|
+
|
128
|
+
@callback.call(instance, old_value, coerced_value)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Check if this attribute has a default value.
|
132
|
+
#
|
133
|
+
# @return [Boolean] true if a default value is set
|
134
|
+
# @rbs () -> bool
|
135
|
+
def default?
|
136
|
+
@default != Undefined
|
137
|
+
end
|
138
|
+
|
139
|
+
# Create a duplicate instance for a new base class.
|
140
|
+
#
|
141
|
+
# @param new_base [Class, Module] the new base class
|
142
|
+
#
|
143
|
+
# @return [Attribute] the duplicated instance
|
144
|
+
# @rbs (__todo__ new_base) -> Attribute
|
145
|
+
def dup_with_base(new_base)
|
146
|
+
raise ArgumentError, "invalid base: #{new_base}" unless new_base.is_a?(Class) || new_base.is_a?(Module)
|
147
|
+
|
148
|
+
dup.tap { |duped| duped.instance_variable_set(:@base, new_base) }
|
149
|
+
end
|
150
|
+
|
151
|
+
# Generate the default value for this attribute.
|
152
|
+
#
|
153
|
+
# @param instance [Object] the instance to generate the default for
|
154
|
+
#
|
155
|
+
# @return [Object] the generated default value
|
156
|
+
# @rbs (untyped instance) -> untyped
|
157
|
+
def generate_default(instance)
|
158
|
+
@default.is_a?(Proc) ? instance.instance_exec(&@default) : @default
|
159
|
+
end
|
160
|
+
|
161
|
+
# Merge this attribute's configuration with another.
|
162
|
+
#
|
163
|
+
# @param other [Attribute] the attribute to merge with
|
164
|
+
#
|
165
|
+
# @raise [ArgumentError] if other is not an Attribute
|
166
|
+
# @return [Attribute] a new attribute with merged configuration
|
167
|
+
# @rbs (Attribute other) -> Attribute
|
168
|
+
def merge(other)
|
169
|
+
raise ArgumentError, 'other must be an instance of Attribute' unless other.is_a?(self.class)
|
170
|
+
|
171
|
+
self.class.new(other.base, **to_options, **other.send(:to_options)) # steep:ignore InsufficientKeywordArguments
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
# Apply initialization options to create attribute components.
|
177
|
+
#
|
178
|
+
# @param base [Class, Module] the base class
|
179
|
+
# @param options [Hash] the initialization options
|
180
|
+
#
|
181
|
+
# @return [void]
|
182
|
+
# @rbs (__todo__ base, initialize_options options) -> void
|
183
|
+
def apply_initialize_options!(base, options)
|
184
|
+
@base = base
|
185
|
+
@callback = Callback.new(self, options.fetch(:callbacks, []))
|
186
|
+
@coercer = Coercer.new(self, options.fetch(:coercers, []))
|
187
|
+
@default = options.fetch(:default, Undefined)
|
188
|
+
@description = options.fetch(:description, nil)
|
189
|
+
@name = options.fetch(:name).to_sym
|
190
|
+
@signature = Signature.new(
|
191
|
+
self, type: options.fetch(:type), **options.slice(:nilable, :position, :read, :required, :write)
|
192
|
+
)
|
193
|
+
@validator = Validator.new(self, options.fetch(:validators, []))
|
194
|
+
end
|
195
|
+
|
196
|
+
# Initialize a copy of this attribute.
|
197
|
+
#
|
198
|
+
# @param source [Attribute] the source attribute
|
199
|
+
#
|
200
|
+
# @return [Attribute] the initialized copy
|
201
|
+
# @rbs override
|
202
|
+
def initialize_copy(source)
|
203
|
+
@base = source.base
|
204
|
+
@callback = source.instance_variable_get(:@callback).dup_with_attribute(self)
|
205
|
+
@coercer = source.instance_variable_get(:@coercer).dup_with_attribute(self)
|
206
|
+
@default = source.instance_variable_get(:@default)
|
207
|
+
@description = source.description
|
208
|
+
@name = source.name
|
209
|
+
@signature = source.signature.dup_with_attribute(self)
|
210
|
+
@validator = source.instance_variable_get(:@validator).dup_with_attribute(self)
|
211
|
+
super
|
212
|
+
end
|
213
|
+
|
214
|
+
# Get this attribute's configuration as options.
|
215
|
+
#
|
216
|
+
# @return [Hash] the configuration options
|
217
|
+
# @rbs () -> initialize_options
|
218
|
+
def to_options
|
219
|
+
{
|
220
|
+
callbacks: @callback.instance_variable_get(:@handlers),
|
221
|
+
coercers: @coercer.instance_variable_get(:@handlers),
|
222
|
+
default: @default,
|
223
|
+
description: @description,
|
224
|
+
name: @name,
|
225
|
+
validators: @validator.instance_variable_get(:@handlers)
|
226
|
+
}.merge(signature.send(:to_options)) #: initialize_options
|
227
|
+
end
|
228
|
+
|
229
|
+
# Validate and apply initialization options.
|
230
|
+
#
|
231
|
+
# @param base [Class, Module] the base class
|
232
|
+
# @param options [Hash] the initialization options
|
233
|
+
#
|
234
|
+
# @return [void]
|
235
|
+
# @rbs (__todo__ base, initialize_options options) -> void
|
236
|
+
def validate_and_apply_initialize_options!(base, options)
|
237
|
+
validate_initialize_options!(base, options)
|
238
|
+
apply_initialize_options!(base, options)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Validate initialization options.
|
242
|
+
#
|
243
|
+
# @param base [Class, Module] the base class
|
244
|
+
# @param options [Hash] the initialization options
|
245
|
+
#
|
246
|
+
# @raise [ArgumentError] if any options are invalid
|
247
|
+
# @return [void]
|
248
|
+
# @rbs (__todo__ base, initialize_options options) -> void
|
249
|
+
def validate_initialize_options!(base, options)
|
250
|
+
raise ArgumentError, "invalid base: #{base}" unless base.is_a?(Class) || base.is_a?(Module)
|
251
|
+
raise ArgumentError, 'missing keyword :name' unless options.key?(:name)
|
252
|
+
raise ArgumentError, 'missing keyword :type' unless options.key?(:type)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'domainic/attributer/attribute'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Domainic
|
7
|
+
module Attributer
|
8
|
+
# A class representing an ordered collection of attributes.
|
9
|
+
#
|
10
|
+
# This class manages a set of attributes for a given class or module. It maintains
|
11
|
+
# attributes in a specific order determined by their type (argument vs option),
|
12
|
+
# default values, and position. The collection supports standard operations like
|
13
|
+
# adding, selecting, and merging attributes while maintaining proper ownership
|
14
|
+
# relationships with their base class.
|
15
|
+
#
|
16
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
17
|
+
# @since 0.1.0
|
18
|
+
class AttributeSet
|
19
|
+
extend Forwardable
|
20
|
+
|
21
|
+
# @rbs @base: __todo__
|
22
|
+
# @rbs @lookup: Hash[Symbol, Attribute]
|
23
|
+
|
24
|
+
# Initialize a new AttributeSet.
|
25
|
+
#
|
26
|
+
# @param base [Class, Module] the class or module this set belongs to
|
27
|
+
# @param attributes [Array<Attribute>] initial attributes to add
|
28
|
+
#
|
29
|
+
# @return [void]
|
30
|
+
# @rbs (__todo__ base, ?Array[Attribute] attributes) -> void
|
31
|
+
def initialize(base, attributes = [])
|
32
|
+
@base = base
|
33
|
+
@lookup = {}
|
34
|
+
attributes.each { |attribute| add(attribute) }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get an attribute by name.
|
38
|
+
#
|
39
|
+
# @param attribute_name [String, Symbol] the name of the attribute
|
40
|
+
#
|
41
|
+
# @return [Attribute, nil] the attribute if found
|
42
|
+
# @rbs (String | Symbol attribute_name) -> Attribute?
|
43
|
+
def [](attribute_name)
|
44
|
+
@lookup[attribute_name.to_sym]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add an attribute to the set.
|
48
|
+
#
|
49
|
+
# If an attribute with the same name exists, the attributes are merged.
|
50
|
+
# If the attribute belongs to a different base class, it is duplicated
|
51
|
+
# with the correct base. After adding, attributes are sorted by type
|
52
|
+
# and position.
|
53
|
+
#
|
54
|
+
# @param attribute [Attribute] the attribute to add
|
55
|
+
#
|
56
|
+
# @raise [ArgumentError] if attribute is invalid
|
57
|
+
# @return [void]
|
58
|
+
# @rbs (Attribute attribute) -> void
|
59
|
+
def add(attribute)
|
60
|
+
raise ArgumentError, "Invalid attribute: #{attribute.inspect}" unless attribute.is_a?(Attribute)
|
61
|
+
|
62
|
+
@lookup[attribute.name] = if @lookup.key?(attribute.name)
|
63
|
+
@lookup[attribute.name].merge(attribute).dup_with_base(@base)
|
64
|
+
elsif attribute.base != @base
|
65
|
+
attribute.dup_with_base(@base)
|
66
|
+
else
|
67
|
+
attribute
|
68
|
+
end
|
69
|
+
|
70
|
+
sort_lookup
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Check if an attribute exists in the set.
|
75
|
+
#
|
76
|
+
# @param attribute_name [String, Symbol] the name to check
|
77
|
+
#
|
78
|
+
# @return [Boolean] true if the attribute exists
|
79
|
+
def attribute?(attribute_name)
|
80
|
+
@lookup.key?(attribute_name.to_sym)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get all attribute names.
|
84
|
+
#
|
85
|
+
# @return [Array<Symbol>] the attribute names
|
86
|
+
# @rbs () -> Array[Symbol]
|
87
|
+
def attribute_names
|
88
|
+
@lookup.keys
|
89
|
+
end
|
90
|
+
|
91
|
+
# Get all attributes.
|
92
|
+
#
|
93
|
+
# @return [Array<Attribute>] the attributes
|
94
|
+
# @rbs () -> Array[Attribute]
|
95
|
+
def attributes
|
96
|
+
@lookup.values
|
97
|
+
end
|
98
|
+
|
99
|
+
# @rbs! def count: () ?{ (Symbol, Attribute) -> boolish } -> Integer
|
100
|
+
def_delegators :@lookup, :count
|
101
|
+
|
102
|
+
# Create a duplicate set for a new base class.
|
103
|
+
#
|
104
|
+
# @param new_base [Class, Module] the new base class
|
105
|
+
#
|
106
|
+
# @return [AttributeSet] the duplicated set
|
107
|
+
# @rbs (__todo__ base) -> AttributeSet
|
108
|
+
def dup_with_base(new_base)
|
109
|
+
dup.tap do |duped|
|
110
|
+
duped.instance_variable_set(:@base, new_base)
|
111
|
+
duped.instance_variable_set(
|
112
|
+
:@lookup,
|
113
|
+
@lookup.transform_values { |attribute| attribute.dup_with_base(new_base) }
|
114
|
+
)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Iterate over attribute name/value pairs.
|
119
|
+
#
|
120
|
+
# @yield [name, attribute] each name/attribute pair
|
121
|
+
# @yieldparam name [Symbol] the attribute name
|
122
|
+
# @yieldparam attribute [Attribute] the attribute
|
123
|
+
#
|
124
|
+
# @return [self]
|
125
|
+
# @rbs () { ([Symbol, Attribute]) -> untyped } -> self
|
126
|
+
def each(...)
|
127
|
+
@lookup.each(...)
|
128
|
+
self
|
129
|
+
end
|
130
|
+
alias each_pair each
|
131
|
+
|
132
|
+
# @rbs! def empty?: () -> bool
|
133
|
+
def_delegators :@lookup, :empty?
|
134
|
+
|
135
|
+
# Create a new set excluding specified attributes.
|
136
|
+
#
|
137
|
+
# @param attribute_names [Array<String, Symbol>] names to exclude
|
138
|
+
#
|
139
|
+
# @return [AttributeSet] new set without specified attributes
|
140
|
+
# @rbs (*String | Symbol attribute_names) -> AttributeSet
|
141
|
+
def except(*attribute_names)
|
142
|
+
self.class.new(@base, @lookup.except(*attribute_names.map(&:to_sym)).values)
|
143
|
+
end
|
144
|
+
|
145
|
+
# @rbs! def length: () -> Integer
|
146
|
+
def_delegators :@lookup, :length
|
147
|
+
|
148
|
+
# Merge another set into this one.
|
149
|
+
#
|
150
|
+
# @param other [AttributeSet] the set to merge
|
151
|
+
#
|
152
|
+
# @return [AttributeSet] new set with merged attributes
|
153
|
+
# @rbs (AttributeSet other) -> AttributeSet
|
154
|
+
def merge(other)
|
155
|
+
self.class.new(other.instance_variable_get(:@base), attributes + other.attributes)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Create a new set with rejected attributes.
|
159
|
+
#
|
160
|
+
# @yield [name, attribute] each name/attribute pair
|
161
|
+
# @yieldparam name [Symbol] the attribute name
|
162
|
+
# @yieldparam attribute [Attribute] the attribute
|
163
|
+
#
|
164
|
+
# @return [AttributeSet] new set without rejected attributes
|
165
|
+
# @rbs () { (Symbol, Attribute) -> boolish } -> AttributeSet
|
166
|
+
def reject(...)
|
167
|
+
self.class.new(@base, @lookup.reject(...).values)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Create a new set with selected attributes.
|
171
|
+
#
|
172
|
+
# @yield [name, attribute] each name/attribute pair
|
173
|
+
# @yieldparam name [Symbol] the attribute name
|
174
|
+
# @yieldparam attribute [Attribute] the attribute
|
175
|
+
#
|
176
|
+
# @return [AttributeSet] new set with selected attributes
|
177
|
+
# @rbs () { (Symbol, Attribute) -> boolish } -> AttributeSet
|
178
|
+
def select(...)
|
179
|
+
self.class.new(@base, @lookup.select(...).values)
|
180
|
+
end
|
181
|
+
|
182
|
+
# @rbs! def size: () -> Integer
|
183
|
+
def_delegators :@lookup, :size
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
# Sort attributes by type and position.
|
188
|
+
#
|
189
|
+
# Attributes are sorted first by type (required arguments, defaulted arguments,
|
190
|
+
# then options), and then by their position within those groups.
|
191
|
+
#
|
192
|
+
# @return [void]
|
193
|
+
# @rbs () -> void
|
194
|
+
def sort_lookup
|
195
|
+
@lookup = @lookup.sort_by do |_, attribute|
|
196
|
+
[
|
197
|
+
if attribute.signature.option?
|
198
|
+
2
|
199
|
+
else
|
200
|
+
(attribute.default? ? 1 : 0)
|
201
|
+
end,
|
202
|
+
attribute.signature.position
|
203
|
+
]
|
204
|
+
end.to_h
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|