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
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