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

Sign up to get free protection for your applications and to get access to all the features.
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: