domainic-type 0.1.0.alpha.3.0.1 → 0.1.0.alpha.3.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e4f8e0bb4883a197a5ed2f87b53a6dbc60ae70a41f48f6369881e8a5a5249b0
4
- data.tar.gz: b512246f56da3aa04d9b068c080324a7ab507f96b6749a6ed8701a8bc8615901
3
+ metadata.gz: 56d315e14fd05fe94174f580d09843c227cc5d763e994b47fd4094c26365dafc
4
+ data.tar.gz: cf0288834c42fdd9d985ddb889484273dbae5278e0b8f0f1bd0021317c0387ae
5
5
  SHA512:
6
- metadata.gz: 5d807fab460c97af3e8fc50acb0f834ae8bc881d56507c668908d1baaa3b983516280a79c361fe30da893e38aeffa04561f265605c9c33633c64578a4461550f
7
- data.tar.gz: c243d9fc6559e8d3be625c7db153d9964d2e36bcda90a33ba2e75f0cb8e69269cfa53542dddabf8fa7a4671da676bde29db7ae4893c5659d1702f38ff5a8f50f
6
+ metadata.gz: d53f6f1acc6969c093bb3617acb04ec17d507571c514604c941e378ad80341e7145d5f15298ec4922e68fc646e5f984cfc3e49fa8a7f2ab501d30456329dc9a4
7
+ data.tar.gz: 9e5a0a9815c013086aeb5d183b66f2dfa3e0db4c31d62b8357ce0a2a12ca5bd3aafdad0a94d8c01781171a61df7a37d9dacd21b5d9d9256fe218ce62bc7b81e7
@@ -8,6 +8,9 @@ constraints:
8
8
  any:
9
9
  constant: Domainic::Type::Constraint::AnyConstraint
10
10
  require_path: domainic/type/constraint/constraints/any_constraint
11
+ attribute_presence:
12
+ constant: Domainic::Type::Constraint::AttributePresenceConstraint
13
+ require_path: domainic/type/constraint/constraints/attribute_presence_constraint
11
14
  case:
12
15
  constant: Domainic::Type::Constraint::CaseConstraint
13
16
  require_path: domainic/type/constraint/constraints/case_constraint
@@ -29,6 +32,9 @@ constraints:
29
32
  inclusion:
30
33
  constant: Domainic::Type::Constraint::InclusionConstraint
31
34
  require_path: domainic/type/constraint/constraints/inclusion_constraint
35
+ instance_of:
36
+ constant: Domainic::Type::Constraint::InstanceOfConstraint
37
+ require_path: domainic/type/constraint/constraints/instance_of_constraint
32
38
  match_pattern:
33
39
  constant: Domainic::Type::Constraint::MatchPatternConstraint
34
40
  require_path: domainic/type/constraint/constraints/match_pattern_constraint
@@ -84,6 +90,9 @@ types:
84
90
  hash:
85
91
  constant: Domainic::Type::HashType
86
92
  require_path: domainic/type/types/core/hash_type
93
+ instance_type:
94
+ constant: Domainic::Type::InstanceType
95
+ require_path: domainic/type/types/specialized/instance_type
87
96
  integer:
88
97
  constant: Domainic::Type::IntegerType
