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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b459adebd387b12382d4e049a1f9211f6330bc6f77d66a8380bfbe758a4fb224
4
- data.tar.gz: d771162ac9e9939e20b9478225baa23dc5d3b4d2fd0f0daa3c821277053ea88f
3
+ metadata.gz: 9721432521677aa431dda4e94240521a54a8ac21ece07fef009393544d19214d
4
+ data.tar.gz: c5b41c95f4c24ff4fad28869bf61ff93174118a2d3e5890928961b382bf9b285
5
5
  SHA512:
6
- metadata.gz: 68c949539f7002388ccff9c0547c48988a3ccb9ae2cb3262f8ab9119f0187f8ff775c46d3b2aa8abbcc1bbb68a767427c99b48af898744c58bfa004fec3dd491
7
- data.tar.gz: 872aeda1f2efb4023e9c34c324e8fba149737d5744bc735e57b0ffdbb52be6001f39360fa86c5f981d70e70b5698394eef228eef9dde2d5ca387180414aac555
6
+ metadata.gz: 715a03576aed152e2fd5737236eb227dd98da9f02b421a14722395a3b9992dc667302574490955f0f9d81192dc5f64f793d916b196bc4509244afad5daa8a37b
7
+ data.tar.gz: 475df2645d537e5c8151ba6431e1469fdcfdd1a80d766489bfa00b135f3c3e57a86b0c09c7e6738c6033609a69864a596660a0b5498bd6762e314588a67bac35
@@ -0,0 +1,544 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Array
4
+ class Generic
5
+ include Literal::Type
6
+
7
+ def initialize(type)
8
+ @type = type
9
+ end
10
+
11
+ attr_reader :type
12
+
13
+ def new(*value)
14
+ Literal::Array.new(value, type: @type)
15
+ end
16
+
17
+ alias_method :[], :new
18
+
19
+ def ===(value)
20
+ Literal::Array === value && Literal.subtype?(value.__type__, of: @type)
21
+ end
22
+
23
+ def >=(other)
24
+ case other
25
+ when Literal::Array::Generic
26
+ @type >= other.type
27
+ else
28
+ false
29
+ end
30
+ end
31
+
32
+ def inspect
33
+ "Literal::Array(#{@type.inspect})"
34
+ end
35
+ end
36
+
37
+ include Enumerable
38
+ include Literal::Types
39
+
40
+ def initialize(value, type:)
41
+ Literal.check(actual: value, expected: _Array(type)) do |c|
42
+ c.fill_receiver(receiver: self, method: "#initialize")
43
+ end
44
+
45
+ @__type__ = type
46
+ @__value__ = value
47
+ end
48
+
49
+ def __initialize_without_check__(value, type:)
50
+ @__type__ = type
51
+ @__value__ = value
52
+ self
53
+ end
54
+
55
+ # Used to create a new Literal::Array with the same type and collection type but a new value. The value is not checked.
56
+ def __with__(value)
57
+ Literal::Array.allocate.__initialize_without_check__(
58
+ value,
59
+ type: @__type__,
60
+ )
61
+ end
62
+
63
+ attr_reader :__type__, :__value__
64
+
65
+ def &(other)
66
+ case other
67
+ when ::Array
68
+ __with__(@__value__ & other)
69
+ when Literal::Array
70
+ __with__(@__value__ & other.__value__)
71
+ else
72
+ raise ArgumentError.new("Cannot perform bitwise AND with #{other.class.name}.")
73
+ end
74
+ end
75
+
76
+ def *(times)
77
+ case times
78
+ when String
79
+ @__value__ * times
80
+ else
81
+ __with__(@__value__ * times)
82
+ end
83
+ end
84
+
85
+ def +(other)
86
+ case other
87
+ when ::Array
88
+ Literal.check(actual: other, expected: _Array(@__type__)) do |c|
89
+ c.fill_receiver(receiver: self, method: "#+")
90
+ end
91
+
92
+ __with__(@__value__ + other)
93
+ when Literal::Array(@__type__)
94
+ __with__(@__value__ + other.__value__)
95
+ when Literal::Array
96
+ raise Literal::TypeError.new(
97
+ context: Literal::TypeError::Context.new(
98
+ expected: Literal::Array(@__type__),
99
+ actual: other
100
+ )
101
+ )
102
+ else
103
+ raise ArgumentError.new("Cannot perform `+` with #{other.class.name}.")
104
+ end
105
+ end
106
+
107
+ def -(other)
108
+ case other
109
+ when ::Array
110
+ __with__(@__value__ - other)
111
+ when Literal::Array
112
+ __with__(@__value__ - other.__value__)
113
+ else
114
+ raise ArgumentError.new("Cannot perform `-` with #{other.class.name}.")
115
+ end
116
+ end
117
+
118
+ def <<(value)
119
+ Literal.check(actual: value, expected: @__type__) do |c|
120
+ c.fill_receiver(receiver: self, method: "#<<")
121
+ end
122
+
123
+ @__value__ << value
124
+ self
125
+ end
126
+
127
+ def <=>(other)
128
+ case other
129
+ when ::Array
130
+ @__value__ <=> other
131
+ when Literal::Array
132
+ @__value__ <=> other.__value__
133
+ else
134
+ raise ArgumentError.new("Cannot perform `<=>` with #{other.class.name}.")
135
+ end
136
+ end
137
+
138
+ def ==(other)
139
+ Literal::Array === other && @__value__ == other.__value__
140
+ end
141
+
142
+ def [](index)
143
+ @__value__[index]
144
+ end
145
+
146
+ def []=(index, value)
147
+ Literal.check(actual: value, expected: @__type__) do |c|
148
+ c.fill_receiver(receiver: self, method: "#[]=")
149
+ end
150
+
151
+ @__value__[index] = value
152
+ end
153
+
154
+ def all?(...)
155
+ @__value__.all?(...)
156
+ end
157
+
158
+ def any?(...)
159
+ @__value__.any?(...)
160
+ end
161
+
162
+ def assoc(...)
163
+ @__value__.assoc(...)
164
+ end
165
+
166
+ def at(...)
167
+ @__value__.at(...)
168
+ end
169
+
170
+ def bsearch(...)
171
+ @__value__.bsearch(...)
172
+ end
173
+
174
+ def clear(...)
175
+ @__value__.clear(...)
176
+ self
177
+ end
178
+
179
+ def combination(...)
180
+ @__value__.combination(...)
181
+ self
182
+ end
183
+
184
+ def compact
185
+ # @TODO if this is an array of nils, we should return an emtpy array
186
+ __with__(@__value__)
187
+ end
188
+
189
+ def compact!
190
+ # @TODO if this is an array of nils, we should set @__value__ = [] and return self
191
+ nil
192
+ end
193
+
194
+ def count(...)
195
+ @__value__.count(...)
196
+ end
197
+
198
+ def delete(...)
199
+ @__value__.delete(...)
200
+ end
201
+
202
+ def delete_at(...)
203
+ @__value__.delete_at(...)
204
+ end
205
+
206
+ def delete_if(...)
207
+ @__value__.delete_if(...)
208
+ self
209
+ end
210
+
211
+ def dig(...)
212
+ @__value__.dig(...)
213
+ end
214
+
215
+ def drop(...)
216
+ __with__(@__value__.drop(...))
217
+ end
218
+
219
+ def drop_while(...)
220
+ __with__(@__value__.drop_while(...))
221
+ end
222
+
223
+ def each(...)
224
+ @__value__.each(...)
225
+ end
226
+
227
+ def empty?
228
+ @__value__.empty?
229
+ end
230
+
231
+ alias_method :eql?, :==
232
+
233
+ def filter(...)
234
+ __with__(@__value__.filter(...))
235
+ end
236
+
237
+ def filter!(...)
238
+ @__value__.filter!(...)
239
+ self
240
+ end
241
+
242
+ def flatten(...)
243
+ __with__(@__value__.flatten(...))
244
+ end
245
+
246
+ def first(...)
247
+ @__value__.first(...)
248
+ end
249
+
250
+ def flatten!(...)
251
+ @__value__.flatten!(...) ? self : nil
252
+ end
253
+
254
+ def freeze
255
+ @__value__.freeze
256
+ super
257
+ end
258
+
259
+ alias_method :index, :find_index
260
+
261
+ def insert(index, *value)
262
+ Literal.check(actual: value, expected: _Array(@__type__)) do |c|
263
+ c.fill_receiver(receiver: self, method: "#insert")
264
+ end
265
+
266
+ @__value__.insert(index, *value)
267
+ self
268
+ end
269
+
270
+ def inspect
271
+ @__value__.inspect
272
+ end
273
+
274
+ def intersect?(other)
275
+ case other
276
+ when ::Array
277
+ @__value__.intersect?(other)
278
+ when Literal::Array
279
+ @__value__.intersect?(other.__value__)
280
+ else
281
+ raise ArgumentError.new("Cannot perform `intersect?` with #{other.class.name}.")
282
+ end
283
+ end
284
+
285
+ def intersection(*values)
286
+ values.map! do |value|
287
+ case value
288
+ when Literal::Array
289
+ value.__value__
290
+ else
291
+ value
292
+ end
293
+ end
294
+
295
+ __with__(@__value__.intersection(*values))
296
+ end
297
+
298
+ def join(...)
299
+ @__value__.join(...)
300
+ end
301
+
302
+ def keep_if(...)
303
+ return_value = @__value__.keep_if(...)
304
+ case return_value
305
+ when Array
306
+ self
307
+ else
308
+ return_value
309
+ end
310
+ end
311
+
312
+ def last(...)
313
+ @__value__.last(...)
314
+ end
315
+
316
+ def length(...)
317
+ @__value__.length(...)
318
+ end
319
+
320
+ def map(type, &block)
321
+ my_type = @__type__
322
+ transform_type = Literal::TRANSFORMS.dig(my_type, block)
323
+
324
+ if transform_type && Literal.subtype?(transform_type, of: my_type)
325
+ Literal::Array.allocate.__initialize_without_check__(
326
+ @__value__.map(&block),
327
+ type:,
328
+ )
329
+ else
330
+ Literal::Array.new(@__value__.map(&block), type:)
331
+ end
332
+ end
333
+
334
+ alias_method :collect, :map
335
+
336
+ # TODO: we can make this faster
337
+ def map!(&)
338
+ new_array = map(@__type__, &)
339
+ @__value__ = new_array.__value__
340
+ self
341
+ end
342
+
343
+ alias_method :collect!, :map!
344
+
345
+ def sum(...)
346
+ @__value__.sum(...)
347
+ end
348
+
349
+ def max(n = nil, &)
350
+ if n
351
+ __with__(@__value__.max(n, &))
352
+ else
353
+ @__value__.max(&)
354
+ end
355
+ end
356
+
357
+ def min(n = nil, &)
358
+ if n
359
+ __with__(@__value__.min(n, &))
360
+ else
361
+ @__value__.min(&)
362
+ end
363
+ end
364
+
365
+ def minmax(...)
366
+ __with__(@__value__.minmax(...))
367
+ end
368
+
369
+ def narrow(type)
370
+ unless Literal.subtype?(type, of: @__type__)
371
+ raise ArgumentError.new("Cannot narrow #{@__type__} to #{type}")
372
+ end
373
+
374
+ if __type__ != type
375
+ @__value__.each do |item|
376
+ Literal.check(actual: item, expected: type) do |c|
377
+ c.fill_receiver(receiver: self, method: "#narrow")
378
+ end
379
+ end
380
+ end
381
+
382
+ Literal::Array.allocate.__initialize_without_check__(
383
+ @__value__,
384
+ type:,
385
+ )
386
+ end
387
+
388
+ def one?(...)
389
+ @__value__.one?(...)
390
+ end
391
+
392
+ def pop(...)
393
+ @__value__.pop(...)
394
+ end
395
+
396
+ def push(*value)
397
+ Literal.check(actual: value, expected: _Array(@__type__)) do |c|
398
+ c.fill_receiver(receiver: self, method: "#push")
399
+ end
400
+
401
+ @__value__.push(*value)
402
+ self
403
+ end
404
+
405
+ alias_method :append, :push
406
+
407
+ def reject(...)
408
+ __with__(@__value__.reject(...))
409
+ end
410
+
411
+ def reject!(...)
412
+ @__value__.reject!(...)
413
+ self
414
+ end
415
+
416
+ def replace(value)
417
+ case value
418
+ when Array
419
+ Literal.check(actual: value, expected: _Array(@__type__)) do |c|
420
+ c.fill_receiver(receiver: self, method: "#replace")
421
+ end
422
+
423
+ @__value__.replace(value)
424
+ when Literal::Array(@__type__)
425
+ @__value__.replace(value.__value__)
426
+ when Literal::Array
427
+ raise Literal::TypeError.new(
428
+ context: Literal::TypeError::Context.new(expected: @__type__, actual: value.__type__)
429
+ )
430
+ else
431
+ raise ArgumentError.new("#replace expects Array argument")
432
+ end
433
+
434
+ self
435
+ end
436
+
437
+ def sample(...)
438
+ @__value__.sample(...)
439
+ end
440
+
441
+ def select(...)
442
+ __with__(@__value__.select(...))
443
+ end
444
+
445
+ def select!(...)
446
+ @__value__.select!(...)
447
+ end
448
+
449
+ def shift(...)
450
+ @__value__.shift(...)
451
+ end
452
+
453
+ def size(...)
454
+ @__value__.size(...)
455
+ end
456
+
457
+ def sort(...)
458
+ __with__(@__value__.sort(...))
459
+ end
460
+
461
+ def sort!(...)
462
+ @__value__.sort!(...)
463
+ self
464
+ end
465
+
466
+ def to_a
467
+ @__value__.dup
468
+ end
469
+
470
+ alias_method :to_ary, :to_a
471
+
472
+ alias_method :to_s, :inspect
473
+
474
+ def uniq
475
+ __with__(@__value__.uniq)
476
+ end
477
+
478
+ def uniq!(...)
479
+ @__value__.uniq!(...) ? self : nil
480
+ end
481
+
482
+ def unshift(value)
483
+ Literal.check(actual: value, expected: @__type__) do |c|
484
+ c.fill_receiver(receiver: self, method: "#unshift")
485
+ end
486
+
487
+ @__value__.unshift(value)
488
+ self
489
+ end
490
+
491
+ alias_method :prepend, :unshift
492
+
493
+ def values_at(*indexes)
494
+ unless @__type__ === nil
495
+ max_value = length - 1
496
+ min_value = -length
497
+
498
+ indexes.each do |index|
499
+ case index
500
+ when Integer
501
+ if index < min_value || index > max_value
502
+ raise IndexError.new("index #{index} out of range")
503
+ end
504
+ when Range
505
+ if index.begin < min_value || index.end > max_value
506
+ raise IndexError.new("index #{index} out of range")
507
+ end
508
+ else
509
+ raise ArgumentError.new("Invalid index: #{index.inspect}")
510
+ end
511
+ end
512
+ end
513
+
514
+ __with__(
515
+ @__value__.values_at(*indexes)
516
+ )
517
+ end
518
+
519
+ def |(other)
520
+ case other
521
+ when ::Array
522
+ Literal.check(actual: other, expected: _Array(@__type__)) do |c|
523
+ c.fill_receiver(receiver: self, method: "#|")
524
+ end
525
+
526
+ __with__(@__value__ | other)
527
+ when Literal::Array(@__type__)
528
+ __with__(@__value__ | other.__value__)
529
+ when Literal::Array
530
+ raise Literal::TypeError.new(
531
+ context: Literal::TypeError::Context.new(
532
+ expected: Literal::Array(@__type__),
533
+ actual: other
534
+ )
535
+ )
536
+ else
537
+ raise ArgumentError.new("Cannot perform `|` with #{other.class.name}.")
538
+ end
539
+ end
540
+
541
+ def fetch(...)
542
+ @__value__.fetch(...)
543
+ end
544
+ end
@@ -10,16 +10,6 @@ class Literal::DataStructure
10
10
  object
