domainic-type 0.1.0.alpha.3.2.0 → 0.1.0.alpha.3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/README.md +66 -10
  4. data/docs/USAGE.md +787 -0
  5. data/lib/domainic/type/accessors.rb +3 -2
  6. data/lib/domainic/type/behavior/date_time_behavior.rb +121 -37
  7. data/lib/domainic/type/behavior.rb +16 -0
  8. data/lib/domainic/type/config/registry.yml +24 -0
  9. data/lib/domainic/type/constraint/constraints/nor_constraint.rb +1 -1
  10. data/lib/domainic/type/constraint/constraints/predicate_constraint.rb +76 -0
  11. data/lib/domainic/type/definitions.rb +212 -0
  12. data/lib/domainic/type/types/core/complex_type.rb +122 -0
  13. data/lib/domainic/type/types/core/range_type.rb +47 -0
  14. data/lib/domainic/type/types/core/rational_type.rb +38 -0
  15. data/lib/domainic/type/types/core_extended/big_decimal_type.rb +34 -0
  16. data/lib/domainic/type/types/core_extended/set_type.rb +34 -0
  17. data/lib/domainic/type/types/datetime/date_time_string_type.rb +156 -0
  18. data/lib/domainic/type/types/datetime/timestamp_type.rb +50 -0
  19. data/sig/domainic/type/accessors.rbs +2 -2
  20. data/sig/domainic/type/behavior/date_time_behavior.rbs +35 -23
  21. data/sig/domainic/type/behavior.rbs +9 -0
  22. data/sig/domainic/type/constraint/constraints/predicate_constraint.rbs +56 -0
  23. data/sig/domainic/type/definitions.rbs +165 -0
  24. data/sig/domainic/type/types/core/complex_type.rbs +96 -0
  25. data/sig/domainic/type/types/core/range_type.rbs +41 -0
  26. data/sig/domainic/type/types/core/rational_type.rbs +32 -0
  27. data/sig/domainic/type/types/core_extended/big_decimal_type.rbs +27 -0
  28. data/sig/domainic/type/types/core_extended/set_type.rbs +27 -0
  29. data/sig/domainic/type/types/datetime/date_time_string_type.rbs +124 -0
  30. data/sig/domainic/type/types/datetime/timestamp_type.rbs +44 -0
  31. metadata +25 -6
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'domainic/type/behavior'
4
+ require 'domainic/type/behavior/date_time_behavior'
5
+
6
+ module Domainic
7
+ module Type
8
+ # A type for validating Unix timestamps (seconds since the Unix epoch).
9
+ #
10
+ # This type ensures the value is an `Integer` representing a valid Unix
11
+ # timestamp. It integrates with `DateTimeBehavior` to provide a rich set of
12
+ # validation capabilities, including chronological constraints and range checks.
13
+ #
14
+ # Key features:
15
+ # - Ensures the value is an `Integer` representing a Unix timestamp.
16
+ # - Supports chronological relationship constraints (e.g., before, after).
17
+ # - Provides range, equality, and nilable checks.
18
+ #
19
+ # @example Basic usage
20
+ # type = TimestampType.new
21
+ # type.validate(Time.now.to_i) # => true
22
+ # type.validate(Date.today.to_time.to_i) # => true
23
+ # type.validate('invalid') # => false
24
+ #
25
+ # @example Range validation
26
+ # type = TimestampType.new
27
+ # .being_between(Time.now.to_i, (Time.now + 3600).to_i)
28
+ # type.validate((Time.now + 1800).to_i) # => true
29
+ # type.validate((Time.now + 7200).to_i) # => false
30
+ #
31
+ # @example Historical timestamps
32
+ # type = TimestampType.new
33
+ # type.validate(-1234567890) # => true (date before 1970-01-01)
34
+ #
35
+ # @example Nilable timestamp
36
+ # nilable_type = _Nilable(TimestampType.new)
37
+ # nilable_type.validate(nil) # => true
38
+ #
39
+ # @author {https://aaronmallen.me Aaron Allen}
40
+ # @since 0.1.0
41
+ class TimestampType
42
+ # @rbs! extend Behavior::ClassMethods
43
+
44
+ include Behavior
45
+ include Behavior::DateTimeBehavior
46
+
47
+ intrinsically_constrain :self, :type, Integer, abort_on_failure: true, description: :not_described
48
+ end
49
+ end
50
+ end
@@ -1,11 +1,11 @@
1
1
  module Domainic
