literal 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d4ade41b16e56d3e05c85771d12ffedffa1e5d0c33998890c1fdd0b8b8503bf
4
- data.tar.gz: 7bb21c5e0ab2318825dd19efe878f38db2469f3a6f500615ebf2300723b7438f
3
+ metadata.gz: b459adebd387b12382d4e049a1f9211f6330bc6f77d66a8380bfbe758a4fb224
4
+ data.tar.gz: d771162ac9e9939e20b9478225baa23dc5d3b4d2fd0f0daa3c821277053ea88f
5
5
  SHA512:
6
- metadata.gz: e56f4aaefec78d299254174dcf6a5aded7cb59970291ef55bdb3a88392c230d26efe07c8a18471c9484acd5e6f477f63b6639e7accf712ca7c9aad18720cd84f
7
- data.tar.gz: a60595864a2f267ded92ca14603eb74b0b42deddfa2167fd582e5ebfaee83f0348569d498755e03e088a83ff647149c1159d8758fbb3c4a1c4ebada0d43a0571
6
+ metadata.gz: 68c949539f7002388ccff9c0547c48988a3ccb9ae2cb3262f8ab9119f0187f8ff775c46d3b2aa8abbcc1bbb68a767427c99b48af898744c58bfa004fec3dd491
7
+ data.tar.gz: 872aeda1f2efb4023e9c34c324e8fba149737d5744bc735e57b0ffdbb52be6001f39360fa86c5f981d70e70b5698394eef228eef9dde2d5ca387180414aac555
@@ -0,0 +1,232 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Flags
4
+ include Enumerable
5
+
6
+ def initialize(value = 0, **new_flags)
7
+ if new_flags.length > 0
8
+ value = self.class.calculate_from_hash(new_flags)
9
+ end
10
+
11
+ @value = value
12
+
13
+ freeze
14
+ end
15
+
16
+ def __initialize_from_value__(value)
17
+ @value = value
18
+ freeze
19
+ end
20
+
21
+ attr_reader :value
22
+
23
+ def self.define(**flags)
24
+ raise ArgumentError if frozen?
25
+ unique_values = flags.values
26
+ unique_values.uniq!
27
+
28
+ if unique_values.length != flags.length
29
+ raise Literal::ArgumentError.new("Flags must be unique.")
30
+ end
31
+
32
+ const_set(:FLAGS, flags.dup.freeze)
33
+
34
+ flags.each do |name, bit|
35
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
36
+ # frozen_string_literal: true
37
+
38
+ def #{name}?
39
+ @value & (2 ** #{bit}) > 0
40
+ end
41
+ RUBY
42
+ end
43
+
44
+ freeze
45
+ end
46
+
47
+ # () -> (Integer) -> Literal::Flags
48
+ def self.to_proc
49
+ proc { |value| new(value) }
50
+ end
51
+
52
+ # (Integer) -> String
53
+ def self.calculate_bit_string(value)
54
+ value.to_s(2).rjust(self::BITS, "0")
55
+ end
56
+
57
+ # (Array(Boolean)) -> Integer
58
+ def self.calculate_from_array(array)
59
+ array.reverse_each.with_index.reduce(0) do |value, (bit, index)|
60
+ value | (bit ? 1 << index : 0)
61
+ end
62
+ end
63
+
64
+ # (Hash(Symbol, Boolean)) -> Integer
65
+ def self.calculate_from_hash(hash)
66
+ flags = self::FLAGS
67
+ hash.reduce(0) do |value, (key, bit)|
68
+ value | (bit ? 2 ** flags.fetch(key) : 0)
69
+ end
70
+ end
71
+
72
+ # (Integer) -> Array(Symbol)
73
+ def self.calculate_tokens(value)
74
+ flags = self::FLAGS
75
+ flags.keys.select { |t| value & (2 ** flags.fetch(t)) > 0 }
76
+ end
77
+
78
+ # (Integer) -> Array(Boolean)
79
+ def self.calculate_array(value)
80
+ bits = self::BITS
81
+ Array.new(bits) { |i| (value & (2 ** (bits - 1 - i)) > 0) }
82
+ end
83
+
84
+ # (Array(Symbol)) -> Integer
85
+ def self.calculate_from_tokens(tokens)
86
+ flags = self::FLAGS
87
+ tokens.reduce(0) { |f, t| f | (2 ** flags.fetch(t)) }
88
+ end
89
+
90
+ # (Integer) -> Hash(Symbol, Boolean)
91
+ def self.calculate_hash_from_value(value)
92
+ self::FLAGS.transform_values do |bit|
93
+ (value & (2 ** bit)) > 0
94
+ end
95
+ end
96
+
97
+ # () -> Array(Symbol)
98
+ def self.keys
99
+ @flags.keys
100
+ end
101
+
102
+ # (String) -> Literal::Flags
103
+ def self.from_bit_string(bit_string)
104
+ from_int(bit_string.to_i(2))
105
+ end
106
+
107
+ # (Array(Boolean)) -> Literal::Flags
108
+ def self.from_array(array)
109
+ if array.length != self::BITS
110
+ raise Literal::ArgumentError.new("The array must have #{self::BITS} items.")
111
+ end
112
+
113
+ from_int(calculate_from_array(array))
114
+ end
115
+
116
+ # (Array(Symbol)) -> Literal::Flags
117
+ def self.from_tokens(tokens)
118
+ from_int(calculate_from_tokens(tokens))
119
+ end
120
+
121
+ # (Integer) -> Literal::Flags
122
+ def self.from_int(value)
123
+ allocate.__initialize_from_value__(value)
124
+ end
125
+
126
+ # (String) -> Integer
127
+ def self.unpack_int(value)
128
+ value.unpack1(self::PACKER)
129
+ end
130
+
131
+ # (String) -> Literal::Flags
132
+ def self.unpack(value)
133
+ new(unpack_int(value))
134
+ end
135
+
136
+ # () -> String
137
+ def pack
138
+ [@value].pack(self.class::PACKER)
139
+ end
140
+
141
+ # () -> String
142
+ def inspect
143
+ to_h.inspect
144
+ end
145
+
146
+ # () -> Hash(Symbol, Boolean)
147
+ def to_h
148
+ self.class.calculate_hash_from_value(@value)
149
+ end
150
+
151
+ def each
152
+ self.class::FLAGS.each do |key, bit|
153
+ yield key, @value & (2 ** bit) > 0
154
+ end
155
+ end
156
+
157
+ # (Symbol) -> Boolean
158
+ def [](key)
159
+ @value & (2 ** self.class::FLAGS.fetch(key)) > 0
160
+ end
161
+
162
+ def |(other)
163
+ case other
164
+ when Literal::Flags
165
+ self.class.new(@value | other.value)
166
+ when Integer
167
+ self.class.new(@value | other)
168
+ end
169
+ end
170
+
171
+ def &(other)
172
+ case other
173
+ when Literal::Flags
174
+ self.class.new(@value & other.value)
175
+ when Integer
176
+ self.class.new(@value & other)
177
+ end
178
+ end
179
+
180
+ def to_i
181
+ @value
182
+ end
183
+
184
+ def to_bit_string
185
+ self.class.calculate_bit_string(@value)
186
+ end
187
+
188
+ def to_tokens
189
+ self.class.calculate_tokens(@value)
190
+ end
191
+
192
+ def to_a
193
+ self.class.calculate_array(@value)
194
+ end
195
+
196
+ alias_method :deconstruct, :to_a
197
+
198
+ def deconstruct_keys(keys = nil)
199
+ if keys
200
+ flags = self.class::FLAGS
201
+ keys.to_h do |key|
202
+ [key, @value & (2 ** flags.fetch(key)) > 0]
203
+ end
204
+ else
205
+ to_h
206
+ end
207
+ end
208
+ end
209
+
210
+ class Literal::Flags8 < Literal::Flags
211
+ BYTES = 1
212
+ BITS = BYTES * 8
213
+ PACKER = "C"
214
+ end
215
+
216
+ class Literal::Flags16 < Literal::Flags
217
+ BYTES = 2
218
+ BITS = BYTES * 8
219
+ PACKER = "S"
220
+ end
221
+
222
+ class Literal::Flags32 < Literal::Flags
223
+ BYTES = 4
224
+ BITS = BYTES * 8
225
+ PACKER = "L"
226
+ end
227
+
228
+ class Literal::Flags64 < Literal::Flags
229
+ BYTES = 8
230
+ BITS = BYTES * 8
231
+ PACKER = "Q"
232
+ end
@@ -47,8 +47,10 @@ class Literal::Properties::Schema
47
47
  end
48
48
 
49
49
  def generate_initializer(buffer = +"")
50
- buffer << "alias initialize initialize\n"
51
- buffer << "def initialize(#{generate_initializer_params})\n"
50
+ buffer << "alias initialize initialize\n" \
51
+ "def initialize("
52
+ generate_initializer_params(buffer)
53
+ buffer << ")\n"
52
54
  generate_initializer_body(buffer)
53
55
  buffer << "" \
54
56
  "rescue Literal::TypeError => error\n" \
@@ -100,7 +102,7 @@ class Literal::Properties::Schema
100
102
  i, n = 0, sorted_properties.size
101
103
  while i < n
102
104
  property = sorted_properties[i]
103
- buffer << " @" << property.name.name << " == other.#{property.escaped_name}"
105
+ buffer << " @" << property.name.name << " == other." << property.escaped_name
104
106
  buffer << " &&\n " if i < n - 1
105
107
  i += 1
106
108
  end
@@ -25,6 +25,21 @@ class Literal::Types::ConstraintType
25
25
  true
26
26
  end
27
27
 
28
+ def record_literal_type_errors(context)
29
+ @object_constraints.each do |constraint|
30
+ next if constraint === context.actual
31
+
32
+ context.add_child(label: inspect, expected: constraint, actual: context.actual)
33
+ end
34
+
35
+ @property_constraints.each do |property, constraint|
36
+ actual = context.actual.public_send(property)
37
+ next if constraint === actual
38
+
39
+ context.add_child(label: ".#{property}", expected: constraint, actual:)
40
+ end
41
+ end
42
+
28
43
  private
29
44
 
30
45
  def inspect_constraints
@@ -18,4 +18,21 @@ class Literal::Types::HashType
18
18
 
19
19
  true
20
20
  end
21
+
22
+ def record_literal_type_errors(context)
23
+ unless Hash === context.actual
24
+ return
25
+ end
26
+
27
+ context.actual.each do |key, item|
28
+ unless @key_type === key
29
+ context.add_child(label: "[]", expected: @key_type, actual: key)
30
+ next
31
+ end
32
+
33
+ unless @value_type === item
34
+ context.add_child(label: "[#{key.inspect}]", expected: @value_type, actual: item)
35
+ end
36
+ end
37
+ end
21
38
  end
@@ -17,4 +17,12 @@ class Literal::Types::IntersectionType
17
17
  def nil?
18
18
  @types.all?(&:nil?)
19
19
  end
20
+
21
+ def record_literal_type_errors(context)
22
+ @types.each do |type|
23
+ next if type === context.actual
24
+
25
+ context.add_child(label: inspect, expected: type, actual: context.actual)
26
+ end
27
+ end
20
28
  end
@@ -22,8 +22,13 @@ class Literal::Types::MapType
22
22
  end
23
23
 
24
24
  context.actual.each do |key, item|
25
- unless @shape[key] === item
26
- context.add_child(label: "[#{key.inspect}]", expected: @shape[key], actual: item)
25
+ unless (expected = @shape[key])
26
+ context.add_child(label: "[]", expected: @shape.keys, actual: key)
27
+ next
28
+ end
29
+
30
+ unless expected === item
31
+ context.add_child(label: "[#{key.inspect}]", expected:, actual: item)
27
32
  end
28
33
  end
29
34
  end
@@ -23,4 +23,20 @@ class Literal::Types::TupleType
23
23
 
24
24
  true
25
25
  end
26
+
27
+ def record_literal_type_errors(context)
28
+ return unless Array === context.actual
29
+
30
+ len = [@types.size, context.actual.size].max
31
+ i = 0
32
+ while i < len
33
+ actual = context.actual[i]
34
+ if !(expected = @types[i])
35
+ context.add_child(label: "[#{i}]", expected: Literal::Types::NeverType, actual:)
36
+ elsif !(expected === actual)
37
+ context.add_child(label: "[#{i}]", expected:, actual:)
38
+ end
39
+ i += 1
40
+ end
41
+ end
26
42
  end
data/lib/literal/types.rb CHANGED
@@ -38,7 +38,7 @@ module Literal::Types
38
38
  NilableLambdaType = NilableType.new(LambdaType)
39
39
  NilableProcableType = NilableType.new(ProcableType)
40
40
 
41
- # Matches any value except `nil`. Use `_Any?` or `_Unit` to match any value including `nil`.
41
+ # Matches any value except `nil`. Use `_Any?` or `_Void` to match any value including `nil`.
42
42
  def _Any
43
43
  AnyType
44
44
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Literal
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
data/lib/literal.rb CHANGED
@@ -13,6 +13,11 @@ module Literal
13
13
  autoload :Property, "literal/property"
14
14
  autoload :Struct, "literal/struct"
15
15
  autoload :Types, "literal/types"
16
+ autoload :Flags, "literal/flags"
17
+ autoload :Flags8, "literal/flags"
18
+ autoload :Flags16, "literal/flags"
19
+ autoload :Flags32, "literal/flags"
20
+ autoload :Flags64, "literal/flags"
16
21
 
17
22
  # Errors
18
23
  autoload :Error, "literal/errors/error"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: literal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Drapper
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-01 00:00:00.000000000 Z
11
+ date: 2024-11-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A literal Ruby gem.
14
14
  email:
@@ -27,6 +27,7 @@ files:
27
27
  - lib/literal/errors/argument_error.rb
28
28
  - lib/literal/errors/error.rb
29
29
  - lib/literal/errors/type_error.rb
30
+ - lib/literal/flags.rb
30
31
  - lib/literal/null.rb
31
32
  - lib/literal/object.rb
32
33
  - lib/literal/properties.rb