11
11
  end
12
12
 
13
- def [](key)
14
- instance_variable_get(:"@#{key}")
15
- end
16
-
17
- def []=(key, value)
18
- # TODO: Sync error array w/ generated setter
19
- @literal_properties[key].check(value) { |c| raise NotImplementedError }
20
- instance_variable_set(:"@#{key}", value)
21
- end
22
-
23
13
  def to_h
24
14
  {}
25
15
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Types::DeferredType
4
+ include Literal::Type
5
+
6
+ def initialize(&block)
7
+ @block = block
8
+ end
9
+
10
+ attr_reader :block
11
+
12
+ def inspect
13
+ "_Deferred"
14
+ end
15
+
16
+ def ===(other)
17
+ @block.call === other
18
+ end
19
+
20
+ def >=(other)
21
+ Literal.subtype?(other, of: @block.call)
22
+ end
23
+ end
data/lib/literal/flags.rb CHANGED
@@ -9,7 +9,6 @@ class Literal::Flags
9
9
  end
10
10
 
11
11
  @value = value
12
-
13
12
  freeze
14
13
  end
15
14
 
@@ -138,6 +137,15 @@ class Literal::Flags
138
137
  [@value].pack(self.class::PACKER)
139
138
  end
140
139
 
140
+ def with(**attributes)
141
+ new_val = attributes.reduce(value) do |value, (k, v)|
142
+ v ? value |= bitmap(k) : value &= ~(bitmap(k))
143
+ value
144
+ end
145
+
146
+ self.class.allocate.__initialize_from_value__(new_val)
147
+ end
148
+
141
149
  # () -> String