2
2
  module Type
3
- type accessor = :abs | :begin | :chars | :class | :count | :end | :entries | :first | :keys | :last | :length | :self | :size | :values
3
+ type accessor = :abs | :begin | :chars | :class | :count | :end | :entries | :first | :keys | :last | :length | :real | :self | :size | :values
4
4
 
5
5
  # A list of valid access methods that can be used to retrieve values for constraint validation.
6
6
  # These methods represent common Ruby interfaces for accessing collection sizes, ranges, and values.
7
7
  #
8
- # - :abs - For absolute values
8
+ # - :abs, :real - For absolute values
9
9
  # - :begin, :end - For Range-like objects
10
10
  # - :class - For type checking
11
11
  # - :count, :length, :size - For measuring collections
@@ -24,73 +24,85 @@ module Domainic
24
24
  # @author {https://aaronmallen.me Aaron Allen}
25
25
  # @since 0.1.0
26
26
  module DateTimeBehavior
27
- TO_DATETIME_COERCER: Proc
27
+ # The supported date/time patterns for parsing date/time strings
28
+ #
29
+ # @note This list is ordered from most specific to least specific to ensure that the most specific patterns are
30
+ # tried first. This is important because some patterns are more lenient than others and may match a wider range
31
+ # of input strings.
32
+ #
33
+ # @return [Array<String>] the supported date/time patterns
34
+ DATETIME_PATTERNS: Array[String]
35
+
36
+ # Coerce a value to a Date, DateTime, or Time object
37
+ #
38
+ # @return [Proc] a lambda that coerces a value to a Date, DateTime, or Time object
39
+ TO_DATETIME_COERCER: ^(Date | DateTime | Integer | String | Time value) -> (Date | DateTime | Time)
28
40
 
29
41
  # Parse arguments for being_between
30
42
  #
31
43
  # @note this in my opinion is better than polluting the namespace of the including class even with a private
32
44
  # method. This way, the method is only available within the module itself. See {#being_between}.
33
45
  #
34
- # @param after [Date, DateTime, String, Time, nil] minimum size value from positional args
35
- # @param before [Date, DateTime, String, Time, nil] maximum size value from positional args
46
+ # @param after [Date, DateTime, Integer, String, Time, nil] minimum size value from positional args
47
+ # @param before [Date, DateTime, Integer, String, Time, nil] maximum size value from positional args
36
48
  # @param options [Hash] keyword arguments containing after/before values
37
49
  #
38
50
  # @raise [ArgumentError] if minimum or maximum value can't be determined
39
- # @return [Array<Date, DateTime, String, Time, nil>] parsed [after, before] values
40
- private def self.parse_being_between_arguments!: ((Date | DateTime | String | Time)? after, (Date | DateTime | String | Time)? before, Hash[Symbol, (Date | DateTime | String | Time)?] options) -> Array[(Date | DateTime | String | Time)?]
51
+ # @return [Array<Date, DateTime, Integer, String, Time, nil>] parsed [after, before] values
52
+ private def self.parse_being_between_arguments!: ((Date | DateTime | Integer | String | Time)? after, (Date | DateTime | Integer | String | Time)? before, Hash[Symbol, (Date | DateTime | Integer | String | Time)?] options) -> Array[(Date | DateTime | Integer | String | Time)?]
41
53
 
42
54
  # Raise appropriate ArgumentError for being_between
43
55
  #
