domainic-type 0.1.0.alpha.2.1.0 → 0.1.0.alpha.3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/LICENSE +1 -1
  4. data/README.md +28 -4
  5. data/lib/domainic/type/accessors.rb +41 -0
  6. data/lib/domainic/type/behavior/enumerable_behavior.rb +262 -0
  7. data/lib/domainic/type/behavior/numeric_behavior.rb +340 -0
  8. data/lib/domainic/type/behavior/sizable_behavior.rb +246 -0
  9. data/lib/domainic/type/behavior/string_behavior.rb +379 -0
  10. data/lib/domainic/type/behavior.rb +239 -0
  11. data/lib/domainic/type/config/registry.yml +101 -0
  12. data/lib/domainic/type/constraint/behavior.rb +342 -0
  13. data/lib/domainic/type/constraint/constraints/all_constraint.rb +81 -0
  14. data/lib/domainic/type/constraint/constraints/and_constraint.rb +105 -0
  15. data/lib/domainic/type/constraint/constraints/any_constraint.rb +83 -0
  16. data/lib/domainic/type/constraint/constraints/case_constraint.rb +104 -0
  17. data/lib/domainic/type/constraint/constraints/character_set_constraint.rb +111 -0
  18. data/lib/domainic/type/constraint/constraints/divisibility_constraint.rb +126 -0
  19. data/lib/domainic/type/constraint/constraints/emptiness_constraint.rb +69 -0
  20. data/lib/domainic/type/constraint/constraints/equality_constraint.rb +75 -0
  21. data/lib/domainic/type/constraint/constraints/finiteness_constraint.rb +123 -0
  22. data/lib/domainic/type/constraint/constraints/inclusion_constraint.rb +74 -0
  23. data/lib/domainic/type/constraint/constraints/match_pattern_constraint.rb +87 -0
  24. data/lib/domainic/type/constraint/constraints/method_presence_constraint.rb +72 -0
  25. data/lib/domainic/type/constraint/constraints/none_constraint.rb +83 -0
  26. data/lib/domainic/type/constraint/constraints/nor_constraint.rb +105 -0
  27. data/lib/domainic/type/constraint/constraints/not_constraint.rb +76 -0
  28. data/lib/domainic/type/constraint/constraints/or_constraint.rb +106 -0
  29. data/lib/domainic/type/constraint/constraints/ordering_constraint.rb +75 -0
  30. data/lib/domainic/type/constraint/constraints/parity_constraint.rb +102 -0
  31. data/lib/domainic/type/constraint/constraints/polarity_constraint.rb +147 -0
  32. data/lib/domainic/type/constraint/constraints/range_constraint.rb +135 -0
  33. data/lib/domainic/type/constraint/constraints/type_constraint.rb +110 -0
  34. data/lib/domainic/type/constraint/constraints/uniqueness_constraint.rb +69 -0
  35. data/lib/domainic/type/constraint/resolver.rb +172 -0
  36. data/lib/domainic/type/constraint/set.rb +266 -0
  37. data/lib/domainic/type/definitions.rb +364 -0
  38. data/lib/domainic/type/types/core/array_type.rb +48 -0
  39. data/lib/domainic/type/types/core/float_type.rb +39 -0
  40. data/lib/domainic/type/types/core/hash_type.rb +143 -0
  41. data/lib/domainic/type/types/core/integer_type.rb +38 -0
  42. data/lib/domainic/type/types/core/string_type.rb +51 -0
  43. data/lib/domainic/type/types/core/symbol_type.rb +51 -0
  44. data/lib/domainic/type/types/specification/anything_type.rb +22 -0
  45. data/lib/domainic/type/types/specification/duck_type.rb +55 -0
  46. data/lib/domainic/type/types/specification/enum_type.rb +26 -0
  47. data/lib/domainic/type/types/specification/union_type.rb +26 -0
  48. data/lib/domainic/type/types/specification/void_type.rb +12 -0
  49. data/lib/domainic/type.rb +7 -0
  50. data/lib/domainic-type.rb +3 -0
  51. data/sig/domainic/type/accessors.rbs +22 -0
  52. data/sig/domainic/type/behavior/enumerable_behavior.rbs +238 -0
  53. data/sig/domainic/type/behavior/numeric_behavior.rbs +299 -0
  54. data/sig/domainic/type/behavior/sizable_behavior.rbs +218 -0
  55. data/sig/domainic/type/behavior/string_behavior.rbs +315 -0
  56. data/sig/domainic/type/behavior.rbs +153 -0
  57. data/sig/domainic/type/constraint/behavior.rbs +258 -0
  58. data/sig/domainic/type/constraint/constraints/all_constraint.rbs +55 -0
  59. data/sig/domainic/type/constraint/constraints/and_constraint.rbs +72 -0
  60. data/sig/domainic/type/constraint/constraints/any_constraint.rbs +57 -0
  61. data/sig/domainic/type/constraint/constraints/case_constraint.rbs +73 -0
  62. data/sig/domainic/type/constraint/constraints/character_set_constraint.rbs +82 -0
  63. data/sig/domainic/type/constraint/constraints/divisibility_constraint.rbs +91 -0
  64. data/sig/domainic/type/constraint/constraints/emptiness_constraint.rbs +54 -0
  65. data/sig/domainic/type/constraint/constraints/equality_constraint.rbs +60 -0
  66. data/sig/domainic/type/constraint/constraints/finiteness_constraint.rbs +82 -0
  67. data/sig/domainic/type/constraint/constraints/inclusion_constraint.rbs +59 -0
  68. data/sig/domainic/type/constraint/constraints/match_pattern_constraint.rbs +66 -0
  69. data/sig/domainic/type/constraint/constraints/method_presence_constraint.rbs +51 -0
  70. data/sig/domainic/type/constraint/constraints/none_constraint.rbs +57 -0
  71. data/sig/domainic/type/constraint/constraints/nor_constraint.rbs +72 -0
  72. data/sig/domainic/type/constraint/constraints/not_constraint.rbs +56 -0
  73. data/sig/domainic/type/constraint/constraints/or_constraint.rbs +74 -0
  74. data/sig/domainic/type/constraint/constraints/ordering_constraint.rbs +60 -0
  75. data/sig/domainic/type/constraint/constraints/parity_constraint.rbs +71 -0
  76. data/sig/domainic/type/constraint/constraints/polarity_constraint.rbs +101 -0
  77. data/sig/domainic/type/constraint/constraints/range_constraint.rbs +88 -0
  78. data/sig/domainic/type/constraint/constraints/type_constraint.rbs +86 -0
  79. data/sig/domainic/type/constraint/constraints/uniqueness_constraint.rbs +54 -0
  80. data/sig/domainic/type/constraint/resolver.rbs +117 -0
  81. data/sig/domainic/type/constraint/set.rbs +159 -0
  82. data/sig/domainic/type/definitions.rbs +304 -0
  83. data/sig/domainic/type/types/core/array_type.rbs +42 -0
  84. data/sig/domainic/type/types/core/float_type.rbs +33 -0
  85. data/sig/domainic/type/types/core/hash_type.rbs +107 -0
  86. data/sig/domainic/type/types/core/integer_type.rbs +32 -0
  87. data/sig/domainic/type/types/core/string_type.rbs +45 -0
  88. data/sig/domainic/type/types/core/symbol_type.rbs +45 -0
  89. data/sig/domainic/type/types/specification/anything_type.rbs +14 -0
  90. data/sig/domainic/type/types/specification/duck_type.rbs +41 -0
  91. data/sig/domainic/type/types/specification/enum_type.rbs +14 -0
  92. data/sig/domainic/type/types/specification/union_type.rbs +14 -0
  93. data/sig/domainic/type/types/specification/void_type.rbs +8 -0
  94. data/sig/domainic/type.rbs +5 -0
  95. data/sig/domainic-type.rbs +1 -0
  96. data/sig/manifest.yaml +2 -0
  97. metadata +108 -71
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18b90d10d73335f1c1c10ab77a9cf2caff65fb40b898a8dc84cd782430373919
4
- data.tar.gz: d943105b0d45b9042ff9352286ef4f716e3d38c516820476932acd4922473dd6
3
+ metadata.gz: f21061b605848ed1ca2638a2819c3ad56949df1690a09d7f703d52c62c8d8720
4
+ data.tar.gz: 35b51a1be388dd8a0ef55f58b0bb8e7190d0c1666984bfe340dfef597fe80519
5
5
  SHA512:
6
- metadata.gz: d776067c6a20cce90560648dd68354f0e4ce8daf737246f44cb304c32e6d19d4dff089808c8e142f6669e5a6ea2cf72abed66569d0bbc76140c8ebe95ebad9a5
7
- data.tar.gz: ca50e98a6c550da3f57768567cd868bce69af7cf94e609f6ec8600b88a266f717aa468c61e502f763256d8f6a2bac637301175f8b1c386195c0e3ff9b1bc29ef
6
+ metadata.gz: 30d67d75036848bae0ad52b09c276af2e560f2227f1bee01499893b4dd43fcdd6deefd444e4839bd92cde586674671634912cc203e4ce7eb2bc3d71ee77e5cc3
7
+ data.tar.gz: 61e0e722906fe09d3df96e63412523b51c62dc4df9a7190f7127e18fa26c68215f44e6626d9368e140d103f6284866b7ded63b94faceafc66feaa4096b2f6624
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog], and this project adheres to [Break Versioning].
6
+
7
+ ## [Unreleased]
8
+
9
+ [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
10
+ [Break Versioning]: https://www.taoensso.com/break-versioning
11
+
12
+ <!-- versions -->
13
+
14
+ [Unreleased]: https://github.com/domainic/domainic/tree/main/domainic-type
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 Aaron Allen
3
+ Copyright (c) Aaron Allen
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,7 +1,31 @@
1
- # Domainic
1
+ # Domainic::Type
2
2
 
3
- Tooling and utilities for domain-driven design in Ruby.
3
+ [![Domainic::Type Version](https://img.shields.io/gem/v/domainic-type?style=for-the-badge&logo=rubygems&logoColor=white&logoSize=auto&label=Gem%20Version)](https://rubygems.org/gems/domainic-type)
4
+ [![Domainic::Type License](https://img.shields.io/github/license/domainic/domainic?logo=opensourceinitiative&logoColor=white&logoSize=auto&style=for-the-badge)](./LICENSE)
5
+ [![Domainic::Type Open Issues](https://img.shields.io/github/issues-search/domainic/domainic?label=open%20issues&logo=github&logoSize=auto&query=is%3Aopen%20label%3Adomainic-type&color=red&style=for-the-badge)](https://github.com/domainic/domainic/issues?q=state%3Aopen%20label%3Adomainic-type%20)
4
6
 
5
- ## WARNING
7
+ > [!IMPORTANT]
8
+ > We're running an experiment with Domainic::Type! Help us explore flexible type validation in Ruby by trying our
9
+ > [alpha release](../docs/experiments/domainic-type-alpha-3/README.md). Your feedback is invaluable for shaping
10
+ > the future of domain-driven design in Ruby.
6
11
 
7
- All gems in this package are in early development and are not yet ready for production use.
12
+ A flexible type validation system for Ruby, offering composable, readable type constraints with elegant error messages.
13
+
14
+ Stop wrestling with complex type validations and unclear error messages. Domainic::Type brings type validation to Ruby
15
+ that is both powerful and delightful to use. Build composable type constraints with crystal-clear error messages that
16
+ actually tell you what went wrong. From simple type checks to complex collection validations, make your types work for
17
+ you, not against you!
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'domainic-type', '~> 0.1.0.alpha.3'
25
+ ```
26
+
27
+ Or install it yourself as:
28
+
29
+ ```bash
30
+ gem install domainic-type --pre
31
+ ```
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Domainic
4
+ module Type
5
+ # @rbs!
6
+ # type accessor = :abs | :begin | :chars | :class | :count | :end | :entries | :first | :keys | :last | :length |
7
+ # :self | :size | :values
8
+
9
+ # A list of valid access methods that can be used to retrieve values for constraint validation.
10
+ # These methods represent common Ruby interfaces for accessing collection sizes, ranges, and values.
11
+ #
12
+ # - :abs - For absolute values
13
+ # - :begin, :end - For Range-like objects
14
+ # - :class - For type checking
15
+ # - :count, :length, :size - For measuring collections
16
+ # - :entries, :chars - For accessing sequence elements
17
+ # - :first, :last - For accessing sequence endpoints
18
+ # - :keys, :values - For Hash-like objects
19
+ # - :self - For operating directly on the value
20
+ #
21
+ # @author {https://aaronmallen.me Aaron Allen}
22
+ # @since 0.1.0
23
+ # @return [Array<Symbol>]
24
+ ACCESSORS = %i[
25
+ class
26
+ self
27
+ entries
28
+ chars
29
+ abs
30
+ count
31
+ size
32
+ length
33
+ first
34
+ last
35
+ begin
36
+ end
37
+ keys
38
+ values
39
+ ].freeze #: Array[accessor]
40
+ end
41
+ end
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'domainic/type/behavior'
4
+ require 'domainic/type/behavior/sizable_behavior'
5
+
6
+ module Domainic
7
+ module Type
8
+ module Behavior
9
+ # A module providing enumerable-specific validation behaviors for types.
10
+ #
11
+ # This module extends the base Type::Behavior with methods specifically designed for validating enumerable
12
+ # collections. It provides a fluent interface for common enumerable validations such as uniqueness, emptiness,
13
+ # ordering, and size constraints.
14
+ #
15
+ # @example Basic usage
16
+ # class ArrayType
17
+ # include Domainic::Type::Behavior::EnumerableBehavior
18
+ #
19
+ # def initialize
20
+ # super
21
+ # being_empty # validates array is empty
22
+ # having_minimum_count(5) # validates at least 5 elements
23
+ # containing(1, 2, 3) # validates specific elements
24
+ # end
25
+ # end
26
+ #
27
+ # @example Combining constraints
28
+ # class OrderedArrayType
29
+ # include Domainic::Type::Behavior::EnumerableBehavior
30
+ #
31
+ # def initialize
32
+ # super
33
+ # being_ordered
34
+ # being_populated
35
+ # having_maximum_count(10)
36
+ # end
37
+ # end
38
+ #
39
+ # @author {https://aaronmallen.me Aaron Allen}
40
+ # @since 0.1.0
41
+ module EnumerableBehavior
42
+ include SizableBehavior
43
+
44
+ def being_distinct
45
+ # @type self: Object & Behavior
46
+ constrain :entries, :uniqueness, description: 'being'
47
+ end
48
+ alias being_unique being_distinct
49
+ alias distinct being_distinct
50
+ alias unique being_distinct
51
+
52
+ # Validate that the enumerable contains duplicate elements.
53
+ #
54
+ # Creates an inverse uniqueness constraint that ensures the collection has at least one duplicate element.
55
+ #
56
+ # @example
57
+ # type.being_duplicative
58
+ # type.validate([1, 1, 2]) # => true
59
+ # type.validate([1, 2, 3]) # => false
60
+ #
61
+ # @return [self] self for method chaining
62
+ # @rbs ()-> Behavior
63
+ def being_duplicative
64
+ # @type self: Object & Behavior
65
+ unique = @constraints.prepare :self, :uniqueness
66
+ constrain :entries, :not, unique, concerning: :uniqueness, description: 'being'
67
+ end
68
+ alias being_redundant being_duplicative
69
+ alias being_repetitive being_duplicative
70
+ alias duplicative being_duplicative
71
+ alias redundant being_duplicative
72
+ alias repetitive being_duplicative
73
+
74
+ # Validate that the enumerable is empty.
75
+ #
76
+ # Creates a constraint that ensures the collection has no elements.
77
+ #
78
+ # @example
79
+ # type.being_empty
80
+ # type.validate([]) # => true
81
+ # type.validate([1]) # => false
82
+ #
83
+ # @return [self] self for method chaining
84
+ # @rbs ()-> Behavior
85
+ def being_empty
86
+ # @type self: Object & Behavior
87
+ constrain :entries, :emptiness, description: 'being'
88
+ end
89
+ alias being_vacant being_empty
90
+ alias empty being_empty
91
+ alias vacant being_empty
92
+
93
+ # Validate that the enumerable contains elements.
94
+ #
95
+ # Creates an inverse emptiness constraint that ensures the collection has at least one element.
96
+ #
97
+ # @example
98
+ # type.being_populated
99
+ # type.validate([1]) # => true
100
+ # type.validate([]) # => false
101
+ #
102
+ # @return [self] self for method chaining
103
+ # @rbs ()-> Behavior
104
+ def being_populated
105
+ # @type self: Object & Behavior
106
+ empty = @constraints.prepare :self, :emptiness
107
+ constrain :entries, :not, empty, concerning: :emptiness, description: 'being'
108
+ end
109
+ alias being_inhabited being_populated
110
+ alias being_occupied being_populated
111
+ alias populated being_populated
112
+ alias inhabited being_populated
113
+ alias occupied being_populated
114
+
115
+ # Validate that the enumerable elements are in sorted order.
116
+ #
117
+ # Creates a constraint that ensures the collection's elements are in ascending order based on their natural
118
+ # comparison methods.
119
+ #
120
+ # @example
121
+ # type.being_ordered
122
+ # type.validate([1, 2, 3]) # => true
123
+ # type.validate([3, 1, 2]) # => false
124
+ #
125
+ # @return [self] self for method chaining
126
+ # @rbs ()-> Behavior
127
+ def being_sorted
128
+ # @type self: Object & Behavior
129
+ constrain :entries, :ordering, description: 'being'
130
+ end
131
+ alias being_aranged being_sorted
132
+ alias being_ordered being_sorted
133
+ alias being_sequential being_sorted
134
+ alias aranged being_sorted
135
+ alias ordered being_sorted
136
+ alias sorted being_sorted
137
+ alias sequential being_sorted
138
+
139
+ # Validate that the enumerable elements are not in sorted order.
140
+ #
141
+ # Creates an inverse ordering constraint that ensures the collection's elements are not in ascending order.
142
+ #
143
+ # @example
144
+ # type.being_unordered
145
+ # type.validate([3, 1, 2]) # => true
146
+ # type.validate([1, 2, 3]) # => false
147
+ #
148
+ # @return [self] self for method chaining
149
+ # @rbs ()-> Behavior
150
+ def being_unsorted
151
+ # @type self: Object & Behavior
152
+ ordered = @constraints.prepare :self, :ordering
153
+ constrain :entries, :not, ordered, concerning: :ordering, description: 'being'
154
+ end
155
+ alias being_disordered being_unsorted
156
+ alias being_unordered being_unsorted
157
+ alias disordered being_unsorted
158
+ alias unsorted being_unsorted
159
+ alias unordered being_unsorted
160
+
161
+ # Validate that the enumerable contains specific entries.
162
+ #
163
+ # Creates a series of inclusion constraints ensuring the collection contains all specified elements.
164
+ #
165
+ # @example
166
+ # type.containing(1, 2)
167
+ # type.validate([1, 2, 3]) # => true
168
+ # type.validate([1, 3]) # => false
169
+ #
170
+ # @param entries [Array<Object>] the elements that must be present
171
+ # @return [self] self for method chaining
172
+ # @rbs (*untyped entries)-> Behavior
173
+ def containing(*entries)
174
+ # @type self: Object & Behavior
175
+ including = entries.map do |entry|
176
+ @constraints.prepare :entries, :inclusion, entry
177
+ end
178
+ constrain :entries, :and, including, concerning: :entry_inclusion
179
+ end
180
+ alias including containing
181
+
182
+ # Validate that the enumerable contains a specific last entry.
183
+ #
184
+ # Creates an equality constraint on the collection's last entry ensuring it is equal to the specified value.
185
+ #
186
+ # @example
187
+ # type.having_last_entry(3)
188
+ # type.validate([1, 2, 3]) # => true
189
+ # type.validate([1, 3, 2]) # => false
190
+ #
191
+ # @param literal [Object] the value that must be the last entry
192
+ # @return [self] self for method chaining
193
+ # @rbs (untyped literal)-> Behavior
194
+ def ending_with(literal)
195
+ # @type self: Object & Behavior
196
+ constrain :last, :equality, literal, concerning: :last_entry_value, description: 'with last entry'
197
+ end
198
+ alias closing_with ending_with
199
+ alias finishing_with ending_with
200
+
201
+ # Validate that the enumerable does not contain specific entries.
202
+ #
203
+ # Creates a series of exclusion constraints ensuring the collection does not contain any of the specified
204
+ # elements.
205
+ #
206
+ # @example
207
+ # type.excluding(1, 2)
208
+ # type.validate([3, 4, 5]) # => true
209
+ # type.validate([1, 2, 3]) # => false
210
+ #
211
+ # @param entries [Array<Object>] the elements that must not be present
212
+ # @return [self] self for method chaining
213
+ # @rbs (*untyped entries)-> Behavior
214
+ def excluding(*entries)
215
+ # @type self: Object & Behavior
216
+ including = entries.map do |entry|
217
+ @constraints.prepare :entries, :inclusion, entry
218
+ end
219
+ constrain :entries, :nor, including, concerning: :entry_exclusion
220
+ end
221
+ alias omitting excluding
222
+
223
+ # Validate that the enumerable contains elements of a specific type.
224
+ #
225
+ # Creates a type constraint on the collection's elements ensuring they are all of the specified type.
226
+ #
227
+ # @example
228
+ # type.of(String)
229
+ # type.validate(['a', 'b', 'c']) # => true
230
+ # type.validate(['a', 1, 'c']) # => false
231
+ #
232
+ # @param type [Class, Module, Behavior] the type that all elements must be
233
+ # @return [self] self for method chaining
234
+ # @rbs (Class | Module | Behavior type)-> Behavior
235
+ def of(type)
236
+ # @type self: Object & Behavior
237
+ type = @constraints.prepare :self, :type, type
238
+ constrain :entries, :all, type, concerning: :entry_type
239
+ end
240
+
241
+ # Validate that the enumerable contains a specific first entry.
242
+ #
243
+ # Creates an equality constraint on the collection's first entry ensuring it is equal to the specified value.
244
+ #
245
+ # @example
246
+ # type.having_first_entry(1)
247
+ # type.validate([1, 2, 3]) # => true
248
+ # type.validate([2, 3, 1]) # => false
249
+ #
250
+ # @param literal [Object] the value that must be the first entry
251
+ # @return [self] self for method chaining
252
+ # @rbs (untyped literal)-> Behavior
253
+ def starting_with(literal)
254
+ # @type self: Object & Behavior
255
+ constrain :first, :equality, literal, concerning: :first_entry_value, description: 'with first entry'
256
+ end
257
+ alias begining_with starting_with
258
+ alias leading_with starting_with
259
+ end
260
+ end
261
+ end
262
+ end