literal 1.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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