44
56
  # @param original_caller [Array<String>] caller stack for error
45
- # @param after [Date, DateTime, String, Time, nil] after value from positional args
46
- # @param before [Date, DateTime, String, Time, nil] before value from positional args
57
+ # @param after [Date, DateTime, Integer, String, Time, nil] after value from positional args
58
+ # @param before [Date, DateTime, Integer, String, Time, nil] before value from positional args
47
59
  # @param options [Hash] keyword arguments containing after/before values
48
60
  #
49
61
  # @raise [ArgumentError] with appropriate message
50
62
  # @return [void]
51
- private def self.raise_being_between_argument_error!: (Array[String] original_caller, (Date | DateTime | String | Time)? after, (Date | DateTime | String | Time)? before, Hash[Symbol, (Date | DateTime | String | Time)?] options) -> void
63
+ private def self.raise_being_between_argument_error!: (Array[String] original_caller, (Date | DateTime | Integer | String | Time)? after, (Date | DateTime | Integer | String | Time)? before, Hash[Symbol, (Date | DateTime | Integer | String | Time)?] options) -> void
52
64
 
53
65
  # Constrain the value to be chronologically after a given date/time
54
66
  #
55
- # @param other [Date, DateTime, String, Time] the date/time to compare against
67
+ # @param other [Date, DateTime, Integer, String, Time] the date/time to compare against
56
68
  # @return [self] self for method chaining
57
- def being_after: (Date | DateTime | String | Time other) -> Behavior
69
+ def being_after: (Date | DateTime | Integer | String | Time other) -> Behavior
58
70
 
59
71
  alias after being_after
60
72
 
61
73
  # Constrain the value to be chronologically before a given date/time
62
74
  #
63
- # @param other [Date, DateTime, String, Time] the date/time to compare against
75
+ # @param other [Date, DateTime, Integer, String, Time] the date/time to compare against
64
76
  # @return [self] self for method chaining
65
- def being_before: (Date | DateTime | String | Time other) -> Behavior
77
+ def being_before: (Date | DateTime | Integer | String | Time other) -> Behavior
66
78
 
67
79
  alias before being_before
68
80
 
69
81
  # Constrain the value to be chronologically between two date/times
70
82
  #
71
- # @param after [Date, DateTime, String, Time] the earliest allowed date/time
72
- # @param before [Date, DateTime, String, Time] the latest allowed date/time
83
+ # @param after [Date, DateTime, Integer, String, Time] the earliest allowed date/time
84
+ # @param before [Date, DateTime, Integer, String, Time] the latest allowed date/time
73
85
  # @param options [Hash] alternative way to specify after/before via keywords
74
- # @option options [Date, DateTime, String, Time] :after earliest allowed date/time
75
- # @option options [Date, DateTime, String, Time] :before latest allowed date/time
86
+ # @option options [Date, DateTime, Integer, String, Time] :after earliest allowed date/time
87
+ # @option options [Date, DateTime, Integer, String, Time] :before latest allowed date/time
76
88
  # @return [self] self for method chaining
77
- def being_between: (Date | DateTime | String | Time after, Date | DateTime | String | Time before) -> Behavior
89
+ def being_between: (Date | DateTime | Integer | String | Time after, Date | DateTime | Integer | String | Time before) -> Behavior
78
90
 
79
91
  alias between being_between
80
92
 
81
93
  # Constrain the value to be exactly equal to a given date/time
82
94
  #
83
- # @param other [Date, DateTime, String, Time] the date/time to compare against
95
+ # @param other [Date, DateTime, Integer, String, Time] the date/time to compare against
84
96
  # @return [self] self for method chaining
85
- def being_equal_to: (Date | DateTime | String | Time other) -> Behavior
97
+ def being_equal_to: (Date | DateTime | Integer | String | Time other) -> Behavior
86
98
 
87
99
  alias at being_equal_to
88
100
 
89
101
  # Constrain the value to be chronologically on or after a given date/time
