literal 0.2.0 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -156
- data/lib/literal/data_structure.rb +24 -15
- data/lib/literal/enum.rb +20 -15
- data/lib/literal/errors/type_error.rb +76 -3
- data/lib/literal/properties/data_schema.rb +3 -4
- data/lib/literal/properties/schema.rb +57 -7
- data/lib/literal/properties.rb +18 -4
- data/lib/literal/property.rb +47 -20
- data/lib/literal/rails/enum_serializer.rb +20 -0
- data/lib/literal/rails/enum_type.rb +41 -0
- data/lib/literal/rails/patches/active_record.rb +31 -0
- data/lib/literal/rails.rb +9 -0
- data/lib/literal/railtie.rb +13 -0
- data/lib/literal/types/array_type.rb +13 -1
- data/lib/literal/types/boolean_type.rb +0 -6
- data/lib/literal/types/constraint_type.rb +32 -3
- data/lib/literal/types/enumerable_type.rb +1 -1
- data/lib/literal/types/float_type.rb +1 -1
- data/lib/literal/types/hash_type.rb +7 -1
- data/lib/literal/types/integer_type.rb +1 -1
- data/lib/literal/types/json_data_type.rb +3 -1
- data/lib/literal/types/map_type.rb +15 -1
- data/lib/literal/types/set_type.rb +7 -1
- data/lib/literal/types/string_type.rb +1 -1
- data/lib/literal/types/symbol_type.rb +1 -1
- data/lib/literal/types/tuple_type.rb +11 -1
- data/lib/literal/types/union_type.rb +8 -2
- data/lib/literal/types.rb +202 -32
- data/lib/literal/version.rb +1 -1
- data/lib/literal.rb +8 -3
- metadata +11 -7
- data/lib/literal.test.rb +0 -5
data/lib/literal/types.rb
CHANGED
@@ -33,68 +33,144 @@ module Literal::Types
|
|
33
33
|
autoload :UnionType, "literal/types/union_type"
|
34
34
|
autoload :VoidType, "literal/types/void_type"
|
35
35
|
|
36
|
-
|
36
|
+
NilableBooleanType = NilableType.new(BooleanType)
|
37
|
+
NilableCallableType = NilableType.new(CallableType)
|
38
|
+
NilableJSONDataType = NilableType.new(JSONDataType)
|
39
|
+
NilableLambdaType = NilableType.new(LambdaType)
|
40
|
+
NilableProcableType = NilableType.new(ProcableType)
|
41
|
+
|
42
|
+
# Matches any value except `nil`. Use `_Any?` or `_Unit` to match any value including `nil`.
|
37
43
|
def _Any
|
38
|
-
|
44
|
+
AnyType
|
45
|
+
end
|
46
|
+
|
47
|
+
def _Any?
|
48
|
+
VoidType
|
39
49
|
end
|
40
50
|
|
41
51
|
# Matches if the value is an `Array` and all the elements match the given type.
|
42
52
|
def _Array(...)
|
43
|
-
|
53
|
+
ArrayType.new(...)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Nilable version of `_Array`
|
57
|
+
def _Array?(...)
|
58
|
+
NilableType.new(
|
59
|
+
ArrayType.new(...),
|
60
|
+
)
|
44
61
|
end
|
45
62
|
|
46
63
|
# Matches if the value is `true` or `false`.
|
47
64
|
def _Boolean
|
48
|
-
|
65
|
+
BooleanType
|
66
|
+
end
|
67
|
+
|
68
|
+
# Nilable version of `_Boolean`
|
69
|
+
def _Boolean?
|
70
|
+
NilableBooleanType
|
49
71
|
end
|
50
72
|
|
51
73
|
# Matches if the value responds to `#call`.
|
52
74
|
def _Callable
|
53
|
-
|
75
|
+
CallableType
|
76
|
+
end
|
77
|
+
|
78
|
+
# Nilabl version of `_Callable`
|
79
|
+
def _Callable?
|
80
|
+
NilableCallableType
|
54
81
|
end
|
55
82
|
|
56
83
|
# Matches if the value either the given class or a subclass of it.
|
57
84
|
def _Class(...)
|
58
|
-
|
85
|
+
ClassType.new(...)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Nilable version of `_Class`
|
89
|
+
def _Class?(...)
|
90
|
+
NilableType.new(
|
91
|
+
ClassType.new(...),
|
92
|
+
)
|
59
93
|
end
|
60
94
|
|
61
95
|
# Similar to `_Intersection`, but allows you to specify attribute constraints as keyword arguments.
|
62
96
|
# @example
|
63
97
|
# _Constraint(Array, size: 1..3)
|
64
98
|
def _Constraint(...)
|
65
|
-
|
99
|
+
ConstraintType.new(...)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Nilable version of `_Constraint`
|
103
|
+
def _Constraint?(...)
|
104
|
+
NilableType.new(
|
105
|
+
ConstraintType.new(...),
|
106
|
+
)
|
66
107
|
end
|
67
108
|
|
68
109
|
# Matches if the value is a descendant of the given class.
|
69
110
|
def _Descendant(...)
|
70
|
-
|
111
|
+
DescendantType.new(...)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Nilable version of `_Descendant`
|
115
|
+
def _Descendant?(...)
|
116
|
+
NilableType.new(
|
117
|
+
DescendantType.new(...),
|
118
|
+
)
|
71
119
|
end
|
72
120
|
|
73
121
|
# Matches if the value is an `Enumerable` and all its elements match the given type.
|
74
122
|
def _Enumerable(...)
|
75
|
-
|
123
|
+
EnumerableType.new(...)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Nilable version of `_Enumerable`
|
127
|
+
def _Enumerable?(...)
|
128
|
+
NilableType.new(
|
129
|
+
EnumerableType.new(...),
|
130
|
+
)
|
76
131
|
end
|
77
132
|
|
78
133
|
# Matches *"falsy"* values (`nil` and `false`).
|
79
134
|
def _Falsy
|
80
|
-
|
135
|
+
FalsyType
|
81
136
|
end
|
82
137
|
|
83
138
|
# Matches if the value is a `Float` and matches the given constraint.
|
84
139
|
# You could use a `Range`, for example, as a constraint.
|
85
140
|
# If you don't need a constraint, use `Float` instead of `_Float`.
|
86
141
|
def _Float(...)
|
87
|
-
|
142
|
+
FloatType.new(...)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Nilable version of `_Float`
|
146
|
+
def _Float?(...)
|
147
|
+
NilableType.new(
|
148
|
+
FloatType.new(...),
|
149
|
+
)
|
88
150
|
end
|
89
151
|
|
90
152
|
# Matches if the value is *frozen*.
|
91
153
|
def _Frozen(...)
|
92
|
-
|
154
|
+
FrozenType.new(...)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Nilable version of `_Frozen`
|
158
|
+
def _Frozen?(...)
|
159
|
+
NilableType.new(
|
160
|
+
FrozenType.new(...),
|
161
|
+
)
|
93
162
|
end
|
94
163
|
|
95
164
|
# Matches if the value is a `Hash` and all the keys and values match the given types.
|
96
165
|
def _Hash(...)
|
97
|
-
|
166
|
+
HashType.new(...)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Nilable version of `_Hash`
|
170
|
+
def _Hash?
|
171
|
+
NilableType.new(
|
172
|
+
HashType.new,
|
173
|
+
)
|
98
174
|
end
|
99
175
|
|
100
176
|
# Matches if the value is an `Integer` and matches the given constraint.
|
@@ -103,95 +179,189 @@ module Literal::Types
|
|
103
179
|
# @example
|
104
180
|
# attribute :age, _Integer(18..127)
|
105
181
|
def _Integer(...)
|
106
|
-
|
182
|
+
IntegerType.new(...)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Nilable version of `_Integer`
|
186
|
+
def _Integer?(...)
|
187
|
+
NilableType.new(
|
188
|
+
IntegerType(...),
|
189
|
+
)
|
107
190
|
end
|
108
191
|
|
109
192
|
# Matches if the value responds to all the given methods.
|
110
193
|
def _Interface(...)
|
111
|
-
|
194
|
+
InterfaceType.new(...)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Nilable version of `_Interface`
|
198
|
+
def _Interface?(...)
|
199
|
+
NilableType.new(
|
200
|
+
InterfaceType.new(...),
|
201
|
+
)
|
112
202
|
end
|
113
203
|
|
114
204
|
# Matches if *all* given types are matched.
|
115
205
|
def _Intersection(...)
|
116
|
-
|
206
|
+
IntersectionType.new(...)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Nilable version of `_Intersection`
|
210
|
+
def _Intersection?(...)
|
211
|
+
NilableType.new(
|
212
|
+
IntersectionType.new(...),
|
213
|
+
)
|
117
214
|
end
|
118
215
|
|
119
216
|
# Ensures the value is valid JSON data (i.e. it came from JSON.parse).
|
120
217
|
def _JSONData
|
121
|
-
|
218
|
+
JSONDataType
|
219
|
+
end
|
220
|
+
|
221
|
+
# Nilable version of `_JSONData`
|
222
|
+
def _JSONData?
|
223
|
+
NilableJSONDataType
|
122
224
|
end
|
123
225
|
|
124
226
|
# Matches if the value is a `Proc` and `#lambda?` returns truthy.
|
125
227
|
def _Lambda
|
126
|
-
|
228
|
+
LambdaType
|
229
|
+
end
|
230
|
+
|
231
|
+
# Nilable version of `_Lambda`
|
232
|
+
def _Lambda?
|
233
|
+
NilableLambdaType
|
127
234
|
end
|
128
235
|
|
129
236
|
def _Map(...)
|
130
|
-
|
237
|
+
MapType.new(...)
|
238
|
+
end
|
239
|
+
|
240
|
+
# Nilable version of `_Map`
|
241
|
+
def _Map?(...)
|
242
|
+
NilableType.new(
|
243
|
+
MapType.new(...),
|
244
|
+
)
|
131
245
|
end
|
132
246
|
|
133
247
|
# Never matches any value.
|
134
248
|
def _Never
|
135
|
-
|
249
|
+
NeverType
|
136
250
|
end
|
137
251
|
|
138
252
|
# Matches if the value is either `nil` or the given type.
|
139
253
|
def _Nilable(...)
|
140
|
-
|
254
|
+
NilableType.new(...)
|
141
255
|
end
|
142
256
|
|
143
257
|
# Matches if the given type is *not* matched.
|
144
258
|
def _Not(...)
|
145
|
-
|
259
|
+
NotType.new(...)
|
146
260
|
end
|
147
261
|
|
148
262
|
# Matches if the value is a `Proc` or responds to `#to_proc`.
|
149
263
|
def _Procable
|
150
|
-
|
264
|
+
ProcableType
|
265
|
+
end
|
266
|
+
|
267
|
+
# Nilable version ofo `_Procable`
|
268
|
+
def _Procable?
|
269
|
+
NilableProcableType
|
151
270
|
end
|
152
271
|
|
153
272
|
# Matches if the value is a `Range` of the given type.
|
154
273
|
def _Range(...)
|
155
|
-
|
274
|
+
RangeType.new(...)
|
275
|
+
end
|
276
|
+
|
277
|
+
# Nilable version of `_Range`
|
278
|
+
def _Range?(...)
|
279
|
+
NilableType.new(
|
280
|
+
RangeType.new(...),
|
281
|
+
)
|
156
282
|
end
|
157
283
|
|
158
284
|
# Matches if the value is a `Set` and all the elements match the given type.
|
159
285
|
def _Set(...)
|
160
|
-
|
286
|
+
SetType.new(...)
|
287
|
+
end
|
288
|
+
|
289
|
+
# Nilable version of `_Set`
|
290
|
+
def _Set?(...)
|
291
|
+
NilableType.new(
|
292
|
+
SetType.new(...),
|
293
|
+
)
|
161
294
|
end
|
162
295
|
|
163
296
|
# Ensures a value matches the given shape of a Hash
|
164
297
|
def _Shape(...)
|
165
|
-
|
298
|
+
ShapeType.new(...)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Nilable version of `_Shape`
|
302
|
+
def _Shape?(...)
|
303
|
+
NilableType.new(
|
304
|
+
ShapeType.new(...),
|
305
|
+
)
|
166
306
|
end
|
167
307
|
|
308
|
+
# Nilable version of `_Shape`
|
309
|
+
|
168
310
|
# Matches if the value is a `String` and matches the given constraints.
|
169
311
|
# If you don't need any constraints, use `String` instead of `_String`.
|
170
312
|
def _String(...)
|
171
|
-
|
313
|
+
StringType.new(...)
|
314
|
+
end
|
315
|
+
|
316
|
+
# Nilable version of `_String`
|
317
|
+
def _String?(...)
|
318
|
+
NilableType.new(
|
319
|
+
StringType.new(...),
|
320
|
+
)
|
172
321
|
end
|
173
322
|
|
174
323
|
# Matches if the value is a `Symbol` and matches the given constraint.
|
175
324
|
def _Symbol(...)
|
176
|
-
|
325
|
+
SymbolType.new(...)
|
326
|
+
end
|
327
|
+
|
328
|
+
# Nilable version of `_Symbol`
|
329
|
+
def _Symbol?(...)
|
330
|
+
NilableType.new(
|
331
|
+
SymbolType.new(...),
|
332
|
+
)
|
177
333
|
end
|
178
334
|
|
179
335
|
# Matches *"truthy"* values (anything except `nil` and `false`).
|
180
336
|
def _Truthy
|
181
|
-
|
337
|
+
TruthyType
|
182
338
|
end
|
183
339
|
|
184
340
|
# Matches if the value is an `Array` and each element matches the given types in order.
|
185
341
|
def _Tuple(...)
|
186
|
-
|
342
|
+
TupleType.new(...)
|
343
|
+
end
|
344
|
+
|
345
|
+
# Nilable version of `_Typle`
|
346
|
+
def _Tuple?(...)
|
347
|
+
NilableType.new(
|
348
|
+
TupleType.new(...),
|
349
|
+
)
|
187
350
|
end
|
188
351
|
|
189
352
|
# Matches if *any* given type is matched.
|
190
353
|
def _Union(...)
|
191
|
-
|
354
|
+
UnionType.new(...)
|
355
|
+
end
|
356
|
+
|
357
|
+
# Nilable version of `_Union`
|
358
|
+
def _Union?(...)
|
359
|
+
NilableType.new(
|
360
|
+
UnionType.new(...),
|
361
|
+
)
|
192
362
|
end
|
193
363
|
|
194
364
|
def _Void
|
195
|
-
|
365
|
+
VoidType
|
196
366
|
end
|
197
367
|
end
|
data/lib/literal/version.rb
CHANGED
data/lib/literal.rb
CHANGED
@@ -25,11 +25,16 @@ module Literal
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.check(
|
29
|
-
if
|
28
|
+
def self.check(actual:, expected:)
|
29
|
+
if expected === actual
|
30
30
|
true
|
31
31
|
else
|
32
|
-
|
32
|
+
context = Literal::TypeError::Context.new(expected:, actual:)
|
33
|
+
expected.record_literal_type_errors(context) if expected.respond_to?(:record_literal_type_errors)
|
34
|
+
yield context if block_given?
|
35
|
+
raise Literal::TypeError.new(context:)
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
39
|
+
|
40
|
+
require_relative "literal/rails" if defined?(Rails)
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: literal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
13
|
+
description: Enums, properties, generics, structured objects.
|
14
14
|
email:
|
15
15
|
- joel@drapper.me
|
16
16
|
executables: []
|
@@ -20,7 +20,6 @@ files:
|
|
20
20
|
- LICENSE.txt
|
21
21
|
- README.md
|
22
22
|
- lib/literal.rb
|
23
|
-
- lib/literal.test.rb
|
24
23
|
- lib/literal/data.rb
|
25
24
|
- lib/literal/data_property.rb
|
26
25
|
- lib/literal/data_structure.rb
|
@@ -34,6 +33,11 @@ files:
|
|
34
33
|
- lib/literal/properties/data_schema.rb
|
35
34
|
- lib/literal/properties/schema.rb
|
36
35
|
- lib/literal/property.rb
|
36
|
+
- lib/literal/rails.rb
|
37
|
+
- lib/literal/rails/enum_serializer.rb
|
38
|
+
- lib/literal/rails/enum_type.rb
|
39
|
+
- lib/literal/rails/patches/active_record.rb
|
40
|
+
- lib/literal/railtie.rb
|
37
41
|
- lib/literal/struct.rb
|
38
42
|
- lib/literal/types.rb
|
39
43
|
- lib/literal/types/any_type.rb
|
@@ -84,15 +88,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
88
|
requirements:
|
85
89
|
- - ">="
|
86
90
|
- !ruby/object:Gem::Version
|
87
|
-
version: '3.
|
91
|
+
version: '3.1'
|
88
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
93
|
requirements:
|
90
94
|
- - ">="
|
91
95
|
- !ruby/object:Gem::Version
|
92
96
|
version: '0'
|
93
97
|
requirements: []
|
94
|
-
rubygems_version: 3.5.
|
98
|
+
rubygems_version: 3.5.18
|
95
99
|
signing_key:
|
96
100
|
specification_version: 4
|
97
|
-
summary: A literal Ruby gem
|
101
|
+
summary: A literal Ruby gem.
|
98
102
|
test_files: []
|