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

Sign up to get free protection for your applications and to get access to all the features.
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: 7e4f8e0bb4883a197a5ed2f87b53a6dbc60ae70a41f48f6369881e8a5a5249b0
4
+ data.tar.gz: b512246f56da3aa04d9b068c080324a7ab507f96b6749a6ed8701a8bc8615901
5
5
  SHA512:
6
- metadata.gz: d776067c6a20cce90560648dd68354f0e4ce8daf737246f44cb304c32e6d19d4dff089808c8e142f6669e5a6ea2cf72abed66569d0bbc76140c8ebe95ebad9a5
7
- data.tar.gz: ca50e98a6c550da3f57768567cd868bce69af7cf94e609f6ec8600b88a266f717aa468c61e502f763256d8f6a2bac637301175f8b1c386195c0e3ff9b1bc29ef
6
+ metadata.gz: 5d807fab460c97af3e8fc50acb0f834ae8bc881d56507c668908d1baaa3b983516280a79c361fe30da893e38aeffa04561f265605c9c33633c64578a4461550f
7
+ data.tar.gz: c243d9fc6559e8d3be625c7db153d9964d2e36bcda90a33ba2e75f0cb8e69269cfa53542dddabf8fa7a4671da676bde29db7ae4893c5659d1702f38ff5a8f50f
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