literal 1.1.0 → 1.3.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/literal/array.rb +544 -0
  3. data/lib/literal/data_structure.rb +0 -10
  4. data/lib/literal/deferred_type.rb +23 -0
  5. data/lib/literal/flags.rb +17 -4
  6. data/lib/literal/hash.rb +48 -0
  7. data/lib/literal/properties/schema.rb +2 -2
  8. data/lib/literal/properties.rb +5 -0
  9. data/lib/literal/property.rb +1 -1
  10. data/lib/literal/rails/flags_type.rb +41 -0
  11. data/lib/literal/rails.rb +1 -0
  12. data/lib/literal/railtie.rb +8 -0
  13. data/lib/literal/set.rb +48 -0
  14. data/lib/literal/struct.rb +26 -0
  15. data/lib/literal/transforms.rb +142 -0
  16. data/lib/literal/type.rb +7 -0
  17. data/lib/literal/types/any_type.rb +13 -3
  18. data/lib/literal/types/array_type.rb +18 -1
  19. data/lib/literal/types/boolean_type.rb +18 -3
  20. data/lib/literal/types/class_type.rb +20 -1
  21. data/lib/literal/types/constraint_type.rb +42 -1
  22. data/lib/literal/types/descendant_type.rb +18 -1
  23. data/lib/literal/types/enumerable_type.rb +18 -1
  24. data/lib/literal/types/falsy_type.rb +22 -3
  25. data/lib/literal/types/frozen_type.rb +35 -1
  26. data/lib/literal/types/hash_type.rb +22 -1
  27. data/lib/literal/types/interface_type.rb +31 -1
  28. data/lib/literal/types/intersection_type.rb +27 -0
  29. data/lib/literal/types/json_data_type.rb +49 -3
  30. data/lib/literal/types/map_type.rb +23 -5
  31. data/lib/literal/types/never_type.rb +18 -3
  32. data/lib/literal/types/nilable_type.rb +24 -1
  33. data/lib/literal/types/not_type.rb +22 -1
  34. data/lib/literal/types/range_type.rb +18 -1
  35. data/lib/literal/types/set_type.rb +28 -1
  36. data/lib/literal/types/truthy_type.rb +17 -3
  37. data/lib/literal/types/tuple_type.rb +19 -2
  38. data/lib/literal/types/union_type.rb +27 -3
  39. data/lib/literal/types/void_type.rb +13 -3
  40. data/lib/literal/types.rb +58 -51
  41. data/lib/literal/version.rb +1 -1
  42. data/lib/literal.rb +38 -5
  43. metadata +9 -9
  44. data/lib/literal/types/callable_type.rb +0 -12
  45. data/lib/literal/types/float_type.rb +0 -10
  46. data/lib/literal/types/integer_type.rb +0 -10
  47. data/lib/literal/types/lambda_type.rb +0 -12
  48. data/lib/literal/types/procable_type.rb +0 -12
  49. data/lib/literal/types/string_type.rb +0 -10
  50. data/lib/literal/types/symbol_type.rb +0 -10
data/lib/literal/types.rb CHANGED
@@ -4,47 +4,45 @@ module Literal::Types
4
4
  autoload :AnyType, "literal/types/any_type"
5
5
  autoload :ArrayType, "literal/types/array_type"
6
6
  autoload :BooleanType, "literal/types/boolean_type"
7
- autoload :CallableType, "literal/types/callable_type"
8
7
  autoload :ClassType, "literal/types/class_type"
9
8
  autoload :ConstraintType, "literal/types/constraint_type"
9
+ autoload :DeferredType, "literal/deferred_type"
10
10
  autoload :DescendantType, "literal/types/descendant_type"
11
11
  autoload :EnumerableType, "literal/types/enumerable_type"
12
12
  autoload :FalsyType, "literal/types/falsy_type"
13
- autoload :FloatType, "literal/types/float_type"
14
13
  autoload :FrozenType, "literal/types/frozen_type"
15
14
  autoload :HashType, "literal/types/hash_type"
16
- autoload :IntegerType, "literal/types/integer_type"
17
15
  autoload :InterfaceType, "literal/types/interface_type"
18
16
  autoload :IntersectionType, "literal/types/intersection_type"
19
17
  autoload :JSONDataType, "literal/types/json_data_type"
20
- autoload :LambdaType, "literal/types/lambda_type"
21
18
  autoload :MapType, "literal/types/map_type"
22
19
  autoload :NeverType, "literal/types/never_type"
23
20
  autoload :NilableType, "literal/types/nilable_type"