90
102
  #
91
- # @param other [Date, DateTime, String, Time] the date/time to compare against
103
+ # @param other [Date, DateTime, Integer, String, Time] the date/time to compare against
92
104
  # @return [self] self for method chaining
93
- def being_on_or_after: (Date | DateTime | String | Time other) -> Behavior
105
+ def being_on_or_after: (Date | DateTime | Integer | String | Time other) -> Behavior
94
106
 
95
107
  alias at_or_after being_on_or_after
96
108
 
@@ -100,9 +112,9 @@ module Domainic
100
112
 
101
113
  # Constrain the value to be chronologically on or before a given date/time
102
114
  #
103
- # @param other [Date, DateTime, String, Time] the date/time to compare against
115
+ # @param other [Date, DateTime, Integer, String, Time] the date/time to compare against
104
116
  # @return [self] self for method chaining
105
- def being_on_or_before: (Date | DateTime | String | Time other) -> Behavior
117
+ def being_on_or_before: (Date | DateTime | Integer | String | Time other) -> Behavior
106
118
 
107
119
  alias at_or_before being_on_or_before
108
120
 
@@ -125,6 +125,15 @@ module Domainic
125
125
  # @return [void]
126
126
  def initialize: (**untyped) -> void
127
127
 
128
+ # Add a custom constraint to this type.
129
+ #
130
+ # @param proc [Proc] the constraint to add
131
+ # @param accessor [Type::Accessor] the accessor to constrain
132
+ # @param options [Hash{Symbol => Object}] additional constraint options
133
+ #
134
+ # @return [self] for chaining constraints
135
+ def satisfies: (Proc proc, ?accessor: Type::accessor, **untyped options) -> Behavior
136
+
128
137
  # Convert the type to a String representation.
129
138
  #
130
139
  # @return [String] The type as a String
@@ -0,0 +1,56 @@
1
+ module Domainic
2
+ module Type
3
+ module Constraint
4
+ # A constraint for validating values using a custom predicate function.
5
+ #
6
+ # This constraint allows for custom validation logic through a Proc that returns
7
+ # a boolean value. It enables users to create arbitrary validation rules when
8
+ # the built-in constraints don't cover their specific needs.
9
+ #
10
+ # @example Basic usage
11
+ # constraint = PredicateConstraint.new(:self, ->(x) { x > 0 })
12
+ # constraint.satisfied?(1) # => true
13
+ # constraint.satisfied?(-1) # => false
14
+ #
15
+ # @example With custom violation description
16
+ # constraint = PredicateConstraint.new(:self, ->(x) { x > 0 }, violation_description: 'not greater than zero')
17
+ # constraint.satisfied?(-1) # => false
18
+ # constraint.short_violation_description # => "not greater than zero"
19
+ #
20
+ # @author {https://aaronmallen.me Aaron Allen}
21
+ # @since 0.1.0
22
+ class PredicateConstraint
23
+ type expected = ^(untyped value) -> bool
24
+
25
+ type options = { ?violation_description: String }
26
+
27
+ include Behavior[expected, untyped, options]
28
+
29
+ # Get a description of what the constraint expects.
30
+ #
31
+ # @note This constraint type does not provide a description as predicates are arbitrary.
32
+ #
33
+ # @return [String] an empty string
34
+ def short_description: ...
35
+
36
+ # Get a description of why the predicate validation failed.
37
+ #
38
+ # @return [String] the custom violation description if provided
39
+ def short_violation_description: ...
40
+
41
+ # Check if the value satisfies the predicate function.
42
+ #
43
+ # @return [Boolean] true if the predicate returns true
44
+ def satisfies_constraint?: ...
45
+
46
+ # Validate that the expectation is a Proc.
47
+ #
48
+ # @param expectation [Object] the expectation to validate
49
+ #
50
+ # @raise [ArgumentError] if the expectation is not a Proc
51
+ # @return [void]
52
+ def validate_expectation!: ...
53
+ end
54
+ end
55
+ end
56
+ end
@@ -64,6 +64,29 @@ module Domainic
64
64
 
