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.
- checksums.yaml +4 -4
- data/lib/literal/array.rb +544 -0
- data/lib/literal/data_structure.rb +0 -10
- data/lib/literal/deferred_type.rb +23 -0
- data/lib/literal/flags.rb +17 -4
- data/lib/literal/hash.rb +48 -0
- data/lib/literal/properties/schema.rb +2 -2
- data/lib/literal/properties.rb +5 -0
- data/lib/literal/property.rb +1 -1
- data/lib/literal/rails/flags_type.rb +41 -0
- data/lib/literal/rails.rb +1 -0
- data/lib/literal/railtie.rb +8 -0
- data/lib/literal/set.rb +48 -0
- data/lib/literal/struct.rb +26 -0
- data/lib/literal/transforms.rb +142 -0
- data/lib/literal/type.rb +7 -0
- data/lib/literal/types/any_type.rb +13 -3
- data/lib/literal/types/array_type.rb +18 -1
- data/lib/literal/types/boolean_type.rb +18 -3
- data/lib/literal/types/class_type.rb +20 -1
- data/lib/literal/types/constraint_type.rb +42 -1
- data/lib/literal/types/descendant_type.rb +18 -1
- data/lib/literal/types/enumerable_type.rb +18 -1
- data/lib/literal/types/falsy_type.rb +22 -3
- data/lib/literal/types/frozen_type.rb +35 -1
- data/lib/literal/types/hash_type.rb +22 -1
- data/lib/literal/types/interface_type.rb +31 -1
- data/lib/literal/types/intersection_type.rb +27 -0
- data/lib/literal/types/json_data_type.rb +49 -3
- data/lib/literal/types/map_type.rb +23 -5
- data/lib/literal/types/never_type.rb +18 -3
- data/lib/literal/types/nilable_type.rb +24 -1
- data/lib/literal/types/not_type.rb +22 -1
- data/lib/literal/types/range_type.rb +18 -1
- data/lib/literal/types/set_type.rb +28 -1
- data/lib/literal/types/truthy_type.rb +17 -3
- data/lib/literal/types/tuple_type.rb +19 -2
- data/lib/literal/types/union_type.rb +27 -3
- data/lib/literal/types/void_type.rb +13 -3
- data/lib/literal/types.rb +58 -51
- data/lib/literal/version.rb +1 -1
- data/lib/literal.rb +38 -5
- metadata +9 -9
- data/lib/literal/types/callable_type.rb +0 -12
- data/lib/literal/types/float_type.rb +0 -10
- data/lib/literal/types/integer_type.rb +0 -10
- data/lib/literal/types/lambda_type.rb +0 -12
- data/lib/literal/types/procable_type.rb +0 -12
- data/lib/literal/types/string_type.rb +0 -10
- data/lib/literal/types/symbol_type.rb +0 -10
data/lib/literal/property.rb
CHANGED
@@ -157,7 +157,7 @@ class Literal::Property
|
|
157
157
|
|
158
158
|
def generate_initializer_handle_property(buffer = +"")
|
159
159
|
buffer << " # " << @name.name << "\n" <<
|
160
|
-
" property =
|
160
|
+
" property = __properties__[:" << @name.name << "]\n"
|
161
161
|
|
162
162
|
if @kind == :keyword && ruby_keyword?
|
163
163
|
generate_initializer_escape_keyword(buffer)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Literal::Rails::FlagsType < ActiveModel::Type::Value
|
4
|
+
def initialize(flags_class)
|
5
|
+
@flags_class = flags_class
|
6
|
+
super()
|
7
|
+
end
|
8
|
+
|
9
|
+
def cast(value)
|
10
|
+
case value
|
11
|
+
when @flags_class
|
12
|
+
value
|
13
|
+
else
|
14
|
+
deserialize(value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def serialize(value)
|
19
|
+
case value
|
20
|
+
when nil
|
21
|
+
nil
|
22
|
+
when @flags_class
|
23
|
+
value.to_bit_string
|
24
|
+
else
|
25
|
+
raise Literal::ArgumentError.new(
|
26
|
+
"Invalid value: #{value.inspect}. Expected an #{@flags_class.inspect}.",
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def deserialize(value)
|
32
|
+
case value
|
33
|
+
when nil
|
34
|
+
nil
|
35
|
+
else
|
36
|
+
@flags_class.from_bit_string(value) || raise(
|
37
|
+
ArgumentError.new("Invalid value: #{value.inspect} for #{@flags_class}"),
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/literal/rails.rb
CHANGED
data/lib/literal/railtie.rb
CHANGED
@@ -6,8 +6,16 @@ class Literal::Railtie < Rails::Railtie
|
|
6
6
|
Literal::Rails::EnumType.new(type)
|
7
7
|
end
|
8
8
|
|
9
|
+
ActiveRecord::Type.register(:literal_flags) do |name, type:|
|
10
|
+
Literal::Rails::FlagsType.new(type)
|
11
|
+
end
|
12
|
+
|
9
13
|
ActiveModel::Type.register(:literal_enum) do |name, type:|
|
10
14
|
Literal::Rails::EnumType.new(type)
|
11
15
|
end
|
16
|
+
|
17
|
+
ActiveModel::Type.register(:literal_flags) do |name, type:|
|
18
|
+
Literal::Rails::FlagsType.new(type)
|
19
|
+
end
|
12
20
|
end
|
13
21
|
end
|
data/lib/literal/set.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Literal::Set
|
4
|
+
class Generic
|
5
|
+
def initialize(type)
|
6
|
+
@type = type
|
7
|
+
end
|
8
|
+
|
9
|
+
def new(*value)
|
10
|
+
Literal::Set.new(value.to_set, type: @type)
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :[], :new
|
14
|
+
|
15
|
+
def ===(value)
|
16
|
+
Literal::Set === value && @type == value.__type__
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"Literal::Set(#{@type.inspect})"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
include Enumerable
|
25
|
+
|
26
|
+
def initialize(value, type:)
|
27
|
+
collection_type = Literal::Types::SetType.new(type)
|
28
|
+
|
29
|
+
Literal.check(actual: value, expected: collection_type) do |c|
|
30
|
+
c.fill_receiver(receiver: self, method: "#initialize")
|
31
|
+
end
|
32
|
+
|
33
|
+
@__type__ = type
|
34
|
+
@__value__ = value
|
35
|
+
@__collection_type__ = collection_type
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :__type__, :__value__
|
39
|
+
|
40
|
+
def freeze
|
41
|
+
@__value__.freeze
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def each(...)
|
46
|
+
@__value__.each(...)
|
47
|
+
end
|
48
|
+
end
|
data/lib/literal/struct.rb
CHANGED
@@ -6,4 +6,30 @@ class Literal::Struct < Literal::DataStructure
|
|
6
6
|
super
|
7
7
|
end
|
8
8
|
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
case key
|
12
|
+
when Symbol
|
13
|
+
when String
|
14
|
+
key = key.intern
|
15
|
+
else
|
16
|
+
raise TypeError.new("expected a string or symbol, got #{key.inspect.class}")
|
17
|
+
end
|
18
|
+
|
19
|
+
prop = self.class.literal_properties[key] || raise(NameError.new("unknown attribute: #{key.inspect} for #{self.class}"))
|
20
|
+
__send__(prop.name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(key, value)
|
24
|
+
case key
|
25
|
+
when Symbol
|
26
|
+
when String
|
27
|
+
key = key.intern
|
28
|
+
else
|
29
|
+
raise TypeError.new("expected a string or symbol, got #{key.inspect.class}")
|
30
|
+
end
|
31
|
+
|
32
|
+
prop = self.class.literal_properties[key] || raise(NameError.new("unknown attribute: #{key.inspect} for #{self.class}"))
|
33
|
+
__send__(:"#{prop.name}=", value)
|
34
|
+
end
|
9
35
|
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# A map of core types to transform Procs mapping to the new type.
|
4
|
+
Literal::TRANSFORMS = {
|
5
|
+
Integer => {
|
6
|
+
abs: Integer,
|
7
|
+
ceil: Integer,
|
8
|
+
chr: String,
|
9
|
+
denominator: Integer,
|
10
|
+
even?: Literal::Types::BooleanType::Instance,
|
11
|
+
floor: Integer,
|
12
|
+
hash: Integer,
|
13
|
+
inspect: String,
|
14
|
+
integer?: true,
|
15
|
+
magnitude: Integer,
|
16
|
+
negative?: Literal::Types::BooleanType::Instance,
|
17
|
+
next: Integer,
|
18
|
+
numerator: Integer,
|
19
|
+
odd?: Literal::Types::BooleanType::Instance,
|
20
|
+
ord: Integer,
|
21
|
+
positive?: Literal::Types::BooleanType::Instance,
|
22
|
+
pred: Integer,
|
23
|
+
round: Integer,
|
24
|
+
size: Integer,
|
25
|
+
succ: Integer,
|
26
|
+
to_f: Float,
|
27
|
+
to_i: Integer,
|
28
|
+
to_int: Integer,
|
29
|
+
to_r: Rational,
|
30
|
+
to_s: String,
|
31
|
+
truncate: Integer,
|
32
|
+
zero?: Literal::Types::BooleanType::Instance,
|
33
|
+
},
|
34
|
+
String => {
|
35
|
+
ascii_only?: Literal::Types::BooleanType::Instance,
|
36
|
+
bytesize: Integer,
|
37
|
+
capitalize: String,
|
38
|
+
chomp: String,
|
39
|
+
chop: String,
|
40
|
+
downcase: String,
|
41
|
+
dump: String,
|
42
|
+
empty?: Literal::Types::BooleanType::Instance,
|
43
|
+
hash: Integer,
|
44
|
+
inspect: String,
|
45
|
+
length: Integer,
|
46
|
+
lstrip: String,
|
47
|
+
ord: Integer,
|
48
|
+
reverse: String,
|
49
|
+
rstrip: String,
|
50
|
+
scrub: String,
|
51
|
+
size: Integer,
|
52
|
+
strip: String,
|
53
|
+
swapcase: String,
|
54
|
+
to_str: String,
|
55
|
+
upcase: String,
|
56
|
+
valid_encoding?: Literal::Types::BooleanType::Instance,
|
57
|
+
},
|
58
|
+
Numeric => {
|
59
|
+
to_i: Integer,
|
60
|
+
to_f: Float,
|
61
|
+
to_s: String,
|
62
|
+
},
|
63
|
+
Array => {
|
64
|
+
size: Integer,
|
65
|
+
length: Integer,
|
66
|
+
empty?: Literal::Types::BooleanType::Instance,
|
67
|
+
sort: Array,
|
68
|
+
to_a: Array,
|
69
|
+
to_ary: Array,
|
70
|
+
},
|
71
|
+
Hash => {
|
72
|
+
empty?: Literal::Types::BooleanType::Instance,
|
73
|
+
inspect: String,
|
74
|
+
keys: Array,
|
75
|
+
length: Integer,
|
76
|
+
size: Integer,
|
77
|
+
to_a: Array,
|
78
|
+
to_h: Hash,
|
79
|
+
to_s: String,
|
80
|
+
values: Array,
|
81
|
+
},
|
82
|
+
Set => {
|
83
|
+
empty?: Literal::Types::BooleanType::Instance,
|
84
|
+
inspect: String,
|
85
|
+
length: Integer,
|
86
|
+
size: Integer,
|
87
|
+
to_a: Array,
|
88
|
+
to_s: String,
|
89
|
+
},
|
90
|
+
Float => {
|
91
|
+
abs: Float,
|
92
|
+
ceil: Integer,
|
93
|
+
floor: Integer,
|
94
|
+
nan?: Literal::Types::BooleanType::Instance,
|
95
|
+
negative?: Literal::Types::BooleanType::Instance,
|
96
|
+
positive?: Literal::Types::BooleanType::Instance,
|
97
|
+
round: Integer,
|
98
|
+
to_i: Integer,
|
99
|
+
to_s: String,
|
100
|
+
truncate: Integer,
|
101
|
+
zero?: Literal::Types::BooleanType::Instance,
|
102
|
+
},
|
103
|
+
Symbol => {
|
104
|
+
empty?: Literal::Types::BooleanType::Instance,
|
105
|
+
inspect: String,
|
106
|
+
length: Integer,
|
107
|
+
size: Integer,
|
108
|
+
to_s: String,
|
109
|
+
to_sym: Symbol,
|
110
|
+
},
|
111
|
+
Range => {
|
112
|
+
begin: Object,
|
113
|
+
end: Object,
|
114
|
+
exclude_end?: Literal::Types::BooleanType::Instance,
|
115
|
+
first: Object,
|
116
|
+
last: Object,
|
117
|
+
max: Object,
|
118
|
+
min: Object,
|
119
|
+
size: Integer,
|
120
|
+
to_a: Array,
|
121
|
+
to_s: String,
|
122
|
+
},
|
123
|
+
Regexp => {
|
124
|
+
casefold?: Literal::Types::BooleanType::Instance,
|
125
|
+
inspect: String,
|
126
|
+
source: String,
|
127
|
+
to_s: String,
|
128
|
+
},
|
129
|
+
Time => {
|
130
|
+
day: Integer,
|
131
|
+
hour: Integer,
|
132
|
+
inspect: String,
|
133
|
+
min: Integer,
|
134
|
+
month: Integer,
|
135
|
+
sec: Integer,
|
136
|
+
to_a: Array,
|
137
|
+
to_f: Float,
|
138
|
+
to_i: Integer,
|
139
|
+
to_s: String,
|
140
|
+
year: Integer,
|
141
|
+
},
|
142
|
+
}.transform_values! { |it| it.transform_keys(&:to_proc) }.freeze
|
data/lib/literal/type.rb
ADDED
@@ -1,12 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# @api private
|
4
|
-
|
5
|
-
|
4
|
+
class Literal::Types::AnyType
|
5
|
+
Instance = new.freeze
|
6
6
|
|
7
|
-
|
7
|
+
include Literal::Type
|
8
|
+
|
9
|
+
def inspect
|
10
|
+
"_Any"
|
11
|
+
end
|
12
|
+
|
13
|
+
def ===(value)
|
8
14
|
!(nil === value)
|
9
15
|
end
|
10
16
|
|
17
|
+
def >=(other)
|
18
|
+
!(other === nil)
|
19
|
+
end
|
20
|
+
|
11
21
|
freeze
|
12
22
|
end
|
@@ -2,16 +2,31 @@
|
|
2
2
|
|
3
3
|
# @api private
|
4
4
|
class Literal::Types::ArrayType
|
5
|
+
include Literal::Type
|
6
|
+
|
5
7
|
def initialize(type)
|
6
8
|
@type = type
|
7
9
|
end
|
8
10
|
|
9
|
-
|
11
|
+
attr_reader :type
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
"_Array(#{@type.inspect})"
|
15
|
+
end
|
10
16
|
|
11
17
|
def ===(value)
|
12
18
|
Array === value && value.all?(@type)
|
13
19
|
end
|
14
20
|
|
21
|
+
def >=(other)
|
22
|
+
case other
|
23
|
+
when Literal::Types::ArrayType
|
24
|
+
@type >= other.type
|
25
|
+
else
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
15
30
|
def record_literal_type_errors(context)
|
16
31
|
unless Array === context.actual
|
17
32
|
return
|
@@ -23,4 +38,6 @@ class Literal::Types::ArrayType
|
|
23
38
|
end
|
24
39
|
end
|
25
40
|
end
|
41
|
+
|
42
|
+
freeze
|
26
43
|
end
|
@@ -1,12 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# @api private
|
4
|
-
|
5
|
-
|
4
|
+
class Literal::Types::BooleanType
|
5
|
+
Instance = new.freeze
|
6
6
|
|
7
|
-
|
7
|
+
include Literal::Type
|
8
|
+
|
9
|
+
def inspect
|
10
|
+
"_Boolean"
|
11
|
+
end
|
12
|
+
|
13
|
+
def ===(value)
|
8
14
|
true == value || false == value
|
9
15
|
end
|
10
16
|
|
17
|
+
def >=(other)
|
18
|
+
case other
|
19
|
+
when true, false, Literal::Types::BooleanType
|
20
|
+
true
|
21
|
+
else
|
22
|
+
false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
11
26
|
freeze
|
12
27
|
end
|
@@ -2,13 +2,32 @@
|
|
2
2
|
|
3
3
|
# @api private
|
4
4
|
class Literal::Types::ClassType
|
5
|
+
include Literal::Type
|
6
|
+
|
5
7
|
def initialize(type)
|
6
8
|
@type = type
|
7
9
|
end
|
8
10
|
|
9
|
-
|
11
|
+
attr_reader :type
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
"_Class(#{@type.name})"
|
15
|
+
end
|
10
16
|
|
11
17
|
def ===(value)
|
12
18
|
Class === value && (value == @type || value < @type)
|
13
19
|
end
|
20
|
+
|
21
|
+
def >=(other)
|
22
|
+
case other
|
23
|
+
when Literal::Types::ClassType
|
24
|
+
Literal.subtype?(other.type, of: @type)
|
25
|
+
when Literal::Types::DescendantType
|
26
|
+
(Class === other.type) && Literal.subtype?(other.type, of: @type)
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
freeze
|
14
33
|
end
|
@@ -2,12 +2,19 @@
|
|
2
2
|
|
3
3
|
# @api private
|
4
4
|
class Literal::Types::ConstraintType
|
5
|
+
include Literal::Type
|
6
|
+
|
5
7
|
def initialize(*object_constraints, **property_constraints)
|
6
8
|
@object_constraints = object_constraints
|
7
9
|
@property_constraints = property_constraints
|
8
10
|
end
|
9
11
|
|
10
|
-
|
12
|
+
attr_reader :object_constraints
|
13
|
+
attr_reader :property_constraints
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"_Constraint(#{inspect_constraints})"
|
17
|
+
end
|
11
18
|
|
12
19
|
def ===(value)
|
13
20
|
object_constraints = @object_constraints
|
@@ -20,11 +27,42 @@ class Literal::Types::ConstraintType
|
|
20
27
|
|
21
28
|
@property_constraints.each do |a, t|
|
22
29
|
return false unless t === value.public_send(a)
|
30
|
+
rescue NoMethodError => e
|
31
|
+
raise unless e.name == a && e.receiver == value
|
32
|
+
return false
|
23
33
|
end
|
24
34
|
|
25
35
|
true
|
26
36
|
end
|
27
37
|
|
38
|
+
def >=(other)
|
39
|
+
case other
|
40
|
+
when Literal::Types::ConstraintType
|
41
|
+
other_object_constraints = other.object_constraints
|
42
|
+
return false unless @object_constraints.all? do |constraint|
|
43
|
+
other_object_constraints.any? { |c| Literal.subtype?(c, of: constraint) }
|
44
|
+
end
|
45
|
+
|
46
|
+
other_property_constraints = other.property_constraints
|
47
|
+
return false unless @property_constraints.all? do |k, v|
|
48
|
+
Literal.subtype?(other_property_constraints[k], of: v)
|
49
|
+
end
|
50
|
+
|
51
|
+
true
|
52
|
+
when Literal::Types::IntersectionType
|
53
|
+
other_object_constraints = other.types
|
54
|
+
return false unless @object_constraints.all? do |constraint|
|
55
|
+
other_object_constraints.any? { |c| Literal.subtype?(c, of: constraint) }
|
56
|
+
end
|
57
|
+
|
58
|
+
true
|
59
|
+
when Literal::Types::FrozenType
|
60
|
+
@object_constraints.all? { |constraint| Literal.subtype?(other.type, of: constraint) }
|
61
|
+
else
|
62
|
+
false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
28
66
|
def record_literal_type_errors(context)
|
29
67
|
@object_constraints.each do |constraint|
|
30
68
|
next if constraint === context.actual
|
@@ -33,6 +71,7 @@ class Literal::Types::ConstraintType
|
|
33
71
|
end
|
34
72
|
|
35
73
|
@property_constraints.each do |property, constraint|
|
74
|
+
next unless context.actual.respond_to?(property)
|
36
75
|
actual = context.actual.public_send(property)
|
37
76
|
next if constraint === actual
|
38
77
|
|
@@ -57,4 +96,6 @@ class Literal::Types::ConstraintType
|
|
57
96
|
@property_constraints.map { |k, t| "#{k}: #{t.inspect}" }.join(", ")
|
58
97
|
end
|
59
98
|
end
|
99
|
+
|
100
|
+
freeze
|
60
101
|
end
|
@@ -1,13 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Literal::Types::DescendantType
|
4
|
+
include Literal::Type
|
5
|
+
|
4
6
|
def initialize(type)
|
5
7
|
@type = type
|
6
8
|
end
|
7
9
|
|
8
|
-
|
10
|
+
attr_reader :type
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
"_Descendant(#{@type})"
|
14
|
+
end
|
9
15
|
|
10
16
|
def ===(value)
|
11
17
|
Module === value && value < @type
|
12
18
|
end
|
19
|
+
|
20
|
+
def >=(other)
|
21
|
+
case other
|
22
|
+
when Literal::Types::DescendantType, Literal::Types::ClassType
|
23
|
+
Literal.subtype?(other.type, of: @type)
|
24
|
+
else
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
freeze
|
13
30
|
end
|
@@ -2,13 +2,30 @@
|
|
2
2
|
|
3
3
|
# @api private
|
4
4
|
class Literal::Types::EnumerableType
|
5
|
+
include Literal::Type
|
6
|
+
|
5
7
|
def initialize(type)
|
6
8
|
@type = type
|
7
9
|
end
|
8
10
|
|
9
|
-
|
11
|
+
attr_reader :type
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
"_Enumerable(#{@type.inspect})"
|
15
|
+
end
|
10
16
|
|
11
17
|
def ===(value)
|
12
18
|
Enumerable === value && value.all?(@type)
|
13
19
|
end
|
20
|
+
|
21
|
+
def >=(other)
|
22
|
+
case other
|
23
|
+
when Literal::Types::EnumerableType
|
24
|
+
Literal.subtype?(other.type, of: @type)
|
25
|
+
else
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
freeze
|
14
31
|
end
|
@@ -1,12 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# @api private
|
4
|
-
|
5
|
-
|
4
|
+
class Literal::Types::FalsyType
|
5
|
+
Instance = new.freeze
|
6
6
|
|
7
|
-
|
7
|
+
include Literal::Type
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
"_Falsy"
|
15
|
+
end
|
16
|
+
|
17
|
+
def ===(value)
|
8
18
|
!value
|
9
19
|
end
|
10
20
|
|
21
|
+
def >=(other)
|
22
|
+
case other
|
23
|
+
when Literal::Types::FalsyType, nil, false
|
24
|
+
true
|
25
|
+
else
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
11
30
|
freeze
|
12
31
|
end
|
@@ -2,13 +2,47 @@
|
|
2
2
|
|
3
3
|
# @api private
|
4
4
|
class Literal::Types::FrozenType
|
5
|
+
ALWAYS_FROZEN = Set[Symbol, Integer, Float, Numeric, true, false, nil].freeze
|
6
|
+
|
7
|
+
include Literal::Type
|
8
|
+
|
5
9
|
def initialize(type)
|
10
|
+
if ALWAYS_FROZEN.include?(type)
|
11
|
+
warn "_Frozen type is redundant for #{type.inspect} since it is always frozen."
|
12
|
+
end
|
13
|
+
|
6
14
|
@type = type
|
7
15
|
end
|
8
16
|
|
9
|
-
|
17
|
+
attr_reader :type
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"_Frozen(#{@type.inspect})"
|
21
|
+
end
|
10
22
|
|
11
23
|
def ===(value)
|
12
24
|
value.frozen? && @type === value
|
13
25
|
end
|
26
|
+
|
27
|
+
def >=(other)
|
28
|
+
case other
|
29
|
+
when Literal::Types::FrozenType
|
30
|
+
@type >= other.type
|
31
|
+
when Literal::Types::ConstraintType
|
32
|
+
type_match = false
|
33
|
+
frozen_match = Literal.subtype?(other.property_constraints[:frozen?], of: true)
|
34
|
+
|
35
|
+
other.object_constraints.each do |constraint|
|
36
|
+
frozen_match ||= ALWAYS_FROZEN.include?(constraint)
|
37
|
+
type_match ||= Literal.subtype?(constraint, of: @type)
|
38
|
+
return true if frozen_match && type_match
|
39
|
+
end
|
40
|
+
|
41
|
+
false
|
42
|
+
else
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
freeze
|
14
48
|
end
|