24
21
  autoload :NotType, "literal/types/not_type"
25
- autoload :ProcableType, "literal/types/procable_type"
26
22
  autoload :RangeType, "literal/types/range_type"
27
23
  autoload :SetType, "literal/types/set_type"
28
- autoload :StringType, "literal/types/string_type"
29
- autoload :SymbolType, "literal/types/symbol_type"
30
24
  autoload :TruthyType, "literal/types/truthy_type"
31
25
  autoload :TupleType, "literal/types/tuple_type"
32
26
  autoload :UnionType, "literal/types/union_type"
33
27
  autoload :VoidType, "literal/types/void_type"
34
28
 
35
- NilableBooleanType = NilableType.new(BooleanType)
36
- NilableCallableType = NilableType.new(CallableType)
37
- NilableJSONDataType = NilableType.new(JSONDataType)
38
- NilableLambdaType = NilableType.new(LambdaType)
39
- NilableProcableType = NilableType.new(ProcableType)
29
+ ProcableType = InterfaceType.new(:to_proc).freeze
30
+ CallableType = InterfaceType.new(:call).freeze
31
+ LambdaType = ConstraintType.new(Proc, lambda?: true).freeze
32
+
33
+ NilableBooleanType = NilableType.new(BooleanType::Instance).freeze
34
+ NilableCallableType = NilableType.new(CallableType).freeze
35
+ NilableJSONDataType = NilableType.new(JSONDataType).freeze
36
+ NilableLambdaType = NilableType.new(LambdaType).freeze
37
+ NilableProcableType = NilableType.new(ProcableType).freeze
40
38
 
41
39
  # Matches any value except `nil`. Use `_Any?` or `_Void` to match any value including `nil`.
42
40
  def _Any
43
- AnyType
41
+ AnyType::Instance
44
42
  end
45
43
 
46
44
  def _Any?
47
- VoidType
45
+ VoidType::Instance
48
46
  end
49
47
 
50
48
  # Matches if the value is an `Array` and all the elements match the given type.
@@ -55,13 +53,13 @@ module Literal::Types
55
53
  # Nilable version of `_Array`
56
54
  def _Array?(...)
57
55
  NilableType.new(
58
- ArrayType.new(...),
56
+ ArrayType.new(...)
59
57
  )
60
58
  end
61
59
 
62
60
  # Matches if the value is `true` or `false`.
63
61
  def _Boolean
64
- BooleanType
62
+ BooleanType::Instance
65
63
  end
66
64
 
67
65
  # Nilable version of `_Boolean`
@@ -87,7 +85,7 @@ module Literal::Types
87
85
  # Nilable version of `_Class`
88
86
  def _Class?(...)
89
87
  NilableType.new(
90
- ClassType.new(...),
88
+ ClassType.new(...)
91
89
  )
92
90
  end
93
91
 
@@ -101,10 +99,14 @@ module Literal::Types
101
99
  # Nilable version of `_Constraint`
102
100
  def _Constraint?(...)
103
101
  NilableType.new(
104
- ConstraintType.new(...),
102
+ ConstraintType.new(...)
105
103
  )
106
104
  end
107
105
 
106
+ def _Deferred(...)
107
+ DeferredType.new(...)
108
+ end
109
+
108
110
  # Matches if the value is a descendant of the given class.
109
111
  def _Descendant(...)
110
112
  DescendantType.new(...)
@@ -113,7 +115,7 @@ module Literal::Types
113
115
  # Nilable version of `_Descendant`
114
116
  def _Descendant?(...)
115
117
  NilableType.new(
116
- DescendantType.new(...),
118
+ DescendantType.new(...)
117
119
  )
118
120
  end
119
121
 
@@ -125,26 +127,26 @@ module Literal::Types
125
127
  # Nilable version of `_Enumerable`
126
128
  def _Enumerable?(...)
127
129
  NilableType.new(
128
- EnumerableType.new(...),
130
+ EnumerableType.new(...)
129
131
  )
130
132
  end
131
133
 
132
134
  # Matches *"falsy"* values (`nil` and `false`).
133
135
  def _Falsy
134
- FalsyType
136
+ FalsyType::Instance
135
137
  end
136
138
 
137
- # Matches if the value is a `Float` and matches the given constraint.
139
+ # Matches if the value is a `Float` and matches the given constraints.
138
140
  # You could use a `Range`, for example, as a constraint.
139
141
  # If you don't need a constraint, use `Float` instead of `_Float`.
140
142
  def _Float(...)
141
- FloatType.new(...)
143
+ _Constraint(Float, ...)
142
144
  end