65
65
  alias _List? _Array?
66
66
 
67
+ # Creates a BigDecimalType instance.
68
+ #
69
+ # @example
70
+ # type = _BigDecimal
71
+ # type.validate(BigDecimal('123.45')) # => true
72
+ #
73
+ # @param options [Hash] additional configuration options
74
+ #
75
+ # @return [Domainic::Type::BigDecimalType] the created type
76
+ def _BigDecimal: (**__todo__ options) -> BigDecimalType
77
+
78
+ # Creates a nilable BigDecimalType instance.
79
+ #
80
+ # @example
81
+ # type = _BigDecimal?
82
+ # type.validate(BigDecimal('123.45')) # => true
83
+ # type.validate(nil) # => true
84
+ #
85
+ # @param options [Hash] additional configuration options
86
+ #
87
+ # @return [Domainic::Type::UnionType] the created type (BigDecimal or NilClass)
88
+ def _BigDecimal?: (**__todo__ options) -> UnionType
89
+
67
90
  # Creates a Boolean type.
68
91
  #
69
92
  # Represents a union of TrueClass and FalseClass.
@@ -111,6 +134,28 @@ module Domainic
111
134
 
112
135
  alias _Cuid? _CUID?
113
136
 
137
+ # Creates a ComplexType instance.
138
+ #
139
+ # @example
140
+ # type = _Complex
141
+ # type.validate(Complex(1, 2)) # => true
142
+ #
143
+ # @param options [Hash] additional configuration options
144
+ #
145
+ # @return [Domainic::Type::ComplexType] the created type
146
+ def _Complex: (**__todo__ options) -> ComplexType
147
+
148
+ # Creates a nilable ComplexType instance.
149
+ #
150
+ # @example
151
+ # type = _Complex?
152
+ # type.validate(Complex(1, 2)) # => true
153
+ #
154
+ # @param options [Hash] additional configuration options
155
+ #
156
+ # @return [Domainic::Type::UnionType] the created type (Complex or NilClass)
157
+ def _Complex?: (**__todo__ options) -> UnionType
158
+
114
159
  # Creates a DateType instance.
115
160
  #
116
161
  # DateType restricts values to valid `Date` objects.
@@ -159,6 +204,34 @@ module Domainic
159
204
  # @return [Domainic::Type::UnionType] the created type (DateTimeType or NilClass)
160
205
  def _DateTime?: (**__todo__ options) -> UnionType
161
206
 
207
+ # Creates a DateTimeStringType instance.
208
+ #
209
+ # DateTimeStringType restricts values to valid date-time strings.
210
+ #
211
+ # @example
212
+ # type = _DateTimeString
213
+ # type.validate('2024-01-01T12:00:00Z') # => true
214
+ #
215
+ # @param options [Hash] additional configuration options
216
+ #
217
+ # @return [Domainic::Type::DateTimeStringType] the created type
218
+ def _DateTimeString: (**__todo__ options) -> DateTimeStringType
219
+
220
+ alias _DateString _DateTimeString
221
+
222
+ # Creates a nilable DateTimeStringType instance.
223
+ #
224
+ # @example
225
+ # _DateTimeString? === '2024-01-01T12:00:00Z' # => true
226
+ # _DateTimeString? === nil # => true
227
+ #
228
+ # @param options [Hash] additional configuration options
229
+ #
230
+ # @return [Domainic::Type::UnionType] the created type (DateTimeStringType or NilClass)
231
+ def _DateTimeString?: (**__todo__ options) -> UnionType
232
+
233
+ alias _DateString? _DateTimeString?
234
+
162
235
  # Creates a DuckType instance.
163
236
  #
164
237
  # DuckType allows specifying behavior based on method availability.
@@ -395,6 +468,74 @@ module Domainic
395
468
 