89
98
  require_path: domainic/type/types/core/integer_type
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'domainic/type/behavior'
4
+ require 'domainic/type/constraint/behavior'
5
+
6
+ module Domainic
7
+ module Type
8
+ module Constraint
9
+ # A constraint that validates the presence and types of object attributes
10
+ #
11
+ # This constraint verifies that objects respond to specified attributes and that
12
+ # those attributes return values matching their corresponding type constraints.
13
+ # It supports both Ruby core types (Class/Module) and custom type constraints
14
+ # that implement the Type::Behavior interface.
15
+ #
16
+ # @example Basic attribute validation
17
+ # # Validate presence and basic Ruby types
18
+ # constraint = AttributePresenceConstraint.new(:self,
19
+ # username: String,
20
+ # age: Integer
21
+ # )
22
+ #
23
+ # # Success case
24
+ # user = User.new(username: "alice", age: 30)
25
+ # constraint.satisfied?(user) # => true
26
+ #
27
+ # # Missing attribute failure
28
+ # user = User.new(username: "bob")
29
+ # constraint.satisfied?(user) # => false
30
+ # constraint.short_violation_description # => "missing attributes: age"
31
+ #
32
+ # # Wrong type failure
33
+ # user = User.new(username: 123, age: "30")
34
+ # constraint.satisfied?(user) # => false
35
+ # constraint.short_violation_description
36
+ # # => "invalid attributes: username: 123, age: \"30\""
37
+ #
38
+ # @example With custom type constraints
39
+ # # Combine with other type constraints
40
+ # constraint = AttributePresenceConstraint.new(:self,
41
+ # username: _String.having_size_between(3, 20),
42
+ # role: _Enum(:admin, :user),
43
+ # email: _String.matching(/@/)
44
+ # )
45
+ #
46
+ # @author {https://aaronmallen.me Aaron Allen}
47
+ # @since 0.1.0
48
+ class AttributePresenceConstraint
49
+ include Behavior #[Hash[Symbol, Class | Module | Type::Behavior], untyped, {}]
50
+
51
+ # Get a description of what the constraint expects
52
+ #
53
+ # @return [String] the constraint description
54
+ # @rbs override
55
+ def short_description
56
+ "attributes #{@expected.map { |attribute, type| "#{attribute}: #{type.inspect}" }.join(', ')}".strip
57
+ end
58
+
59
+ # Get a description of why the constraint was violated
60
+ #
61
+ # @return [String] the violation description
62
+ # @rbs override
63
+ def short_violation_description
64
+ missing, invalid = violations
65
+ return '' if missing.empty? && invalid.empty?
66
+
67
+ # @type var missing: Array[Symbol]
68
+ # @type var invalid: Array[Symbol]
69
+
70
+ [
71
+ missing.empty? ? nil : "missing attributes: #{missing.join(', ')}",
72
+ invalid.empty? ? nil : "invalid attributes: #{format_invalid_attributes(invalid)}"
73
+ ].compact.join(' and ')
74
+ end
75
+
76
+ protected
77
+
78
+ # Coerce expectation hash keys into symbols
79
+ #
80
+ # @param expectation [Hash] the raw expectation hash
81
+ #
82
+ # @return [Hash] the coerced expectation
83
+ # @rbs override
84
+ def coerce_expectation(expectation)
85
+ return expectation unless expectation.is_a?(Hash)
86
+
87
+ expectation.transform_keys(&:to_sym)
88
+ end
89
+
90
+ # Format the list of invalid attributes for error messages
91
+ #
92
+ # @param invalid [Array<Symbol>] The list of invalid attribute names
93
+ #
94
+ # @return [String] formatted error message
95
+ # @rbs (Array[Symbol] invalid) -> String
96
+ def format_invalid_attributes(invalid)
97
+ invalid.map do |attribute| # use filter_map to exclude nil entries
98
+ "#{attribute}: #{@actual.public_send(attribute).inspect}"
99
+ end.join(', ')
100
+ end
101
+
102
+ # Check if the constraint is satisfied
103
+ #
104
+ # @return [Boolean] whether all attributes exist and have valid types
105
+ # @rbs override
106
+ def satisfies_constraint?
107
+ violations.all?(&:empty?)
108
+ end
109
+
110
+ # Check if a value satisfies a type constraint
111
+ #
112
+ # @param value [Object] the value to check
113
+ # @param type [Class, Module, Type::Behavior] the type to check against
114
+ #
115
+ # @return [Boolean] whether the value matches the type
116
+ # @rbs (untyped value, Class | Module | Type::Behavior type) -> bool
117
+ def satisfies_type?(value, type)
118
+ type === value || value.is_a?(type) # rubocop:disable Style/CaseEquality
119
+ end
120
+
121
+ # Validate the format of the expectation hash
122
+ #
123
+ # @param expectation [Hash] the expectation to validate
124
+ #
125
+ # @raise [ArgumentError] if the expectation is invalid
126
+ # @return [void]
127
+ # @rbs override
128
+ def validate_expectation!(expectation)
129
+ raise ArgumentError, 'Expectation must be a Hash' unless expectation.is_a?(Hash)
130
+ raise ArgumentError, 'Expectation must have symbolized keys' unless expectation.keys.all?(Symbol)
131
+
132
+ expectation.each_value do |value|
133
+ next if [Class, Module, Type::Behavior].any? { |type| value.is_a?(type) }
134
+
135
+ raise ArgumentError, 'Expectation must have values of Class, Module, or Domainic::Type'
136
+ end
137
+ end
138
+
139
+ # Get lists of missing and invalid attributes
140
+ #
141
+ # @return [Array(Array<Symbol>, Array<Symbol>)] missing and invalid attribute lists
142
+ # @rbs () -> Array[Array[Symbol]]
143
+ def violations
144
+ @violations ||= begin
145
+ missing = @expected.keys.reject { |attribute| @actual.respond_to?(attribute) }
146
+ invalid = @expected.reject do |attribute, type|
147
+ missing.include?(attribute) || satisfies_type?(@actual.public_send(attribute), type)
148
+ end.keys
149
+ [missing, invalid] #: Array[Array[Symbol]]
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'domainic/type/constraint/behavior'
4
+
5
+ module Domainic
6
+ module Type
7
+ module Constraint
8
+ # A constraint for validating that a value is an instance of a specified class or module.
9
+ #
10
+ # This constraint checks if the value is a direct instance of the expected class or module
11
+ # (excluding subclasses or other related types).
12
+ #
13
+ # @example Basic instance validation
14
+ # constraint = InstanceOfConstraint.new(:self, String)
15
+ # constraint.satisfied?("test") # => true
16
+ # constraint.satisfied?(:symbol) # => false
17
+ #
18
+ # @example Custom class validation
19
+ # class MyClass; end
20
+ # constraint = InstanceOfConstraint.new(:self, MyClass)
21
+ # constraint.satisfied?(MyClass.new) # => true
22
+ # constraint.satisfied?("test") # => false
23
+ #
24
+ # @author {https://aaronmallen.me Aaron Allen}
25
+ # @since 0.1.0
26
+ class InstanceOfConstraint
27
+ include Behavior #[Class | Module, untyped, {}]
28
+
29
+ # Get a human-readable description of the instance requirement.
30
+ #
31
+ # @example
32
+ # constraint = InstanceOfConstraint.new(:self, String)
33
+ # constraint.description # => "instance of String"
34
+ #
35
+ # @return [String] A description of the expected instance type
36
+ # @rbs override
37
+ def short_description
38
+ "instance of #{@expected}"
39
+ end
40
+
41
+ # Get a human-readable description of why instance validation failed.
42
+ #
43
+ # @example
44
+ # constraint = InstanceOfConstraint.new(:self, String)
45
+ # constraint.satisfied?(:symbol)
46
+ # constraint.short_violation_description # => "not an instance of String"
47
+ #
48
+ # @return [String] A description of the instance validation failure
49
+ # @rbs override
50
+ def short_violation_description
51
+ "not an instance of #{@expected}"
52
+ end
53
+
54
+ protected
55
+
56
+ # Check if the actual value is an instance of the expected class or module.
57
+ #
58
+ # @return [Boolean] true if the value is an instance of the expected class/module
59
+ # @rbs override
60
+ def satisfies_constraint?
61
+ @actual.class < @expected || @actual.instance_of?(@expected)
62
+ end
63
+
64
+ # Validate that the expected value is a Class or Module.
65
+ #
66
+ # @raise [ArgumentError] if the expected value is not a Class or Module
67
+ # @return [void]
68
+ # @rbs override
69
+ def validate_expectation!(expectation)
70
+ return if [Class, Module].any? { |mod| expectation.is_a?(mod) }
71
+
72
+ raise ArgumentError, 'Expectation must be a Class or Module'
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -218,6 +218,35 @@ module Domainic
218
218
  end