143
145
 
144
146
  # Nilable version of `_Float`
145
147
  def _Float?(...)
146
- NilableType.new(
147
- FloatType.new(...),
148
+ _Nilable(
149
+ _Float(...)
148
150
  )
149
151
  end
150
152
 
@@ -156,7 +158,7 @@ module Literal::Types
156
158
  # Nilable version of `_Frozen`
157
159
  def _Frozen?(...)
158
160
  NilableType.new(
159
- FrozenType.new(...),
161
+ FrozenType.new(...)
160
162
  )
161
163
  end
162
164
 
@@ -166,9 +168,9 @@ module Literal::Types
166
168
  end
167
169
 
168
170
  # Nilable version of `_Hash`
169
- def _Hash?
171
+ def _Hash?(...)
170
172
  NilableType.new(
171
- HashType.new,
173
+ HashType.new(...)
172
174
  )
173
175
  end
174
176
 
@@ -178,13 +180,13 @@ module Literal::Types
178
180
  # @example
179
181
  # attribute :age, _Integer(18..127)
180
182
  def _Integer(...)
181
- IntegerType.new(...)
183
+ _Constraint(Integer, ...)
182
184
  end
183
185
 
184
186
  # Nilable version of `_Integer`
185
187
  def _Integer?(...)
186
- NilableType.new(
187
- IntegerType(...),
188
+ _Nilable(
189
+ _Integer(...)
188
190
  )
189
191
  end
190
192
 
@@ -196,7 +198,7 @@ module Literal::Types
196
198
  # Nilable version of `_Interface`
197
199
  def _Interface?(...)
198
200
  NilableType.new(
199
- InterfaceType.new(...),
201
+ InterfaceType.new(...)
200
202
  )
201
203
  end
202
204
 
@@ -208,13 +210,13 @@ module Literal::Types
208
210
  # Nilable version of `_Intersection`
209
211
  def _Intersection?(...)
210
212
  NilableType.new(
211
- IntersectionType.new(...),
213
+ IntersectionType.new(...)
212
214
  )
213
215
  end
214
216
 
215
217
  # Ensures the value is valid JSON data (i.e. it came from JSON.parse).
216
218
  def _JSONData
217
- JSONDataType
219
+ JSONDataType::Instance
218
220
  end
219
221
 
220
222
  # Nilable version of `_JSONData`
@@ -239,13 +241,13 @@ module Literal::Types
239
241
  # Nilable version of `_Map`
240
242
  def _Map?(...)
241
243
  NilableType.new(
242
- MapType.new(...),
244
+ MapType.new(...)
243
245
  )
244
246
  end
245
247
 
246
248
  # Never matches any value.
247
249
  def _Never
248
- NeverType
250
+ NeverType::Instance
249
251
  end
250
252
 
251
253
  # Matches if the value is either `nil` or the given type.
@@ -254,8 +256,13 @@ module Literal::Types
254
256
  end
255
257
 
256
258
  # Matches if the given type is *not* matched.
257
- def _Not(...)
258
- NotType.new(...)
259
+ def _Not(type)
260
+ case type
261
+ when NotType
262
+ type.type
263
+ else
264
+ NotType.new(type)
265
+ end
259
266
  end
260
267
 
261
268
  # Matches if the value is a `Proc` or responds to `#to_proc`.
@@ -276,7 +283,7 @@ module Literal::Types
276
283
  # Nilable version of `_Range`
277
284
  def _Range?(...)
278
285
  NilableType.new(
279
- RangeType.new(...),
286
+ RangeType.new(...)
280
287
  )
281
288
  end
282
289
 
@@ -288,38 +295,38 @@ module Literal::Types
288
295
  # Nilable version of `_Set`
289
296
  def _Set?(...)
290
297
  NilableType.new(
291
- SetType.new(...),
298
+ SetType.new(...)
292
299
  )
293
300
  end
294
301
 
295
302
  # Matches if the value is a `String` and matches the given constraints.
296
303
  # If you don't need any constraints, use `String` instead of `_String`.
297
304
  def _String(...)
298
- StringType.new(...)
305
+ _Constraint(String, ...)
299
306
  end
300
307
 
301
308
  # Nilable version of `_String`
302
309
  def _String?(...)
303
- NilableType.new(
304
- StringType.new(...),
310
+ _Nilable(
311
+ _String(...)
305
312
  )
306
313
  end
307
314
 
308
- # Matches if the value is a `Symbol` and matches the given constraint.
315
+ # Matches if the value is a `Symbol` and matches the given constraints.
309
316
  def _Symbol(...)
310
- SymbolType.new(...)
317
+ _Constraint(Symbol, ...)
311
318
  end
312
319
 
313
320
  # Nilable version of `_Symbol`
314
321
  def _Symbol?(...)
315
- NilableType.new(
316
- SymbolType.new(...),
322
+ _Nilable(
323
+ _Symbol(...)
317
324
  )
318
325
  end
319
326
 
320
327
  # Matches *"truthy"* values (anything except `nil` and `false`).
321
328
  def _Truthy
322
- TruthyType
329
+ TruthyType::Instance
323
330
  end
324
331
 
325
332
  # Matches if the value is an `Array` and each element matches the given types in order.
@@ -330,7 +337,7 @@ module Literal::Types
330
337
  # Nilable version of `_Typle`
331
338
  def _Tuple?(...)
332
339
  NilableType.new(
333
- TupleType.new(...),
340
+ TupleType.new(...)
334
341
  )
335
342
  end
336
343
 
@@ -342,11 +349,11 @@ module Literal::Types
342
349
  # Nilable version of `_Union`
343
350
  def _Union?(...)
344
351
  NilableType.new(
345
- UnionType.new(...),
352
+ UnionType.new(...)
346
353
  )
347
354
  end
348
355
 
349
356
  def _Void
350
- VoidType
357
+ VoidType::Instance
351
358
  end
352
359
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Literal
4
- VERSION = "1.1.0"
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/literal.rb CHANGED
@@ -3,33 +3,51 @@
3
3
  module Literal
4
4
  TYPE_CHECKS_DISABLED = ENV["LITERAL_TYPE_CHECKS"] == "false"
5
5
 
6
+ autoload :Array, "literal/array"
6
7
  autoload :Data, "literal/data"
7
8
  autoload :DataProperty, "literal/data_property"
8
9
  autoload :DataStructure, "literal/data_structure"
9
10
  autoload :Enum, "literal/enum"
11
+ autoload :Flags, "literal/flags"
12
+ autoload :Flags16, "literal/flags"
13
+ autoload :Flags32, "literal/flags"
14
+ autoload :Flags64, "literal/flags"
15
+ autoload :Flags8, "literal/flags"
16
+ autoload :Hash, "literal/hash"
10
17
  autoload :Null, "literal/null"
11
18
  autoload :Object, "literal/object"
12
19
  autoload :Properties, "literal/properties"
13
20
  autoload :Property, "literal/property"
21
+ autoload :Set, "literal/set"
14
22
  autoload :Struct, "literal/struct"
23
+ autoload :Type, "literal/type"
15
24
  autoload :Types, "literal/types"
16
- autoload :Flags, "literal/flags"
17
- autoload :Flags8, "literal/flags"
18
- autoload :Flags16, "literal/flags"
19
- autoload :Flags32, "literal/flags"
20
- autoload :Flags64, "literal/flags"
21
25
 
22
26
  # Errors
23
27
  autoload :Error, "literal/errors/error"
24
28
  autoload :TypeError, "literal/errors/type_error"
25
29
  autoload :ArgumentError, "literal/errors/argument_error"
26
30
 
31
+ autoload :TRANSFORMS, "literal/transforms"
32
+
27
33
  def self.Enum(type)
28
34
  Class.new(Literal::Enum) do
29
35
  prop :value, type, :positional
30
36
  end
31
37
  end
32
38
 
39
+ def self.Array(type)
40
+ Literal::Array::Generic.new(type)
41
+ end
42
+
43
+ def self.Set(type)
44
+ Literal::Set::Generic.new(type)
45
+ end
46
+
47
+ def self.Hash(key_type, value_type)
48
+ Literal::Hash::Generic.new(key_type, value_type)
49
+ end
50
+
33
51
  def self.check(actual:, expected:)
34
52
  if expected === actual
35
53
  true
@@ -40,6 +58,21 @@ module Literal
40
58
  raise Literal::TypeError.new(context:)
41
59
  end
42
60
  end
61
+
62
+ def self.subtype?(type, of:)
63
+ type = type.block.call if Types::DeferredType === type
64
+
65
+ (of == type) || case of
66
+ when Literal::Type
67
+ of >= type
68
+ when Module
69
+ (Module === type) ? of >= type : false
70
+ when Range
71
+ of.cover?(type)
72
+ else
73
+ false
74
+ end
75
+ end
43
76
  end
44
77
 
45
78
  require_relative "literal/rails" if defined?(Rails)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: literal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
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-07 00:00:00.000000000 Z
11
+ date: 2024-11-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A literal Ruby gem.
14
14
  email:
@@ -20,14 +20,17 @@ files:
20
20
  - LICENSE.txt
21
21
  - README.md
22
22
  - lib/literal.rb
23
+ - lib/literal/array.rb
23
24
  - lib/literal/data.rb
24
25
  - lib/literal/data_property.rb
25
26
  - lib/literal/data_structure.rb
27
+ - lib/literal/deferred_type.rb
26
28
  - lib/literal/enum.rb
27
29
  - lib/literal/errors/argument_error.rb
28
30
  - lib/literal/errors/error.rb
29
31
  - lib/literal/errors/type_error.rb
30
32
  - lib/literal/flags.rb
33
+ - lib/literal/hash.rb
31
34
  - lib/literal/null.rb
32
35
  - lib/literal/object.rb
33
36
  - lib/literal/properties.rb
@@ -37,36 +40,33 @@ files:
37
40
  - lib/literal/rails.rb
38
41
  - lib/literal/rails/enum_serializer.rb
39
42
  - lib/literal/rails/enum_type.rb
43
+ - lib/literal/rails/flags_type.rb
40
44
  - lib/literal/rails/patches/active_record.rb
41
45
  - lib/literal/railtie.rb
46
+ - lib/literal/set.rb
42
47
  - lib/literal/struct.rb
48
+ - lib/literal/transforms.rb
49
+ - lib/literal/type.rb
43
50
  - lib/literal/types.rb
44
51
  - lib/literal/types/any_type.rb
45
52
  - lib/literal/types/array_type.rb
46
53
  - lib/literal/types/boolean_type.rb
47
- - lib/literal/types/callable_type.rb
48
54
  - lib/literal/types/class_type.rb
49
55
  - lib/literal/types/constraint_type.rb
50
56
  - lib/literal/types/descendant_type.rb
51
57
  - lib/literal/types/enumerable_type.rb
52
58
  - lib/literal/types/falsy_type.rb
53
- - lib/literal/types/float_type.rb
54
59
  - lib/literal/types/frozen_type.rb
55
60
  - lib/literal/types/hash_type.rb
56
- - lib/literal/types/integer_type.rb
57
61
  - lib/literal/types/interface_type.rb
58
62
  - lib/literal/types/intersection_type.rb
59
63
  - lib/literal/types/json_data_type.rb
60
- - lib/literal/types/lambda_type.rb
61
64
  - lib/literal/types/map_type.rb
62
65
  - lib/literal/types/never_type.rb
63
66
  - lib/literal/types/nilable_type.rb
64
67
  - lib/literal/types/not_type.rb
65
- - lib/literal/types/procable_type.rb
66
68
  - lib/literal/types/range_type.rb
67
69
  - lib/literal/types/set_type.rb
68
- - lib/literal/types/string_type.rb
69
- - lib/literal/types/symbol_type.rb
70
70
  - lib/literal/types/truthy_type.rb
71
71
  - lib/literal/types/tuple_type.rb
72
72
  - lib/literal/types/union_type.rb
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- module Literal::Types::CallableType
5
- def self.inspect = "_Callable"
6
-
7
- def self.===(value)
8
- value.respond_to?(:call)
9
- end
10
-
11
- freeze
12
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- class Literal::Types::FloatType < Literal::Types::ConstraintType
5
- def inspect = "_Float(#{inspect_constraints})"
6
-
7
- def ===(value)
8
- Float === value && super
9
- end
10
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- class Literal::Types::IntegerType < Literal::Types::ConstraintType
5
- def inspect = "_Integer(#{inspect_constraints})"
6
-
7
- def ===(value)
8
- Integer === value && super
9
- end
10
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- module Literal::Types::LambdaType
5
- def self.inspect = "_Lambda"
6
-
7
- def self.===(value)
8
- Proc === value && value.lambda?
9
- end
10
-
11
- freeze
12
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- module Literal::Types::ProcableType
5
- def self.inspect = "_Procable"
6
-
7
- def self.===(value)
8
- Proc === value || value.respond_to?(:to_proc)
9
- end
10
-
11
- freeze
12
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- class Literal::Types::StringType < Literal::Types::ConstraintType
5
- def inspect = "_String(#{inspect_constraints})"
6
-
7
- def ===(value)
8
- String === value && super
9
- end
10
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- class Literal::Types::SymbolType < Literal::Types::ConstraintType
5
- def inspect = "_Symbol(#{inspect_constraints})"
6
-
7
- def ===(value)
8
- Symbol === value && super
9
- end
10
- end