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