219
219
  alias _Map? _Hash?
220
220
 
221
+ # Create an InstanceType instance.
222
+ #
223
+ # @example
224
+ # _type = _Instance.of(User)
225
+ #
226
+ # @param options [Hash] additional configuration options
227
+ #
228
+ # @return [Domainic::Type::InstanceType]
229
+ # @rbs (**__todo__ options) -> InstanceType
230
+ def _Instance(**options)
231
+ require 'domainic/type/types/specialized/instance_type'
232
+ Domainic::Type::InstanceType.new(**options)
233
+ end
234
+ alias _Record _Instance
235
+
236
+ # Create an InstanceType instance.
237
+ #
238
+ # @example
239
+ # _type = _Instance?(of: User)
240
+ #
241
+ # @param options [Hash] additional configuration options
242
+ #
243
+ # @return [Domainic::Type::UnionType] the created type (Integer or NilClass)
244
+ # @rbs (**__todo__ options) -> UnionType
245
+ def _Instance?(**options)
246
+ _Nilable(_Instance(**options))
247
+ end
248
+ alias _Record? _Instance?
249
+
221
250
  # Creates an IntegerType instance.
222
251
  #
223
252
  # @example
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'domainic/type/behavior'
4
+
5
+ module Domainic
6
+ module Type
7
+ # A type for validation that an object is an instance of a specific class or module.
8
+ #
9
+ # This class provides flexible constraints for ensuring objects conform to
10
+ # expected types, including specific class or module checks, as well as
11
+ # constraints on attributes within those objects.
12
+ #
13
+ # Key features:
14
+ # - Instance type constraints for classes and modules
15
+ # - Attribute presence constraints
16
+ # - Extensible through the Domainic type system
17
+ #
18
+ # @example Basic usage
19
+ # type = InstanceType.new
20
+ # type.of(String) # enforce instance of String
21
+ # type.constrain("example") # => true
22
+ # type.constrain(123) # => false
23
+ #
24
+ # @example Attribute constraints
25
+ # type = InstanceType.new
26
+ # type.having_attributes(name: String, age: Integer) # enforce attribute presence and types
27
+ # type.constrain(OpenStruct.new(name: "John", age: 30)) # => true
28
+ # type.constrain(OpenStruct.new(name: "John")) # => false
29
+ #
30
+ # @example Combined constraints
31
+ # type = InstanceType.new
32
+ # type
33
+ # .of(User) # enforce instance of User
34
+ # .having_attributes(:email => String, :admin => Symbol) # attribute constraints
35
+ # type.validate(User.new(email: "admin@example.com", admin: :admin)) # => true
36
+ #
37
+ # @author {https://aaronmallen.me Aaron Allen}
38
+ # @since 0.1.0
39
+ class InstanceType
40
+ # @rbs! extend Behavior::ClassMethods
41
+
42
+ include Behavior
43
+
44
+ # Constrain that the object has specific attributes.
45
+ #
46
+ # @example
47
+ # type.having_attributes(name: String, age: Integer)
48
+ # type.constrain(OpenStruct.new(name: "John", age: 30)) # => true
49
+ # type.constrain(OpenStruct.new(name: "John")) # => false
50
+ #
51
+ # @param attributes [Hash{String, Symbol => Class, Module, Behavior}] the attributes and their expected types
52
+ # @return [self] self for method chaining
53
+ # @rbs (Hash[String | Symbol, Class | Module | Behavior] attributes) -> self
54
+ def having_attributes(attributes)
55
+ constrain :self, :attribute_presence, attributes, description: 'having'
56
+ end
57
+
58
+ # Constrain that the object is an instance of the specified class or module.
59
+ #
60
+ # @example
61
+ # type.of(String)
62
+ # type.constrain("example") # => true
63
+ # type.constrain(123) # => false
64
+ #
65
+ # @param type [Class, Module, Behavior] the expected class, module, or behavior
66
+ # @return [self] self for method chaining
67
+ # @rbs (Class | Module | Behavior type) -> self
68
+ def of(type)
69
+ constrain :self, :instance_of, type, description: 'of'
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,98 @@
1
+ module Domainic
2
+ module Type
3
+ module Constraint
4
+ # A constraint that validates the presence and types of object attributes
5
+ #
6
+ # This constraint verifies that objects respond to specified attributes and that
7
+ # those attributes return values matching their corresponding type constraints.
8
+ # It supports both Ruby core types (Class/Module) and custom type constraints
9
+ # that implement the Type::Behavior interface.
10
+ #
11
+ # @example Basic attribute validation
12
+ # # Validate presence and basic Ruby types
13
+ # constraint = AttributePresenceConstraint.new(:self,
14
+ # username: String,
15
+ # age: Integer
16
+ # )
17
+ #
18
+ # # Success case
19
+ # user = User.new(username: "alice", age: 30)
20
+ # constraint.satisfied?(user) # => true
21
+ #
22
+ # # Missing attribute failure
23
+ # user = User.new(username: "bob")
24
+ # constraint.satisfied?(user) # => false
25
+ # constraint.short_violation_description # => "missing attributes: age"
26
+ #
27
+ # # Wrong type failure
28
+ # user = User.new(username: 123, age: "30")
29
+ # constraint.satisfied?(user) # => false
30
+ # constraint.short_violation_description
31
+ # # => "invalid attributes: username: 123, age: \"30\""
32
+ #
33
+ # @example With custom type constraints
34
+ # # Combine with other type constraints
35
+ # constraint = AttributePresenceConstraint.new(:self,
36
+ # username: _String.having_size_between(3, 20),
37
+ # role: _Enum(:admin, :user),
38
+ # email: _String.matching(/@/)
39
+ # )
40
+ #
41
+ # @author {https://aaronmallen.me Aaron Allen}
42
+ # @since 0.1.0
43
+ class AttributePresenceConstraint
44
+ include Behavior[Hash[Symbol, Class | Module | Type::Behavior], untyped, { }]
45
+
46
+ # Get a description of what the constraint expects
47
+ #
48
+ # @return [String] the constraint description
49
+ def short_description: ...
50
+
51
+ # Get a description of why the constraint was violated
52
+ #
53
+ # @return [String] the violation description
54
+ def short_violation_description: ...
55
+
56
+ # Coerce expectation hash keys into symbols
57
+ #
58
+ # @param expectation [Hash] the raw expectation hash
59
+ #
60
+ # @return [Hash] the coerced expectation
61
+ def coerce_expectation: ...
62
+
63
+ # Format the list of invalid attributes for error messages
64
+ #
65
+ # @param invalid [Array<Symbol>] The list of invalid attribute names
66
+ #
67
+ # @return [String] formatted error message
68
+ def format_invalid_attributes: (Array[Symbol] invalid) -> String
69
+
70
+ # Check if the constraint is satisfied
71
+ #
72
+ # @return [Boolean] whether all attributes exist and have valid types
73
+ def satisfies_constraint?: ...
74
+
75
+ # Check if a value satisfies a type constraint
76
+ #
77
+ # @param value [Object] the value to check
78
+ # @param type [Class, Module, Type::Behavior] the type to check against
79
+ #
80
+ # @return [Boolean] whether the value matches the type
81
+ def satisfies_type?: (untyped value, Class | Module | Type::Behavior type) -> bool
82
+
83
+ # Validate the format of the expectation hash
84
+ #
85
+ # @param expectation [Hash] the expectation to validate
86
+ #
87
+ # @raise [ArgumentError] if the expectation is invalid
88
+ # @return [void]
89
+ def validate_expectation!: ...
90
+
91
+ # Get lists of missing and invalid attributes
92
+ #
93
+ # @return [Array(Array<Symbol>, Array<Symbol>)] missing and invalid attribute lists
94
+ def violations: () -> Array[Array[Symbol]]
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,57 @@
1
+ module Domainic
2
+ module Type
3
+ module Constraint
4
+ # A constraint for validating that a value is an instance of a specified class or module.
5
+ #
6
+ # This constraint checks if the value is a direct instance of the expected class or module
7
+ # (excluding subclasses or other related types).
8
+ #
9
+ # @example Basic instance validation
10
+ # constraint = InstanceOfConstraint.new(:self, String)
11
+ # constraint.satisfied?("test") # => true
12
+ # constraint.satisfied?(:symbol) # => false
13
+ #
14
+ # @example Custom class validation
15
+ # class MyClass; end
16
+ # constraint = InstanceOfConstraint.new(:self, MyClass)
17
+ # constraint.satisfied?(MyClass.new) # => true
18
+ # constraint.satisfied?("test") # => false
19
+ #
20
+ # @author {https://aaronmallen.me Aaron Allen}
21
+ # @since 0.1.0
22
+ class InstanceOfConstraint
23
+ include Behavior[Class | Module, untyped, { }]
24
+
25
+ # Get a human-readable description of the instance requirement.
26
+ #
27
+ # @example
28
+ # constraint = InstanceOfConstraint.new(:self, String)
29
+ # constraint.description # => "instance of String"
30
+ #
31
+ # @return [String] A description of the expected instance type
32
+ def short_description: ...
33
+
34
+ # Get a human-readable description of why instance validation failed.
35
+ #
36
+ # @example
37
+ # constraint = InstanceOfConstraint.new(:self, String)
38
+ # constraint.satisfied?(:symbol)
39
+ # constraint.short_violation_description # => "not an instance of String"
40
+ #
41
+ # @return [String] A description of the instance validation failure
42
+ def short_violation_description: ...
43
+
44
+ # Check if the actual value is an instance of the expected class or module.
45
+ #
46
+ # @return [Boolean] true if the value is an instance of the expected class/module
47
+ def satisfies_constraint?: ...
48
+
49
+ # Validate that the expected value is a Class or Module.
50
+ #
51
+ # @raise [ArgumentError] if the expected value is not a Class or Module
52
+ # @return [void]
53
+ def validate_expectation!: ...
54
+ end
55
+ end
56
+ end
57
+ end
@@ -184,6 +184,30 @@ module Domainic
184
184
 
