literal 1.5.0 → 1.7.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.
- checksums.yaml +4 -4
- data/lib/literal/array.rb +15 -15
- data/lib/literal/data_structure.rb +4 -3
- data/lib/literal/delegator.rb +25 -0
- data/lib/literal/enum.rb +4 -5
- data/lib/literal/flags/flags_16.rb +7 -0
- data/lib/literal/flags/flags_32.rb +7 -0
- data/lib/literal/flags/flags_64.rb +7 -0
- data/lib/literal/flags/flags_8.rb +7 -0
- data/lib/literal/flags.rb +0 -24
- data/lib/literal/hash.rb +1 -1
- data/lib/literal/properties/schema.rb +3 -3
- data/lib/literal/properties.rb +5 -6
- data/lib/literal/property.rb +3 -3
- data/lib/literal/rails/enum_type.rb +4 -0
- data/lib/literal/rails.rb +0 -3
- data/lib/literal/set.rb +1 -1
- data/lib/literal/transforms.rb +2 -2
- data/lib/literal/tuple.rb +2 -2
- data/lib/literal/types/array_type.rb +1 -0
- data/lib/literal/types/class_type.rb +3 -2
- data/lib/literal/types/constraint_type.rb +5 -4
- data/lib/literal/{deferred_type.rb → types/deferred_type.rb} +1 -1
- data/lib/literal/types/descendant_type.rb +2 -1
- data/lib/literal/types/enumerable_type.rb +2 -1
- data/lib/literal/types/frozen_type.rb +3 -2
- data/lib/literal/types/hash_type.rb +3 -2
- data/lib/literal/types/interface_type.rb +20 -14
- data/lib/literal/types/intersection_type.rb +4 -3
- data/lib/literal/types/map_type.rb +2 -1
- data/lib/literal/types/nilable_type.rb +3 -2
- data/lib/literal/types/not_type.rb +4 -3
- data/lib/literal/types/predicate_type.rb +22 -0
- data/lib/literal/types/range_type.rb +2 -1
- data/lib/literal/types/set_type.rb +2 -1
- data/lib/literal/types/tuple_type.rb +1 -0
- data/lib/literal/types/union_type.rb +46 -30
- data/lib/literal/types.rb +143 -87
- data/lib/literal/value.rb +65 -0
- data/lib/literal/version.rb +1 -1
- data/lib/literal.rb +82 -37
- metadata +26 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c4292f514f586e16d0d477cc57e9a8b1f38771a8124f9ed933b67aa167550a0
|
4
|
+
data.tar.gz: 48dc63568c23368fb5c1577a57833720ca272c2aeca24dfc33e26271ed378497
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d79162f89f5088923b2a18ffb2d77214401e18f2d992d2535ab85a4f73b0adbf4430bf385dd846f860e7c0c984508bd6a4d48296a13883fefdb1eb8ef0ac51eb
|
7
|
+
data.tar.gz: d0cbebd25520b382b6ea73d22b9b2120b15831d7b51d6b2deb99bfd2adaa1c53cfeadbf4b6c3f7af6e97ea634991c49fe5e49d559c2efcf228ec2e9fe942daf1
|
data/lib/literal/array.rb
CHANGED
@@ -17,13 +17,13 @@ class Literal::Array
|
|
17
17
|
alias_method :[], :new
|
18
18
|
|
19
19
|
def ===(value)
|
20
|
-
Literal::Array === value && Literal.subtype?(value.__type__,
|
20
|
+
Literal::Array === value && Literal.subtype?(value.__type__, @type)
|
21
21
|
end
|
22
22
|
|
23
23
|
def >=(other)
|
24
24
|
case other
|
25
25
|
when Literal::Array::Generic
|
26
|
-
Literal.subtype?(other.type,
|
26
|
+
Literal.subtype?(other.type, @type)
|
27
27
|
else
|
28
28
|
false
|
29
29
|
end
|
@@ -51,7 +51,7 @@ class Literal::Array
|
|
51
51
|
include Literal::Types
|
52
52
|
|
53
53
|
def initialize(value, type:)
|
54
|
-
Literal.check(
|
54
|
+
Literal.check(value, _Array(type)) do |c|
|
55
55
|
c.fill_receiver(receiver: self, method: "#initialize")
|
56
56
|
end
|
57
57
|
|
@@ -98,7 +98,7 @@ class Literal::Array
|
|
98
98
|
def +(other)
|
99
99
|
case other
|
100
100
|
when ::Array
|
101
|
-
Literal.check(
|
101
|
+
Literal.check(other, _Array(@__type__)) do |c|
|
102
102
|
c.fill_receiver(receiver: self, method: "#+")
|
103
103
|
end
|
104
104
|
|
@@ -129,7 +129,7 @@ class Literal::Array
|
|
129
129
|
end
|
130
130
|
|
131
131
|
def <<(value)
|
132
|
-
Literal.check(
|
132
|
+
Literal.check(value, @__type__) do |c|
|
133
133
|
c.fill_receiver(receiver: self, method: "#<<")
|
134
134
|
end
|
135
135
|
|
@@ -157,7 +157,7 @@ class Literal::Array
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def []=(index, value)
|
160
|
-
Literal.check(
|
160
|
+
Literal.check(value, @__type__) do |c|
|
161
161
|
c.fill_receiver(receiver: self, method: "#[]=")
|
162
162
|
end
|
163
163
|
|
@@ -284,7 +284,7 @@ class Literal::Array
|
|
284
284
|
alias_method :index, :find_index
|
285
285
|
|
286
286
|
def insert(index, *value)
|
287
|
-
Literal.check(
|
287
|
+
Literal.check(value, _Array(@__type__)) do |c|
|
288
288
|
c.fill_receiver(receiver: self, method: "#insert")
|
289
289
|
end
|
290
290
|
|
@@ -344,9 +344,9 @@ class Literal::Array
|
|
344
344
|
|
345
345
|
def map(type, &block)
|
346
346
|
my_type = @__type__
|
347
|
-
transform_type = Literal::
|
347
|
+
transform_type = Literal::Transforms.dig(my_type, block)
|
348
348
|
|
349
|
-
if transform_type && Literal.subtype?(transform_type,
|
349
|
+
if transform_type && Literal.subtype?(transform_type, my_type)
|
350
350
|
Literal::Array.allocate.__initialize_without_check__(
|
351
351
|
@__value__.map(&block),
|
352
352
|
type:,
|
@@ -392,13 +392,13 @@ class Literal::Array
|
|
392
392
|
end
|
393
393
|
|
394
394
|
def narrow(type)
|
395
|
-
unless Literal.subtype?(type,
|
395
|
+
unless Literal.subtype?(type, @__type__)
|
396
396
|
raise ArgumentError.new("Cannot narrow #{@__type__} to #{type}")
|
397
397
|
end
|
398
398
|
|
399
399
|
if __type__ != type
|
400
400
|
@__value__.each do |item|
|
401
|
-
Literal.check(
|
401
|
+
Literal.check(item, type) do |c|
|
402
402
|
c.fill_receiver(receiver: self, method: "#narrow")
|
403
403
|
end
|
404
404
|
end
|
@@ -453,7 +453,7 @@ class Literal::Array
|
|
453
453
|
end
|
454
454
|
|
455
455
|
def push(*value)
|
456
|
-
Literal.check(
|
456
|
+
Literal.check(value, _Array(@__type__)) do |c|
|
457
457
|
c.fill_receiver(receiver: self, method: "#push")
|
458
458
|
end
|
459
459
|
|
@@ -475,7 +475,7 @@ class Literal::Array
|
|
475
475
|
def replace(value)
|
476
476
|
case value
|
477
477
|
when Array
|
478
|
-
Literal.check(
|
478
|
+
Literal.check(value, _Array(@__type__)) do |c|
|
479
479
|
c.fill_receiver(receiver: self, method: "#replace")
|
480
480
|
end
|
481
481
|
|
@@ -597,7 +597,7 @@ class Literal::Array
|
|
597
597
|
end
|
598
598
|
|
599
599
|
def unshift(value)
|
600
|
-
Literal.check(
|
600
|
+
Literal.check(value, @__type__) do |c|
|
601
601
|
c.fill_receiver(receiver: self, method: "#unshift")
|
602
602
|
end
|
603
603
|
|
@@ -636,7 +636,7 @@ class Literal::Array
|
|
636
636
|
def |(other)
|
637
637
|
case other
|
638
638
|
when ::Array
|
639
|
-
Literal.check(
|
639
|
+
Literal.check(other, _Array(@__type__)) do |c|
|
640
640
|
c.fill_receiver(receiver: self, method: "#|")
|
641
641
|
end
|
642
642
|
|
@@ -38,7 +38,7 @@ class Literal::DataStructure
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def marshal_dump
|
41
|
-
[1, to_h, frozen?]
|
41
|
+
[1, to_h, frozen?].freeze
|
42
42
|
end
|
43
43
|
|
44
44
|
def hash
|
@@ -46,9 +46,10 @@ class Literal::DataStructure
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def ==(other)
|
49
|
-
|
49
|
+
self.class === other && other.class.literal_properties.empty?
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
|
+
alias_method :eql?, :==
|
52
53
|
|
53
54
|
def self.__generate_literal_methods__(new_property, buffer = +"")
|
54
55
|
super
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Literal::Delegator < SimpleDelegator
|
4
|
+
def self.to_proc
|
5
|
+
-> (value) { new(value) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.[](value)
|
9
|
+
new(value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(value)
|
13
|
+
Literal.check(value, __type__)
|
14
|
+
super
|
15
|
+
freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def ===(other)
|
19
|
+
self.class === other && __getobj__ == other.__getobj__
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :==, :===
|
23
|
+
|
24
|
+
freeze
|
25
|
+
end
|
data/lib/literal/enum.rb
CHANGED
@@ -24,7 +24,7 @@ class Literal::Enum
|
|
24
24
|
@names = {}
|
25
25
|
end
|
26
26
|
|
27
|
-
if RUBY_ENGINE != "truffleruby"
|
27
|
+
if subclass.name && RUBY_ENGINE != "truffleruby"
|
28
28
|
TracePoint.trace(:end) do |tp|
|
29
29
|
if tp.self == subclass
|
30
30
|
tp.self.__after_defined__
|
@@ -55,7 +55,7 @@ class Literal::Enum
|
|
55
55
|
|
56
56
|
types = @indexes_definitions.fetch(key)
|
57
57
|
type = types.first
|
58
|
-
Literal.check(
|
58
|
+
Literal.check(value, type) { |c| raise NotImplementedError }
|
59
59
|
|
60
60
|
@indexes.fetch(key)[value]
|
61
61
|
end
|
@@ -71,9 +71,8 @@ class Literal::Enum
|
|
71
71
|
raise ArgumentError.new("You can only use `find_by` on unique indexes.")
|
72
72
|
end
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
end
|
74
|
+
type = @indexes_definitions.fetch(key)[0]
|
75
|
+
Literal.check(value, type)
|
77
76
|
|
78
77
|
@indexes.fetch(key)[value]&.first
|
79
78
|
end
|
data/lib/literal/flags.rb
CHANGED
@@ -219,27 +219,3 @@ class Literal::Flags
|
|
219
219
|
2 ** self.class::FLAGS.fetch(key)
|
220
220
|
end
|
221
221
|
end
|
222
|
-
|
223
|
-
class Literal::Flags8 < Literal::Flags
|
224
|
-
BYTES = 1
|
225
|
-
BITS = BYTES * 8
|
226
|
-
PACKER = "C"
|
227
|
-
end
|
228
|
-
|
229
|
-
class Literal::Flags16 < Literal::Flags
|
230
|
-
BYTES = 2
|
231
|
-
BITS = BYTES * 8
|
232
|
-
PACKER = "S"
|
233
|
-
end
|
234
|
-
|
235
|
-
class Literal::Flags32 < Literal::Flags
|
236
|
-
BYTES = 4
|
237
|
-
BITS = BYTES * 8
|
238
|
-
PACKER = "L"
|
239
|
-
end
|
240
|
-
|
241
|
-
class Literal::Flags64 < Literal::Flags
|
242
|
-
BYTES = 8
|
243
|
-
BITS = BYTES * 8
|
244
|
-
PACKER = "Q"
|
245
|
-
end
|
data/lib/literal/hash.rb
CHANGED
@@ -25,7 +25,7 @@ class Literal::Hash
|
|
25
25
|
def initialize(value, key_type:, value_type:)
|
26
26
|
collection_type = Literal::Types::HashType.new(key_type, value_type)
|
27
27
|
|
28
|
-
Literal.check(
|
28
|
+
Literal.check(value, collection_type) do |c|
|
29
29
|
c.fill_receiver(receiver: self, method: "#initialize")
|
30
30
|
end
|
31
31
|
|
@@ -62,7 +62,7 @@ class Literal::Properties::Schema
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def generate_after_initializer(buffer = +"")
|
65
|
-
buffer << " after_initialize if respond_to?(:after_initialize)\n"
|
65
|
+
buffer << " after_initialize if respond_to?(:after_initialize, true)\n"
|
66
66
|
end
|
67
67
|
|
68
68
|
def generate_to_h(buffer = +"")
|
@@ -96,13 +96,13 @@ class Literal::Properties::Schema
|
|
96
96
|
|
97
97
|
def generate_eq(buffer = +"")
|
98
98
|
buffer << "def ==(other)\n"
|
99
|
-
buffer << " return false unless
|
99
|
+
buffer << " return false unless self.class === other && other.class.literal_properties.size == self.class.literal_properties.size\n"
|
100
100
|
|
101
101
|
sorted_properties = @sorted_properties
|
102
102
|
i, n = 0, sorted_properties.size
|
103
103
|
while i < n
|
104
104
|
property = sorted_properties[i]
|
105
|
-
buffer << "
|
105
|
+
buffer << " @#{property.name.name} == other.instance_variable_get(:@#{property.name.name})"
|
106
106
|
buffer << " &&\n " if i < n - 1
|
107
107
|
i += 1
|
108
108
|
end
|
data/lib/literal/properties.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Literal::Properties
|
4
|
-
autoload :Schema, "literal/properties/schema"
|
5
|
-
autoload :DataSchema, "literal/properties/data_schema"
|
6
|
-
|
7
4
|
include Literal::Types
|
8
5
|
|
9
6
|
module DocString
|
@@ -30,7 +27,7 @@ module Literal::Properties
|
|
30
27
|
end
|
31
28
|
|
32
29
|
unless Literal::Property::VISIBILITY_OPTIONS.include?(predicate)
|
33
|
-
|
30
|
+
raise Literal::ArgumentError.new("The predicate must be one of #{Literal::Property::VISIBILITY_OPTIONS.map(&:inspect).join(', ')}.")
|
34
31
|
end
|
35
32
|
|
36
33
|
if reader && :class == name
|
@@ -57,12 +54,14 @@ module Literal::Properties
|
|
57
54
|
literal_properties << property
|
58
55
|
__define_literal_methods__(property)
|
59
56
|
include(__literal_extension__)
|
57
|
+
|
58
|
+
name
|
60
59
|
end
|
61
60
|
|
62
61
|
def literal_properties
|
63
62
|
return @literal_properties if defined?(@literal_properties)
|
64
63
|
|
65
|
-
if
|
64
|
+
if Literal::Properties === superclass
|
66
65
|
@literal_properties = superclass.literal_properties.dup
|
67
66
|
else
|
68
67
|
@literal_properties = Literal::Properties::Schema.new
|
@@ -90,7 +89,7 @@ module Literal::Properties
|
|
90
89
|
end
|
91
90
|
|
92
91
|
def to_h
|
93
|
-
|
92
|
+
{}
|
94
93
|
end
|
95
94
|
|
96
95
|
set_temporary_name "Literal::Properties(Extension)" if respond_to?(:set_temporary_name)
|
data/lib/literal/property.rb
CHANGED
@@ -97,15 +97,15 @@ class Literal::Property
|
|
97
97
|
def check(value, &)
|
98
98
|
raise ArgumentError.new("Cannot check type without a block") unless block_given?
|
99
99
|
|
100
|
-
Literal.check(
|
100
|
+
Literal.check(value, @type, &)
|
101
101
|
end
|
102
102
|
|
103
103
|
def check_writer(receiver, value)
|
104
|
-
Literal.check(
|
104
|
+
Literal.check(value, @type) { |c| c.fill_receiver(receiver:, method: "##{@name.name}=(value)") }
|
105
105
|
end
|
106
106
|
|
107
107
|
def check_initializer(receiver, value)
|
108
|
-
Literal.check(
|
108
|
+
Literal.check(value, @type) { |c| c.fill_receiver(receiver:, method: "#initialize", label: param) }
|
109
109
|
end
|
110
110
|
|
111
111
|
def generate_reader_method(buffer = +"")
|
data/lib/literal/rails.rb
CHANGED
data/lib/literal/set.rb
CHANGED
@@ -26,7 +26,7 @@ class Literal::Set
|
|
26
26
|
def initialize(value, type:)
|
27
27
|
collection_type = Literal::Types::SetType.new(type)
|
28
28
|
|
29
|
-
Literal.check(
|
29
|
+
Literal.check(value, collection_type) do |c|
|
30
30
|
c.fill_receiver(receiver: self, method: "#initialize")
|
31
31
|
end
|
32
32
|
|
data/lib/literal/transforms.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# A map of core types to transform Procs mapping to the new type.
|
4
|
-
Literal::
|
4
|
+
Literal::Transforms = {
|
5
5
|
Integer => {
|
6
6
|
abs: Integer,
|
7
7
|
ceil: Integer,
|
@@ -140,4 +140,4 @@ Literal::TRANSFORMS = {
|
|
140
140
|
to_s: String,
|
141
141
|
year: Integer,
|
142
142
|
},
|
143
|
-
}.transform_values! { |it| it.transform_keys(&:to_proc) }.freeze
|
143
|
+
}.transform_values! { |it| it.transform_keys(&:to_proc).freeze }.freeze
|
data/lib/literal/tuple.rb
CHANGED
@@ -19,7 +19,7 @@ class Literal::Tuple
|
|
19
19
|
|
20
20
|
i, len = 0, types.size
|
21
21
|
while i < len
|
22
|
-
return false unless Literal.subtype?(other_types[i],
|
22
|
+
return false unless Literal.subtype?(other_types[i], types[i])
|
23
23
|
i += 1
|
24
24
|
end
|
25
25
|
|
@@ -36,7 +36,7 @@ class Literal::Tuple
|
|
36
36
|
|
37
37
|
i, len = 0, types.size
|
38
38
|
while i < len
|
39
|
-
return false unless Literal.subtype?(other_types[i],
|
39
|
+
return false unless Literal.subtype?(other_types[i], types[i])
|
40
40
|
i += 1
|
41
41
|
end
|
42
42
|
|
@@ -6,6 +6,7 @@ class Literal::Types::ClassType
|
|
6
6
|
|
7
7
|
def initialize(type)
|
8
8
|
@type = type
|
9
|
+
freeze
|
9
10
|
end
|
10
11
|
|
11
12
|
attr_reader :type
|
@@ -21,9 +22,9 @@ class Literal::Types::ClassType
|
|
21
22
|
def >=(other)
|
22
23
|
case other
|
23
24
|
when Literal::Types::ClassType
|
24
|
-
Literal.subtype?(other.type,
|
25
|
+
Literal.subtype?(other.type, @type)
|
25
26
|
when Literal::Types::DescendantType
|
26
|
-
(Class === other.type) && Literal.subtype?(other.type,
|
27
|
+
(Class === other.type) && Literal.subtype?(other.type, @type)
|
27
28
|
else
|
28
29
|
false
|
29
30
|
end
|
@@ -7,6 +7,7 @@ class Literal::Types::ConstraintType
|
|
7
7
|
def initialize(*object_constraints, **property_constraints)
|
8
8
|
@object_constraints = object_constraints
|
9
9
|
@property_constraints = property_constraints
|
10
|
+
freeze
|
10
11
|
end
|
11
12
|
|
12
13
|
attr_reader :object_constraints
|
@@ -45,24 +46,24 @@ class Literal::Types::ConstraintType
|
|
45
46
|
when Literal::Types::ConstraintType
|
46
47
|
other_object_constraints = other.object_constraints
|
47
48
|
return false unless @object_constraints.all? do |constraint|
|
48
|
-
other_object_constraints.any? { |c| Literal.subtype?(c,
|
49
|
+
other_object_constraints.any? { |c| Literal.subtype?(c, constraint) }
|
49
50
|
end
|
50
51
|
|
51
52
|
other_property_constraints = other.property_constraints
|
52
53
|
return false unless @property_constraints.all? do |k, v|
|
53
|
-
Literal.subtype?(other_property_constraints[k],
|
54
|
+
Literal.subtype?(other_property_constraints[k], v)
|
54
55
|
end
|
55
56
|
|
56
57
|
true
|
57
58
|
when Literal::Types::IntersectionType
|
58
59
|
other_object_constraints = other.types
|
59
60
|
return false unless @object_constraints.all? do |constraint|
|
60
|
-
other_object_constraints.any? { |c| Literal.subtype?(c,
|
61
|
+
other_object_constraints.any? { |c| Literal.subtype?(c, constraint) }
|
61
62
|
end
|
62
63
|
|
63
64
|
true
|
64
65
|
when Literal::Types::FrozenType
|
65
|
-
@object_constraints.all? { |constraint| Literal.subtype?(other.type,
|
66
|
+
@object_constraints.all? { |constraint| Literal.subtype?(other.type, constraint) }
|
66
67
|
else
|
67
68
|
false
|
68
69
|
end
|
@@ -5,6 +5,7 @@ class Literal::Types::DescendantType
|
|
5
5
|
|
6
6
|
def initialize(type)
|
7
7
|
@type = type
|
8
|
+
freeze
|
8
9
|
end
|
9
10
|
|
10
11
|
attr_reader :type
|
@@ -20,7 +21,7 @@ class Literal::Types::DescendantType
|
|
20
21
|
def >=(other)
|
21
22
|
case other
|
22
23
|
when Literal::Types::DescendantType, Literal::Types::ClassType
|
23
|
-
Literal.subtype?(other.type,
|
24
|
+
Literal.subtype?(other.type, @type)
|
24
25
|
else
|
25
26
|
false
|
26
27
|
end
|
@@ -6,6 +6,7 @@ class Literal::Types::EnumerableType
|
|
6
6
|
|
7
7
|
def initialize(type)
|
8
8
|
@type = type
|
9
|
+
freeze
|
9
10
|
end
|
10
11
|
|
11
12
|
attr_reader :type
|
@@ -21,7 +22,7 @@ class Literal::Types::EnumerableType
|
|
21
22
|
def >=(other)
|
22
23
|
case other
|
23
24
|
when Literal::Types::EnumerableType
|
24
|
-
Literal.subtype?(other.type,
|
25
|
+
Literal.subtype?(other.type, @type)
|
25
26
|
else
|
26
27
|
false
|
27
28
|
end
|
@@ -12,6 +12,7 @@ class Literal::Types::FrozenType
|
|
12
12
|
end
|
13
13
|
|
14
14
|
@type = type
|
15
|
+
freeze
|
15
16
|
end
|
16
17
|
|
17
18
|
attr_reader :type
|
@@ -30,11 +31,11 @@ class Literal::Types::FrozenType
|
|
30
31
|
@type >= other.type
|
31
32
|
when Literal::Types::ConstraintType
|
32
33
|
type_match = false
|
33
|
-
frozen_match = Literal.subtype?(other.property_constraints[:frozen?],
|
34
|
+
frozen_match = Literal.subtype?(other.property_constraints[:frozen?], true)
|
34
35
|
|
35
36
|
other.object_constraints.each do |constraint|
|
36
37
|
frozen_match ||= ALWAYS_FROZEN.include?(constraint)
|
37
|
-
type_match ||= Literal.subtype?(constraint,
|
38
|
+
type_match ||= Literal.subtype?(constraint, @type)
|
38
39
|
return true if frozen_match && type_match
|
39
40
|
end
|
40
41
|
|
@@ -7,6 +7,7 @@ class Literal::Types::HashType
|
|
7
7
|
def initialize(key_type, value_type)
|
8
8
|
@key_type = key_type
|
9
9
|
@value_type = value_type
|
10
|
+
freeze
|
10
11
|
end
|
11
12
|
|
12
13
|
attr_reader :key_type, :value_type
|
@@ -29,9 +30,9 @@ class Literal::Types::HashType
|
|
29
30
|
case other
|
30
31
|
when Literal::Types::HashType
|
31
32
|
(
|
32
|
-
Literal.subtype?(other.key_type,
|
33
|
+
Literal.subtype?(other.key_type, @key_type)
|
33
34
|
) && (
|
34
|
-
Literal.subtype?(other.value_type,
|
35
|
+
Literal.subtype?(other.value_type, @value_type)
|
35
36
|
)
|
36
37
|
else
|
37
38
|
false
|
@@ -2,18 +2,15 @@
|
|
2
2
|
|
3
3
|
# @api private
|
4
4
|
class Literal::Types::InterfaceType
|
5
|
-
# TODO: We can generate this and make it much more extensive.
|
6
|
-
METHOD_TYPE_MAPPINGS = {
|
7
|
-
:call => Set[Proc, Method],
|
8
|
-
:to_proc => Set[Proc, Method],
|
9
|
-
:to_s => Set[String],
|
10
|
-
}.freeze
|
11
|
-
|
12
5
|
include Literal::Type
|
13
6
|
|
7
|
+
# List of `===` method owners where the comparison will only match for objects with the same class
|
8
|
+
OwnClassTypeMethodOwners = Set[String, Integer, Kernel, Float, NilClass, TrueClass, FalseClass].freeze
|
9
|
+
|
14
10
|
def initialize(*methods)
|
15
11
|
raise Literal::ArgumentError.new("_Interface type must have at least one method.") if methods.size < 1
|
16
|
-
@methods = methods
|
12
|
+
@methods = methods.to_set.freeze
|
13
|
+
freeze
|
17
14
|
end
|
18
15
|
|
19
16
|
attr_reader :methods
|
@@ -23,21 +20,30 @@ class Literal::Types::InterfaceType
|
|
23
20
|
end
|
24
21
|
|
25
22
|
def ===(value)
|
26
|
-
@methods.
|
23
|
+
@methods.each do |method|
|
24
|
+
return false unless value.respond_to?(method)
|
25
|
+
end
|
26
|
+
|
27
|
+
true
|
27
28
|
end
|
28
29
|
|
29
30
|
def >=(other)
|
30
31
|
case other
|
31
32
|
when Literal::Types::InterfaceType
|
32
|
-
@methods.
|
33
|
+
@methods.subset?(other.methods)
|
33
34
|
when Module
|
34
|
-
|
35
|
+
public_methods = other.public_instance_methods.to_set
|
36
|
+
@methods.subset?(public_methods)
|
35
37
|
when Literal::Types::IntersectionType
|
36
|
-
other.types.any? { |type| Literal.subtype?(type,
|
38
|
+
other.types.any? { |type| Literal.subtype?(type, self) }
|
37
39
|
when Literal::Types::ConstraintType
|
38
|
-
other.object_constraints.any? { |type| Literal.subtype?(type,
|
40
|
+
other.object_constraints.any? { |type| Literal.subtype?(type, self) }
|
39
41
|
else
|
40
|
-
|
42
|
+
if OwnClassTypeMethodOwners.include?(other.method(:===).owner)
|
43
|
+
self === other
|
44
|
+
else
|
45
|
+
false
|
46
|
+
end
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|