literal 1.4.0 → 1.6.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/README.md +1 -1
- data/lib/literal/array.rb +124 -2
- data/lib/literal/enum.rb +76 -34
- data/lib/literal/failure.rb +7 -0
- data/lib/literal/null.rb +4 -0
- data/lib/literal/properties/schema.rb +1 -1
- data/lib/literal/properties.rb +2 -2
- data/lib/literal/property.rb +13 -27
- data/lib/literal/rails/enum_type.rb +9 -11
- data/lib/literal/rails/patches/active_record.rb +4 -3
- data/lib/literal/railtie.rb +8 -14
- data/lib/literal/result.rb +4 -0
- data/lib/literal/success.rb +7 -0
- data/lib/literal/transforms.rb +1 -0
- data/lib/literal/tuple.rb +12 -0
- data/lib/literal/types/array_type.rb +1 -0
- data/lib/literal/types/class_type.rb +1 -0
- data/lib/literal/types/constraint_type.rb +8 -2
- data/lib/literal/types/descendant_type.rb +1 -0
- data/lib/literal/types/enumerable_type.rb +1 -0
- data/lib/literal/types/frozen_type.rb +1 -0
- data/lib/literal/types/hash_type.rb +1 -0
- data/lib/literal/types/interface_type.rb +1 -0
- data/lib/literal/types/intersection_type.rb +1 -0
- data/lib/literal/types/map_type.rb +1 -0
- data/lib/literal/types/nilable_type.rb +1 -0
- data/lib/literal/types/not_type.rb +1 -0
- data/lib/literal/types/range_type.rb +1 -0
- data/lib/literal/types/set_type.rb +1 -0
- data/lib/literal/types/tuple_type.rb +1 -0
- data/lib/literal/types/union_type.rb +46 -25
- data/lib/literal/types.rb +164 -61
- data/lib/literal/version.rb +1 -1
- data/lib/literal.rb +26 -8
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98bc237de806f82733e8c812bccc840c5451183afd22f369ecffc6720c3b88ba
|
4
|
+
data.tar.gz: b340a2c25c5d23d033a83dbf3ab1483a9b071424f343f0edf5c104bee83402c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17b16bdea93b6dff73b9fdcbdd269053648e996f3e2b5d6773933710281b756a50eb93684d727b46711aef990858985111f9d59d80250d20a3f71963767032ca
|
7
|
+
data.tar.gz: 67647cf3e25cdbdbdb12638081a7cbd40b5bee6771d9be54ca4100646740a97989259f24242b60064c41b016c7687d91a3969632d2195a0715c6015bede8e839
|
data/README.md
CHANGED
data/lib/literal/array.rb
CHANGED
@@ -32,6 +32,19 @@ class Literal::Array
|
|
32
32
|
def inspect
|
33
33
|
"Literal::Array(#{@type.inspect})"
|
34
34
|
end
|
35
|
+
|
36
|
+
def coerce(value)
|
37
|
+
case value
|
38
|
+
when self
|
39
|
+
value
|
40
|
+
when Array
|
41
|
+
Literal::Array.new(value, type: @type)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_proc
|
46
|
+
method(:coerce).to_proc
|
47
|
+
end
|
35
48
|
end
|
36
49
|
|
37
50
|
include Enumerable
|
@@ -224,6 +237,10 @@ class Literal::Array
|
|
224
237
|
@__value__.each(...)
|
225
238
|
end
|
226
239
|
|
240
|
+
def each_index(...)
|
241
|
+
@__value__.each_index(...)
|
242
|
+
end
|
243
|
+
|
227
244
|
def empty?
|
228
245
|
@__value__.empty?
|
229
246
|
end
|
@@ -276,7 +293,7 @@ class Literal::Array
|
|
276
293
|
end
|
277
294
|
|
278
295
|
def inspect
|
279
|
-
@__value__.inspect
|
296
|
+
"Literal::Array(#{@__type__.inspect})#{@__value__.inspect}"
|
280
297
|
end
|
281
298
|
|
282
299
|
def intersect?(other)
|
@@ -497,6 +514,7 @@ class Literal::Array
|
|
497
514
|
|
498
515
|
def select!(...)
|
499
516
|
@__value__.select!(...)
|
517
|
+
self
|
500
518
|
end
|
501
519
|
|
502
520
|
def shift(...)
|
@@ -525,17 +543,50 @@ class Literal::Array
|
|
525
543
|
self
|
526
544
|
end
|
527
545
|
|
546
|
+
def sort_by!(...)
|
547
|
+
@__value__.sort_by!(...)
|
548
|
+
self
|
549
|
+
end
|
550
|
+
|
528
551
|
def take(...)
|
529
552
|
__with__(@__value__.take(...))
|
530
553
|
end
|
531
554
|
|
555
|
+
def take_while(...)
|
556
|
+
__with__(@__value__.take_while(...))
|
557
|
+
end
|
558
|
+
|
559
|
+
def transpose
|
560
|
+
case @__type__
|
561
|
+
when Literal::Tuple::Generic
|
562
|
+
tuple_types = @__type__.types
|
563
|
+
new_array_types = tuple_types.map { |t| Literal::Array(t) }
|
564
|
+
|
565
|
+
Literal::Tuple(*new_array_types).new(
|
566
|
+
*new_array_types.each_with_index.map do |t, i|
|
567
|
+
t.new(
|
568
|
+
*@__value__.map { |it| it[i] }
|
569
|
+
)
|
570
|
+
end
|
571
|
+
)
|
572
|
+
when Literal::Array::Generic
|
573
|
+
__with__(
|
574
|
+
@__value__.map(&:to_a).transpose.map! { |it| @__type__.new(*it) }
|
575
|
+
)
|
576
|
+
else
|
577
|
+
@__value__.transpose
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
532
581
|
def to_a
|
533
582
|
@__value__.dup
|
534
583
|
end
|
535
584
|
|
536
585
|
alias_method :to_ary, :to_a
|
537
586
|
|
538
|
-
|
587
|
+
def to_s
|
588
|
+
@__value__.to_s
|
589
|
+
end
|
539
590
|
|
540
591
|
def uniq
|
541
592
|
__with__(@__value__.uniq)
|
@@ -607,4 +658,75 @@ class Literal::Array
|
|
607
658
|
def fetch(...)
|
608
659
|
@__value__.fetch(...)
|
609
660
|
end
|
661
|
+
|
662
|
+
def zip(*others)
|
663
|
+
other_types = others.map do |other|
|
664
|
+
case other
|
665
|
+
when Literal::Array
|
666
|
+
other.__type__
|
667
|
+
when Array
|
668
|
+
_Any?
|
669
|
+
else
|
670
|
+
raise ArgumentError
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
tuple = Literal::Tuple(
|
675
|
+
@__type__,
|
676
|
+
*other_types
|
677
|
+
)
|
678
|
+
|
679
|
+
my_length = length
|
680
|
+
max_length = [my_length, *others.map(&:length)].max
|
681
|
+
|
682
|
+
# Check we match the max length or our type is nilable
|
683
|
+
unless my_length == max_length || @__type__ === nil
|
684
|
+
raise ArgumentError.new(<<~MESSAGE)
|
685
|
+
The literal array could not be zipped becuase its type is not nilable and it has fewer items than the maximum number of items in the other arrays.
|
686
|
+
|
687
|
+
You can either make the type of this array nilable, or add more items so its length matches the others.
|
688
|
+
|
689
|
+
#{inspect}
|
690
|
+
MESSAGE
|
691
|
+
end
|
692
|
+
|
693
|
+
# Check others match the max length or their types is nilable
|
694
|
+
others.each_with_index do |other, index|
|
695
|
+
unless other.length == max_length || other_types[index] === nil
|
696
|
+
raise ArgumentError.new(<<~MESSAGE)
|
697
|
+
The literal array could not be zipped becuase its type is not nilable and it has fewer items than the maximum number of items in the other arrays.
|
698
|
+
|
699
|
+
You can either make the type of this array nilable, or add more items so its length matches the others.
|
700
|
+
|
701
|
+
#{inspect}
|
702
|
+
MESSAGE
|
703
|
+
end
|
704
|
+
end
|
705
|
+
|
706
|
+
i = 0
|
707
|
+
|
708
|
+
if block_given?
|
709
|
+
while i < max_length
|
710
|
+
yield tuple.new(
|
711
|
+
@__value__[i],
|
712
|
+
*others.map { |it| it[i] }
|
713
|
+
)
|
714
|
+
i += 1
|
715
|
+
end
|
716
|
+
|
717
|
+
nil
|
718
|
+
else
|
719
|
+
result_value = []
|
720
|
+
|
721
|
+
while i < max_length
|
722
|
+
result_value << tuple.new(
|
723
|
+
@__value__[i],
|
724
|
+
*others.map { |it| it[i] }
|
725
|
+
)
|
726
|
+
i += 1
|
727
|
+
end
|
728
|
+
|
729
|
+
__with__(result_value)
|
730
|
+
end
|
731
|
+
end
|
610
732
|
end
|
data/lib/literal/enum.rb
CHANGED
@@ -9,20 +9,22 @@ class Literal::Enum
|
|
9
9
|
attr_reader :members
|
10
10
|
|
11
11
|
def values = @values.keys
|
12
|
+
def names = @names
|
12
13
|
|
13
|
-
def prop(name, type, kind = :keyword, reader: :public, default: nil)
|
14
|
-
super(name, type, kind, reader:, writer: false, default:)
|
14
|
+
def prop(name, type, kind = :keyword, reader: :public, predicate: false, default: nil)
|
15
|
+
super(name, type, kind, reader:, writer: false, predicate:, default:)
|
15
16
|
end
|
16
17
|
|
17
18
|
def inherited(subclass)
|
18
19
|
subclass.instance_exec do
|
19
20
|
@values = {}
|
20
|
-
@members =
|
21
|
+
@members = []
|
22
|
+
@indexes_definitions = {}
|
21
23
|
@indexes = {}
|
22
|
-
@
|
24
|
+
@names = {}
|
23
25
|
end
|
24
26
|
|
25
|
-
if RUBY_ENGINE != "truffleruby"
|
27
|
+
if subclass.name && RUBY_ENGINE != "truffleruby"
|
26
28
|
TracePoint.trace(:end) do |tp|
|
27
29
|
if tp.self == subclass
|
28
30
|
tp.self.__after_defined__
|
@@ -32,8 +34,16 @@ class Literal::Enum
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
37
|
+
def position_of(member)
|
38
|
+
coerce(member).__position__
|
39
|
+
end
|
40
|
+
|
41
|
+
def at_position(n)
|
42
|
+
@members[n]
|
43
|
+
end
|
44
|
+
|
35
45
|
def index(name, type, unique: true, &block)
|
36
|
-
@
|
46
|
+
@indexes_definitions[name] = [type, unique, block || name.to_proc]
|
37
47
|
end
|
38
48
|
|
39
49
|
def where(**kwargs)
|
@@ -43,11 +53,11 @@ class Literal::Enum
|
|
43
53
|
|
44
54
|
key, value = kwargs.first
|
45
55
|
|
46
|
-
types = @
|
56
|
+
types = @indexes_definitions.fetch(key)
|
47
57
|
type = types.first
|
48
58
|
Literal.check(actual: value, expected: type) { |c| raise NotImplementedError }
|
49
59
|
|
50
|
-
@
|
60
|
+
@indexes.fetch(key)[value]
|
51
61
|
end
|
52
62
|
|
53
63
|
def find_by(**kwargs)
|
@@ -57,15 +67,14 @@ class Literal::Enum
|
|
57
67
|
|
58
68
|
key, value = kwargs.first
|
59
69
|
|
60
|
-
unless @
|
70
|
+
unless @indexes_definitions.fetch(key)[1]
|
61
71
|
raise ArgumentError.new("You can only use `find_by` on unique indexes.")
|
62
72
|
end
|
63
73
|
|
64
|
-
|
65
|
-
|
66
|
-
end
|
74
|
+
type = @indexes_definitions.fetch(key)[0]
|
75
|
+
Literal.check(actual: value, expected: type)
|
67
76
|
|
68
|
-
@
|
77
|
+
@indexes.fetch(key)[value]&.first
|
69
78
|
end
|
70
79
|
|
71
80
|
def _load(data)
|
@@ -77,12 +86,8 @@ class Literal::Enum
|
|
77
86
|
object = const_get(name)
|
78
87
|
|
79
88
|
if self === object
|
80
|
-
|
81
|
-
|
82
|
-
end
|
83
|
-
object.instance_variable_set(:@name, name)
|
84
|
-
@values[object.value] = object
|
85
|
-
@members << object
|
89
|
+
# object.instance_variable_set(:@name, name)
|
90
|
+
@names[object] = name
|
86
91
|
define_method("#{name.to_s.gsub(/([^A-Z])([A-Z]+)/, '\1_\2').downcase}?") { self == object }
|
87
92
|
object.freeze
|
88
93
|
end
|
@@ -90,12 +95,21 @@ class Literal::Enum
|
|
90
95
|
|
91
96
|
def new(*args, **kwargs, &block)
|
92
97
|
raise ArgumentError if frozen?
|
98
|
+
|
93
99
|
new_object = super(*args, **kwargs, &nil)
|
94
100
|
|
95
|
-
if
|
96
|
-
new_object.
|
101
|
+
if @values.key?(new_object.value)
|
102
|
+
raise ArgumentError.new("The value #{new_object.value} is already used by #{@values[new_object.value].name}.")
|
97
103
|
end
|
98
104
|
|
105
|
+
@values[new_object.value] = new_object
|
106
|
+
|
107
|
+
new_object.instance_variable_set(:@__position__, @members.length)
|
108
|
+
|
109
|
+
@members << new_object
|
110
|
+
|
111
|
+
new_object.instance_exec(&block) if block
|
112
|
+
|
99
113
|
new_object
|
100
114
|
end
|
101
115
|
|
@@ -106,7 +120,7 @@ class Literal::Enum
|
|
106
120
|
constants(false).each { |name| const_added(name) }
|
107
121
|
end
|
108
122
|
|
109
|
-
@
|
123
|
+
@indexes_definitions.each do |name, (type, unique, block)|
|
110
124
|
index = @members.group_by(&block).freeze
|
111
125
|
|
112
126
|
index.each do |key, values|
|
@@ -119,7 +133,7 @@ class Literal::Enum
|
|
119
133
|
end
|
120
134
|
end
|
121
135
|
|
122
|
-
@
|
136
|
+
@indexes[name] = index
|
123
137
|
end
|
124
138
|
|
125
139
|
@values.freeze
|
@@ -149,8 +163,20 @@ class Literal::Enum
|
|
149
163
|
case value
|
150
164
|
when self
|
151
165
|
value
|
166
|
+
when Symbol
|
167
|
+
self[value] || begin
|
168
|
+
const_get(value)
|
169
|
+
rescue NameError
|
170
|
+
raise ArgumentError.new(
|
171
|
+
"Can't coerce #{value.inspect} into a #{inspect}."
|
172
|
+
)
|
173
|
+
end
|
152
174
|
else
|
153
|
-
self[value]
|
175
|
+
self[value] || raise(
|
176
|
+
ArgumentError.new(
|
177
|
+
"Can't coerce #{value.inspect} into a #{inspect}."
|
178
|
+
)
|
179
|
+
)
|
154
180
|
end
|
155
181
|
end
|
156
182
|
|
@@ -167,20 +193,13 @@ class Literal::Enum
|
|
167
193
|
end
|
168
194
|
end
|
169
195
|
|
170
|
-
def initialize(name, value, &block)
|
171
|
-
@name = name
|
172
|
-
@value = value
|
173
|
-
instance_exec(&block) if block
|
174
|
-
freeze
|
175
|
-
end
|
176
|
-
|
177
|
-
attr_reader :value
|
178
|
-
|
179
196
|
def name
|
180
|
-
|
197
|
+
klass = self.class
|
198
|
+
"#{klass.name}::#{klass.names[self]}"
|
181
199
|
end
|
182
200
|
|
183
201
|
alias_method :inspect, :name
|
202
|
+
alias_method :to_s, :name
|
184
203
|
|
185
204
|
def deconstruct
|
186
205
|
[@value]
|
@@ -194,4 +213,27 @@ class Literal::Enum
|
|
194
213
|
def _dump(level)
|
195
214
|
Marshal.dump(@value)
|
196
215
|
end
|
216
|
+
|
217
|
+
def <=>(other)
|
218
|
+
case other
|
219
|
+
when self.class
|
220
|
+
@__position__ <=> other.__position__
|
221
|
+
else
|
222
|
+
raise ArgumentError.new("Can't compare instances of #{other.class} to instances of #{self.class}")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def succ
|
227
|
+
self.class.members[@__position__ + 1]
|
228
|
+
end
|
229
|
+
|
230
|
+
def pred
|
231
|
+
if @__position__ <= 0
|
232
|
+
nil
|
233
|
+
else
|
234
|
+
self.class.members[@__position__ - 1]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
attr_reader :__position__
|
197
239
|
end
|
data/lib/literal/null.rb
CHANGED
@@ -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 << "
|
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
@@ -30,7 +30,7 @@ module Literal::Properties
|
|
30
30
|
end
|
31
31
|
|
32
32
|
unless Literal::Property::VISIBILITY_OPTIONS.include?(predicate)
|
33
|
-
|
33
|
+
raise Literal::ArgumentError.new("The predicate must be one of #{Literal::Property::VISIBILITY_OPTIONS.map(&:inspect).join(', ')}.")
|
34
34
|
end
|
35
35
|
|
36
36
|
if reader && :class == name
|
@@ -90,7 +90,7 @@ module Literal::Properties
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def to_h
|
93
|
-
|
93
|
+
{}
|
94
94
|
end
|
95
95
|
|
96
96
|
set_temporary_name "Literal::Properties(Extension)" if respond_to?(:set_temporary_name)
|
data/lib/literal/property.rb
CHANGED
@@ -118,29 +118,18 @@ class Literal::Property
|
|
118
118
|
"\n value\nend\n"
|
119
119
|
end
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
(@writer ? @writer.name : "public") <<
|
134
|
-
" def " <<
|
135
|
-
@name.name <<
|
136
|
-
"=(value)\n" <<
|
137
|
-
" self.class.literal_properties[:" <<
|
138
|
-
@name.name <<
|
139
|
-
"].check_writer(self, value)\n" <<
|
140
|
-
" @" << @name.name << " = value\n" <<
|
141
|
-
"rescue Literal::TypeError => error\n error.set_backtrace(caller(1))\n raise\n" <<
|
142
|
-
"end\n"
|
143
|
-
end
|
121
|
+
def generate_writer_method(buffer = +"")
|
122
|
+
buffer <<
|
123
|
+
(@writer ? @writer.name : "public") <<
|
124
|
+
" def " <<
|
125
|
+
@name.name <<
|
126
|
+
"=(value)\n" <<
|
127
|
+
" self.class.literal_properties[:" <<
|
128
|
+
@name.name <<
|
129
|
+
"].check_writer(self, value)\n" <<
|
130
|
+
" @" << @name.name << " = value\n" <<
|
131
|
+
"rescue Literal::TypeError => error\n error.set_backtrace(caller(1))\n raise\n" <<
|
132
|
+
"end\n"
|
144
133
|
end
|
145
134
|
|
146
135
|
def generate_predicate_method(buffer = +"")
|
@@ -171,10 +160,7 @@ class Literal::Property
|
|
171
160
|
generate_initializer_coerce_property(buffer)
|
172
161
|
end
|
173
162
|
|
174
|
-
|
175
|
-
generate_initializer_check_type(buffer)
|
176
|
-
end
|
177
|
-
|
163
|
+
generate_initializer_check_type(buffer)
|
178
164
|
generate_initializer_assign_value(buffer)
|
179
165
|
end
|
180
166
|
|
@@ -6,12 +6,16 @@ class Literal::Rails::EnumType < ActiveModel::Type::Value
|
|
6
6
|
super()
|
7
7
|
end
|
8
8
|
|
9
|
+
def type
|
10
|
+
:literal_enum
|
11
|
+
end
|
12
|
+
|
9
13
|
def cast(value)
|
10
14
|
case value
|
11
|
-
when
|
12
|
-
|
15
|
+
when nil
|
16
|
+
nil
|
13
17
|
else
|
14
|
-
|
18
|
+
@enum.coerce(value)
|
15
19
|
end
|
16
20
|
end
|
17
21
|
|
@@ -19,12 +23,8 @@ class Literal::Rails::EnumType < ActiveModel::Type::Value
|
|
19
23
|
case value
|
20
24
|
when nil
|
21
25
|
nil
|
22
|
-
when @enum
|
23
|
-
value.value
|
24
26
|
else
|
25
|
-
|
26
|
-
"Invalid value: #{value.inspect}. Expected an #{@enum.inspect}.",
|
27
|
-
)
|
27
|
+
@enum.coerce(value).value
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -33,9 +33,7 @@ class Literal::Rails::EnumType < ActiveModel::Type::Value
|
|
33
33
|
when nil
|
34
34
|
nil
|
35
35
|
else
|
36
|
-
@enum
|
37
|
-
ArgumentError.new("Invalid value: #{value.inspect} for #{@enum}"),
|
38
|
-
)
|
36
|
+
@enum.coerce(value)
|
39
37
|
end
|
40
38
|
end
|
41
39
|
end
|
@@ -4,9 +4,10 @@ module ActiveRecord
|
|
4
4
|
class RelationType
|
5
5
|
def initialize(model_class)
|
6
6
|
unless Class === model_class && model_class < ActiveRecord::Base
|
7
|
-
raise Literal::TypeError.
|
8
|
-
|
9
|
-
|
7
|
+
raise Literal::TypeError.new(
|
8
|
+
context: Literal::TypeError::Context.new(
|
9
|
+
expected: ActiveRecord::Base, actual: model_class
|
10
|
+
)
|
10
11
|
)
|
11
12
|
end
|
12
13
|
|
data/lib/literal/railtie.rb
CHANGED
@@ -2,20 +2,14 @@
|
|
2
2
|
|
3
3
|
class Literal::Railtie < Rails::Railtie
|
4
4
|
initializer "literal.register_literal_enum_type" do
|
5
|
-
ActiveRecord::Type.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
ActiveModel::Type.register(:literal_enum) do |name, type:|
|
14
|
-
Literal::Rails::EnumType.new(type)
|
15
|
-
end
|
16
|
-
|
17
|
-
ActiveModel::Type.register(:literal_flags) do |name, type:|
|
18
|
-
Literal::Rails::FlagsType.new(type)
|
5
|
+
[ActiveRecord::Type, ActiveModel::Type].each do |registry|
|
6
|
+
registry.register(:literal_enum) do |name, type:|
|
7
|
+
Literal::Rails::EnumType.new(type)
|
8
|
+
end
|
9
|
+
|
10
|
+
registry.register(:literal_flags) do |name, type:|
|
11
|
+
Literal::Rails::FlagsType.new(type)
|
12
|
+
end
|
19
13
|
end
|
20
14
|
end
|
21
15
|
end
|
data/lib/literal/transforms.rb
CHANGED
data/lib/literal/tuple.rb
CHANGED
@@ -56,5 +56,17 @@ class Literal::Tuple
|
|
56
56
|
@__types__ = types
|
57
57
|
end
|
58
58
|
|
59
|
+
def inspect
|
60
|
+
"Literal::Tuple(#{@__types__.map(&:inspect).join(', ')})#{@__values__.inspect}"
|
61
|
+
end
|
62
|
+
|
59
63
|
attr_reader :__values__, :__types__
|
64
|
+
|
65
|
+
def ==(other)
|
66
|
+
(Literal::Tuple === other) && (@__values__ == other.__values__)
|
67
|
+
end
|
68
|
+
|
69
|
+
def [](index)
|
70
|
+
@__values__[index]
|
71
|
+
end
|
60
72
|
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
|
@@ -25,14 +26,19 @@ class Literal::Types::ConstraintType
|
|
25
26
|
i += 1
|
26
27
|
end
|
27
28
|
|
29
|
+
result = true
|
30
|
+
|
28
31
|
@property_constraints.each do |a, t|
|
29
|
-
|
32
|
+
# We intentionally don’t return early here becuase it triggers an allocation.
|
33
|
+
if result && !(t === value.public_send(a))
|
34
|
+
result = false
|
35
|
+
end
|
30
36
|
rescue NoMethodError => e
|
31
37
|
raise unless e.name == a && e.receiver == value
|
32
38
|
return false
|
33
39
|
end
|
34
40
|
|
35
|
-
|
41
|
+
result
|
36
42
|
end
|
37
43
|
|
38
44
|
def >=(other)
|