185
185
  alias _Map? _Hash?
186
186
 
187
+ # Create an InstanceType instance.
188
+ #
189
+ # @example
190
+ # _type = _Instance.of(User)
191
+ #
192
+ # @param options [Hash] additional configuration options
193
+ #
194
+ # @return [Domainic::Type::InstanceType]
195
+ def _Instance: (**__todo__ options) -> InstanceType
196
+
197
+ alias _Record _Instance
198
+
199
+ # Create an InstanceType instance.
200
+ #
201
+ # @example
202
+ # _type = _Instance?(of: User)
203
+ #
204
+ # @param options [Hash] additional configuration options
205
+ #
206
+ # @return [Domainic::Type::UnionType] the created type (Integer or NilClass)
207
+ def _Instance?: (**__todo__ options) -> UnionType
208
+
209
+ alias _Record? _Instance?
210
+
187
211
  # Creates an IntegerType instance.
188
212
  #
189
213
  # @example
@@ -0,0 +1,63 @@
1
+ module Domainic
2
+ module Type
3
+ # A type for validation that an object is an instance of a specific class or module.
4
+ #
5
+ # This class provides flexible constraints for ensuring objects conform to
6
+ # expected types, including specific class or module checks, as well as
7
+ # constraints on attributes within those objects.
8
+ #
9
+ # Key features:
10
+ # - Instance type constraints for classes and modules
11
+ # - Attribute presence constraints
12
+ # - Extensible through the Domainic type system
13
+ #
14
+ # @example Basic usage
15
+ # type = InstanceType.new
16
+ # type.of(String) # enforce instance of String
17
+ # type.constrain("example") # => true
18
+ # type.constrain(123) # => false
19
+ #
20
+ # @example Attribute constraints
21
+ # type = InstanceType.new
22
+ # type.having_attributes(name: String, age: Integer) # enforce attribute presence and types
23
+ # type.constrain(OpenStruct.new(name: "John", age: 30)) # => true
24
+ # type.constrain(OpenStruct.new(name: "John")) # => false
25
+ #
26
+ # @example Combined constraints
27
+ # type = InstanceType.new
28
+ # type
29
+ # .of(User) # enforce instance of User
30
+ # .having_attributes(:email => String, :admin => Symbol) # attribute constraints
31
+ # type.validate(User.new(email: "admin@example.com", admin: :admin)) # => true
32
+ #
33
+ # @author {https://aaronmallen.me Aaron Allen}
34
+ # @since 0.1.0
35
+ class InstanceType
36
+ extend Behavior::ClassMethods
37
+
38
+ include Behavior
39
+
40
+ # Constrain that the object has specific attributes.
41
+ #
42
+ # @example
43
+ # type.having_attributes(name: String, age: Integer)
44
+ # type.constrain(OpenStruct.new(name: "John", age: 30)) # => true
45
+ # type.constrain(OpenStruct.new(name: "John")) # => false
46
+ #
47
+ # @param attributes [Hash{String, Symbol => Class, Module, Behavior}] the attributes and their expected types
48
+ # @return [self] self for method chaining
49
+ def having_attributes: (Hash[String | Symbol, Class | Module | Behavior] attributes) -> self
50
+
51
+ # Constrain that the object is an instance of the specified class or module.
52
+ #
53
+ # @example
54
+ # type.of(String)
55
+ # type.constrain("example") # => true
56
+ # type.constrain(123) # => false
57
+ #
58
+ # @param type [Class, Module, Behavior] the expected class, module, or behavior
59
+ # @return [self] self for method chaining
60
+ def of: (Class | Module | Behavior type) -> self
61
+ end
62
+ end
63
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: domainic-type
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha.3.0.1
4
+ version: 0.1.0.alpha.3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Allen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-24 00:00:00.000000000 Z
11
+ date: 2024-12-25 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Stop wrestling with complex type validations and unclear error messages.
14
14
  Domainic::Type brings type validation to Ruby that is both powerful and delightful
@@ -37,6 +37,7 @@ files:
37
37
  - lib/domainic/type/constraint/constraints/all_constraint.rb
38
38
  - lib/domainic/type/constraint/constraints/and_constraint.rb
39
39
  - lib/domainic/type/constraint/constraints/any_constraint.rb
40
+ - lib/domainic/type/constraint/constraints/attribute_presence_constraint.rb
40
41
  - lib/domainic/type/constraint/constraints/case_constraint.rb
41
42
  - lib/domainic/type/constraint/constraints/character_set_constraint.rb
42
43
  - lib/domainic/type/constraint/constraints/divisibility_constraint.rb
@@ -44,6 +45,7 @@ files:
44
45
  - lib/domainic/type/constraint/constraints/equality_constraint.rb
45
46
  - lib/domainic/type/constraint/constraints/finiteness_constraint.rb
46
47
  - lib/domainic/type/constraint/constraints/inclusion_constraint.rb
48
+ - lib/domainic/type/constraint/constraints/instance_of_constraint.rb
47
49
  - lib/domainic/type/constraint/constraints/match_pattern_constraint.rb
48
50
  - lib/domainic/type/constraint/constraints/method_presence_constraint.rb
49
51
  - lib/domainic/type/constraint/constraints/none_constraint.rb
@@ -65,6 +67,7 @@ files:
65
67
  - lib/domainic/type/types/core/integer_type.rb