396
469
  alias _Nullable _Nilable
397
470
 
471
+ # Creates a RangeType instance.
472
+ #
473
+ # @example
474
+ # type = _Range
475
+ # type.validate(1..10) # => true
476
+ #
477
+ # @param options [Hash] additional configuration options
478
+ #
479
+ # @return [Domainic::Type::RangeType] the created type
480
+ def _Range: (**__todo__ options) -> RangeType
481
+
482
+ # Creates a nilable RangeType instance.
483
+ #
484
+ # @example
485
+ # type = _Range?
486
+ # type.validate(1..10) # => true
487
+ #
488
+ # @param options [Hash] additional configuration options
489
+ #
490
+ # @return [Domainic::Type::UnionType] the created type (Range or NilClass)
491
+ def _Range?: (**__todo__ options) -> UnionType
492
+
493
+ # Creates a RationalType instance.
494
+ #
495
+ # @example
496
+ # type = _Rational
497
+ # type.validate(Rational(1, 2)) # => true
498
+ #
499
+ # @param options [Hash] additional configuration options
500
+ #
501
+ # @return [Domainic::Type::RationalType] the created type
502
+ def _Rational: (**__todo__ options) -> RationalType
503
+
504
+ # Creates a nilable RationalType instance.
505
+ #
506
+ # @example
507
+ # type = _Rational?
508
+ # type.validate(Rational(1, 2)) # => true
509
+ # type.validate(nil) # => true
510
+ #
511
+ # @param options [Hash] additional configuration options
512
+ #
513
+ # @return [Domainic::Type::UnionType] the created type (Rational or NilClass)
514
+ def _Rational?: (**__todo__ options) -> UnionType
515
+
516
+ # Creates a SetType instance.
517
+ #
518
+ # @example
519
+ # type = _Set
520
+ # type.validate(Set[1, 2, 3]) # => true
521
+ #
522
+ # @param options [Hash] additional configuration options
523
+ #
524
+ # @return [Domainic::Type::SetType] the created type
525
+ def _Set: (**__todo__ options) -> SetType
526
+
527
+ # Creates a nilable SetType instance.
528
+ #
529
+ # @example
530
+ # type = _Set?
531
+ # type.validate(Set[1, 2, 3]) # => true
532
+ # type.validate(nil) # => true
533
+ #
534
+ # @param options [Hash] additional configuration options
535
+ #
536
+ # @return [Domainic::Type::UnionType] the created type (Set or NilClass)
537
+ def _Set?: (**__todo__ options) -> UnionType
538
+
398
539
  # Creates a StringType instance.
399
540
  #
400
541
  # @example
@@ -467,6 +608,30 @@ module Domainic
467
608
  # @return [Domainic::Type::UnionType] the created type (TimeType or NilClass)
468
609
  def _Time?: (**__todo__ options) -> UnionType
469
610
 
611
+ # Creates a TimestampType instance.
612
+ #
613
+ # TimestampType restricts values to valid timestamps.
614
+ #
615
+ # @example
616
+ # type = _Timestamp
617
+ # type.validate(1640995200) # => true
618
+ #
619
+ # @param options [Hash] additional configuration options
620
+ #
621
+ # @return [Domainic::Type::TimestampType] the created type
622
+ def _Timestamp: (**__todo__ options) -> TimestampType
623
+
624
+ # Creates a nilable TimestampType instance.
625
+ #
626
+ # @example
627
+ # _Timestamp? === 1640995200 # => true
628
+ # _Timestamp? === nil # => true
629
+ #
630
+ # @param options [Hash] additional configuration options
631
+ #
632
+ # @return [Domainic::Type::UnionType] the created type (TimestampType or NilClass)
633
+ def _Timestamp?: (**__todo__ options) -> UnionType
634
+
470
635
  # Creates a URIType instance.
471
636
  #
472
637
  # URIType restricts values to valid URIs.
@@ -0,0 +1,96 @@
1
+ module Domainic
2
+ module Type
3
+ # A type for validating and constraining `Complex` numbers.
4
+ #
5
+ # This type extends `NumericBehavior` to provide a fluent interface for numeric-specific validations such as
6
+ # polarity and divisibility checks.
7
+ #
8
+ # @example Validating a `Complex` value
9
+ # type = Domainic::Type::ComplexType.new
10
+ # type.validate!(Complex(3, 4)) # => true
11
+ #
12
+ # @example Enforcing constraints
13
+ # type = Domainic::Type::ComplexType.new
14
+ # type.being_positive.validate!(Complex(42, 0)) # => raises TypeError
15
+ #
16
+ # @author {https://aaronmallen.me Aaron Allen}
17
+ # @since 0.1.0
18
+ class ComplexType
19
+ extend Behavior::ClassMethods
20
+
21
+ include Behavior
22
+
23
+ include Behavior::NumericBehavior
24
+
25
+ # Constrain the Complex real to be divisible by a given divisor.
26
+ #
27
+ # @param arguments [Array<Numeric>] a list of arguments, typically one divisor
28
+ # @param options [Hash] additional options such as tolerance for floating-point checks
29
+ # @option options [Numeric] :divisor the divisor to check for divisibility
30
+ # @option options [Numeric] :tolerance the tolerance for floating-point checks
31
+ #
32
+ # @return [self] the current instance for chaining
33
+ def being_divisible_by: (*Numeric arguments, ?divisor: Numeric, ?tolerance: Numeric) -> Behavior
34
+
35
+ alias being_multiple_of being_divisible_by
36
+
37
+ alias divisible_by being_divisible_by
38
+
39
+ alias multiple_of being_divisible_by
40
+
41
+ # Constrain the Complex real to be even.
42
+ #
43
+ # @return [self] the current instance for chaining
44
+ def being_even: () -> Behavior
45
+
46
+ alias even being_even
47
+
48
+ alias not_being_odd being_even
49
+
50
+ # Constrain the Complex real to be negative.
51
+ #
52
+ # @return [self] the current instance for chaining
53
+ def being_negative: () -> Behavior
54
+
55
+ alias negative being_negative
56
+
57
+ alias not_being_positive being_negative
58
+
59
+ # Constrain the Complex real value to be odd.
60
+ #
61
+ # @return [self] the current instance for chaining
62
+ def being_odd: () -> Behavior
63
+
64
+ alias odd being_odd
65
+
66
+ alias not_being_even being_odd
67
+
68
+ # Constrain the Complex real to be positive.
69
+ #
70
+ # @return [self] the current instance for chaining
71
+ def being_positive: () -> Behavior
72
+
73
+ alias positive being_positive
74
+
75
+ alias not_being_negative being_positive
76
+
77
+ # Constrain the Complex real to not be divisible by a specific divisor.
78
+ #
79
+ # @note the divisor MUST be provided as an argument or in the options Hash.
80
+ #
81
+ # @param arguments [Array<Numeric>] a list of arguments, typically one divisor
82
+ # @param options [Hash] additional options such as tolerance for floating-point checks
83
+ # @option options [Numeric] :divisor the divisor to check for divisibility
84
+ # @option options [Numeric] :tolerance the tolerance for floating-point checks
85
+ #
86
+ # @return [self] the current instance for chaining
87
+ def not_being_divisible_by: (*Numeric arguments, ?divisor: Numeric, ?tolerance: Numeric) -> Behavior
88
+
89
+ alias not_being_multiple_of not_being_divisible_by
90
+
91
+ alias not_divisible_by not_being_divisible_by
92
+
93
+ alias not_multiple_of not_being_divisible_by
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,41 @@
1
+ module Domainic
2
+ module Type
3
+ # A type for validating `Range` objects with comprehensive constraints.
4
+ #
5
+ # This class allows flexible validation of ranges, supporting type checks,
6
+ # inclusion/exclusion of values, and range-specific behaviors such as bounds validation.
7
+ # It integrates with `EnumerableBehavior` for enumerable-style validations
8
+ # (e.g., size constraints, element presence).
9
+ #
10
+ # Key features:
11
+ # - Ensures the value is a `Range`.
12
+ # - Supports constraints for range boundaries (`begin` and `end`).
13
+ # - Provides validations for inclusion and exclusion of values.
14
+ # - Leverages `EnumerableBehavior` for size and collection-style constraints.
15
+ #
16
+ # @example Basic usage
17
+ # type = RangeType.new
18
+ # type.having_bounds(1, 10) # Validates range bounds (inclusive or exclusive).
19
+ # type.containing(5) # Ensures value is within the range.
20
+ # type.not_containing(15) # Ensures value is not within the range.
21
+ #
22
+ # @example Integration with EnumerableBehavior
23
+ # type = RangeType.new
24
+ # type.having_size(10) # Validates size (total elements in the range).
25
+ # type.containing_exactly(3, 7) # Validates specific values within the range.
26
+ #
27
+ # @example Flexible boundaries
28
+ # type = RangeType.new
29
+ # type.having_bounds(1, 10, exclusive: true) # Upper and lower bounds are exclusive.
30
+ #
31
+ # @author {https://aaronmallen.me Aaron Allen}
32
+ # @since 0.1.0
33
+ class RangeType
34
+ extend Behavior::ClassMethods
35
+
36
+ include Behavior
37
+
38
+ include Behavior::EnumerableBehavior
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ module Domainic
2
+ module Type
3
+ # A type for validating Rational numbers.
4
+ #
5
+ # This type ensures values are of type `Rational` and supports a range of
6
+ # constraints for numerical validation, such as positivity, negativity,
7
+ # and divisibility. It integrates with `NumericBehavior` to provide a
8
+ # consistent and fluent interface for numeric constraints.
9
+ #
10
+ # @example Validating a positive Rational number
11
+ # type = Domainic::Type::RationalType.new
12
+ # type.being_positive.validate!(Rational(3, 4)) # => true
13
+ #
14
+ # @example Validating divisibility
15
+ # type = Domainic::Type::RationalType.new
16
+ # type.being_divisible_by(1).validate!(Rational(3, 1)) # => true
17
+ #
18
+ # @example Using constraints with chaining
19
+ # type = Domainic::Type::RationalType.new
20
+ # type.being_greater_than(0).being_less_than(1).validate!(Rational(1, 2)) # => true
21
+ #
22
+ # @author {https://aaronmallen.me Aaron Allen}
23
+ # @since 0.1.0
24
+ class RationalType
25
+ extend Behavior::ClassMethods
26
+
27
+ include Behavior
28
+
29
+ include Behavior::NumericBehavior
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ module Domainic
2
+ module Type
3
+ # A type for validating and constraining `BigDecimal` objects.
4
+ #
5
+ # This type extends `NumericBehavior` to provide a fluent interface for numeric-specific validations such as being
6
+ # positive, being within a range, or satisfying divisibility rules.
7
+ #
8
+ # @example Validating a `BigDecimal` value
9
+ # type = Domainic::Type::BigDecimalType.new
10
+ # type.validate!(BigDecimal('3.14')) # => true
11
+ #
12
+ # @example Enforcing constraints
13
+ # type = Domainic::Type::BigDecimalType.new
14
+ # type.being_positive.validate!(BigDecimal('42')) # => true
15
+ # type.being_positive.validate!(BigDecimal('-42')) # raises TypeError
16
+ #
17
+ # @author {https://aaronmallen.me Aaron Allen}
18
+ # @since 0.1.0
19
+ class BigDecimalType
20
+ extend Behavior::ClassMethods
21
+
22
+ include Behavior
23
+
24
+ include Behavior::NumericBehavior
25
+ end
26
+ end
27
+ end