142
150
  def inspect
143
151
  to_h.inspect
@@ -156,7 +164,7 @@ class Literal::Flags
156
164
 
157
165
  # (Symbol) -> Boolean
158
166
  def [](key)
159
- @value & (2 ** self.class::FLAGS.fetch(key)) > 0
167
+ @value & (bitmap(key)) > 0
160
168
  end
161
169
 
162
170
  def |(other)
@@ -197,14 +205,19 @@ class Literal::Flags
197
205
 
198
206
  def deconstruct_keys(keys = nil)
199
207
  if keys
200
- flags = self.class::FLAGS
201
208
  keys.to_h do |key|
202
- [key, @value & (2 ** flags.fetch(key)) > 0]
209
+ [key, @value & (bitmap(key)) > 0]
203
210
  end
204
211
  else
205
212
  to_h
206
213
  end
207
214
  end
215
+
216
+ private
217
+
218
+ def bitmap(key)
219
+ 2 ** self.class::FLAGS.fetch(key)
220
+ end
208
221
  end
209
222
 
210
223
  class Literal::Flags8 < Literal::Flags
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Hash
4
+ class Generic
5
+ def initialize(key_type, value_type)
6
+ @key_type = key_type
7
+ @value_type = value_type
8
+ end
9
+
10
+ def new(**value)
11
+ Literal::Hash.new(value, key_type: @key_type, value_type: @value_type)
12
+ end
13
+
14
+ def ===(value)
15
+ Literal::Hash === value && @type == value.__type__
16
+ end
17
+
18
+ def inspect
19
+ "Literal::Hash(#{@type.inspect})"
20
+ end
21
+ end
22
+
23
+ include Enumerable
24
+
25
+ def initialize(value, key_type:, value_type:)
26
+ collection_type = Literal::Types::HashType.new(key_type, value_type)
27
+
28
+ Literal.check(actual: value, expected: collection_type) do |c|
29
+ c.fill_receiver(receiver: self, method: "#initialize")
30
+ end
31
+
32
+ @__key_type__ = key_type
33
+ @__value_type__ = value_type
34
+ @__value__ = value
35
+ @__collection_type__ = collection_type
36
+ end
37
+
38
+ attr_reader :__key_type__, :__value_type__, :__value__
39
+
40
+ def freeze
41
+ @__value__.freeze
42
+ super
43
+ end
44
+
45
+ def each(...)
46
+ @__value__.each(...)
47
+ end
48
+ end
@@ -102,7 +102,7 @@ class Literal::Properties::Schema
102
102
  i, n = 0, sorted_properties.size
103
103
  while i < n
104
104
  property = sorted_properties[i]
105
- buffer << " @" << property.name.name << " == other." << property.escaped_name
105
+ buffer << " @" << property.name.name << " == other." << property.name.name
106
106
  buffer << " &&\n " if i < n - 1
107
107
  i += 1
108
108
  end
@@ -154,7 +154,7 @@ class Literal::Properties::Schema
154
154
  end
155
155
 
156
156
  def generate_initializer_body(buffer = +"")
157
- buffer << " properties = self.class.literal_properties.properties_index\n"
157
+ buffer << " __properties__ = self.class.literal_properties.properties_index\n"
158
158
  generate_initializer_handle_properties(@sorted_properties, buffer)
159
159
  end
160
160
 
@@ -6,8 +6,13 @@ module Literal::Properties
6
6
 
7
7
  include Literal::Types
8
8
 
9
+ module DocString
10
+ # @!method initialize(...)
11
+ end
12
+
9
13
  def self.extended(base)
10
14
  super
15
+ base.include(DocString)
11
16
  base.include(base.__send__(:__literal_extension__))
12
17
  end
13
18