66
68
  - lib/domainic/type/types/core/string_type.rb
67
69
  - lib/domainic/type/types/core/symbol_type.rb
70
+ - lib/domainic/type/types/specialized/instance_type.rb
68
71
  - lib/domainic/type/types/specification/anything_type.rb
69
72
  - lib/domainic/type/types/specification/duck_type.rb
70
73
  - lib/domainic/type/types/specification/enum_type.rb
@@ -82,6 +85,7 @@ files:
82
85
  - sig/domainic/type/constraint/constraints/all_constraint.rbs
83
86
  - sig/domainic/type/constraint/constraints/and_constraint.rbs
84
87
  - sig/domainic/type/constraint/constraints/any_constraint.rbs
88
+ - sig/domainic/type/constraint/constraints/attribute_presence_constraint.rbs
85
89
  - sig/domainic/type/constraint/constraints/case_constraint.rbs
86
90
  - sig/domainic/type/constraint/constraints/character_set_constraint.rbs
87
91
  - sig/domainic/type/constraint/constraints/divisibility_constraint.rbs
@@ -89,6 +93,7 @@ files:
89
93
  - sig/domainic/type/constraint/constraints/equality_constraint.rbs
90
94
  - sig/domainic/type/constraint/constraints/finiteness_constraint.rbs
91
95
  - sig/domainic/type/constraint/constraints/inclusion_constraint.rbs
96
+ - sig/domainic/type/constraint/constraints/instance_of_constraint.rbs
92
97
  - sig/domainic/type/constraint/constraints/match_pattern_constraint.rbs
93
98
  - sig/domainic/type/constraint/constraints/method_presence_constraint.rbs
94
99
  - sig/domainic/type/constraint/constraints/none_constraint.rbs
@@ -110,21 +115,22 @@ files:
110
115
  - sig/domainic/type/types/core/integer_type.rbs
111
116
  - sig/domainic/type/types/core/string_type.rbs
112
117
  - sig/domainic/type/types/core/symbol_type.rbs
118
+ - sig/domainic/type/types/specialized/instance_type.rbs
113
119
  - sig/domainic/type/types/specification/anything_type.rbs
114
120
  - sig/domainic/type/types/specification/duck_type.rbs
115
121
  - sig/domainic/type/types/specification/enum_type.rbs
116
122
  - sig/domainic/type/types/specification/union_type.rbs
117
123
  - sig/domainic/type/types/specification/void_type.rbs
118
124
  - sig/manifest.yaml
119
- homepage: https://github.com/domainic/domainic/tree/domainic-type-v0.1.0-alpha.3.0.1/domainic-type
125
+ homepage: https://github.com/domainic/domainic/tree/domainic-type-v0.1.0-alpha.3.0.2/domainic-type
120
126
  licenses:
121
127
  - MIT
122
128
  metadata:
123
129
  bug_tracker_uri: https://github.com/domainic/domainic/issues
124
- changelog_uri: https://github.com/domainic/domainic/releases/tag/domainic-type-v0.1.0-alpha.3.0.1
125
- homepage_uri: https://github.com/domainic/domainic/tree/domainic-type-v0.1.0-alpha.3.0.1/domainic-type
130
+ changelog_uri: https://github.com/domainic/domainic/releases/tag/domainic-type-v0.1.0-alpha.3.0.2
131
+ homepage_uri: https://github.com/domainic/domainic/tree/domainic-type-v0.1.0-alpha.3.0.2/domainic-type
126
132
  rubygems_mfa_required: 'true'
127
- source_code_uri: https://github.com/domainic/domainic/tree/domainic-type-v0.1.0-alpha.3.0.1/domainic-type
133
+ source_code_uri: https://github.com/domainic/domainic/tree/domainic-type-v0.1.0-alpha.3.0.2/domainic-type
128
134
  post_install_message:
129
135
  rdoc_options: []
130
136
  require_paths: