literal 1.7.1 → 1.8.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 +9 -0
- data/lib/literal/data_structure.rb +2 -0
- data/lib/literal/enum.rb +2 -2
- data/lib/literal/flags.rb +1 -3
- data/lib/literal/properties/schema.rb +4 -5
- data/lib/literal/properties.rb +7 -7
- data/lib/literal/property.rb +8 -10
- data/lib/literal/types/constraint_type.rb +4 -6
- data/lib/literal/types/interface_type.rb +1 -1
- data/lib/literal/types/intersection_type.rb +1 -1
- data/lib/literal/types/map_type.rb +1 -1
- data/lib/literal/types/tuple_type.rb +1 -1
- data/lib/literal/types/union_type.rb +3 -5
- data/lib/literal/types/unit_type.rb +30 -0
- data/lib/literal/types.rb +58 -20
- data/lib/literal/version.rb +1 -1
- data/lib/literal.rb +1 -0
- data/lib/ruby_lsp/literal/addon.rb +70 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09739f3793221d93a906cbfbf62075a48fe06c02130ad99a4defab048bf43641'
|
4
|
+
data.tar.gz: 3df8df84ac14d6d3a8942f2c563f441d989b38589dbd961ebe5cd37c06abe670
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b981a63d59128471ce98bec6e6f49d094a991d1e5f86568430e3625333e2de623f169bf586509bde463e2aff3acc25420953628e2691f74e841fabdbe0959d0a
|
7
|
+
data.tar.gz: 60311bfab274436f61b3d4c900f60cf6ef1926db1bf59da1b0ece278c769f01cad55093d87121967b9b957b437634216af501366c9ded606b5e52b5162779d96
|
data/lib/literal/array.rb
CHANGED
@@ -493,8 +493,17 @@ class Literal::Array
|
|
493
493
|
self
|
494
494
|
end
|
495
495
|
|
496
|
+
def reverse(...)
|
497
|
+
__with__(@__value__.reverse(...))
|
498
|
+
end
|
499
|
+
|
496
500
|
alias_method :initialize_copy, :replace
|
497
501
|
|
502
|
+
def reverse!
|
503
|
+
@__value__.reverse!
|
504
|
+
self
|
505
|
+
end
|
506
|
+
|
498
507
|
def rotate(...)
|
499
508
|
__with__(@__value__.rotate(...))
|
500
509
|
end
|
data/lib/literal/enum.rb
CHANGED
@@ -86,9 +86,9 @@ class Literal::Enum
|
|
86
86
|
object = const_get(name)
|
87
87
|
|
88
88
|
if self === object
|
89
|
-
# object.instance_variable_set(:@name, name)
|
90
89
|
@names[object] = name
|
91
|
-
|
90
|
+
predicate_name = name.to_s.gsub(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_").downcase
|
91
|
+
define_method("#{predicate_name}?") { self == object }
|
92
92
|
object.freeze
|
93
93
|
end
|
94
94
|
end
|
data/lib/literal/flags.rb
CHANGED
@@ -78,6 +78,7 @@ class Literal::Properties::Schema
|
|
78
78
|
end
|
79
79
|
|
80
80
|
buffer << " }\n" << "end\n"
|
81
|
+
buffer << "alias to_hash to_h\n"
|
81
82
|
end
|
82
83
|
|
83
84
|
def generate_hash(buffer = +"")
|
@@ -111,9 +112,7 @@ class Literal::Properties::Schema
|
|
111
112
|
buffer << "alias eql? ==\n"
|
112
113
|
end
|
113
114
|
|
114
|
-
private
|
115
|
-
|
116
|
-
def generate_initializer_params(buffer = +"")
|
115
|
+
private def generate_initializer_params(buffer = +"")
|
117
116
|
sorted_properties = @sorted_properties
|
118
117
|
i, n = 0, sorted_properties.size
|
119
118
|
while i < n
|
@@ -153,12 +152,12 @@ class Literal::Properties::Schema
|
|
153
152
|
buffer
|
154
153
|
end
|
155
154
|
|
156
|
-
def generate_initializer_body(buffer = +"")
|
155
|
+
private def generate_initializer_body(buffer = +"")
|
157
156
|
buffer << " __properties__ = self.class.literal_properties.properties_index\n"
|
158
157
|
generate_initializer_handle_properties(@sorted_properties, buffer)
|
159
158
|
end
|
160
159
|
|
161
|
-
def generate_initializer_handle_properties(properties, buffer = +"")
|
160
|
+
private def generate_initializer_handle_properties(properties, buffer = +"")
|
162
161
|
i, n = 0, properties.size
|
163
162
|
while i < n
|
164
163
|
properties[i].generate_initializer_handle_property(buffer)
|
data/lib/literal/properties.rb
CHANGED
@@ -68,36 +68,36 @@ module Literal::Properties
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
private
|
72
|
-
|
73
|
-
def __literal_property_class__
|
71
|
+
private def __literal_property_class__
|
74
72
|
Literal::Property
|
75
73
|
end
|
76
74
|
|
77
|
-
def __define_literal_methods__(new_property)
|
75
|
+
private def __define_literal_methods__(new_property)
|
78
76
|
code = __generate_literal_methods__(new_property)
|
79
77
|
__literal_extension__.module_eval(code)
|
80
78
|
end
|
81
79
|
|
82
|
-
def __literal_extension__
|
80
|
+
private def __literal_extension__
|
83
81
|
if defined?(@__literal_extension__)
|
84
82
|
@__literal_extension__
|
85
83
|
else
|
86
84
|
@__literal_extension__ = Module.new do
|
87
85
|
def initialize
|
88
|
-
after_initialize if respond_to?(:after_initialize)
|
86
|
+
after_initialize if respond_to?(:after_initialize, true)
|
89
87
|
end
|
90
88
|
|
91
89
|
def to_h
|
92
90
|
{}
|
93
91
|
end
|
94
92
|
|
93
|
+
alias to_hash to_h
|
94
|
+
|
95
95
|
set_temporary_name "Literal::Properties(Extension)" if respond_to?(:set_temporary_name)
|
96
96
|
end
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
def __generate_literal_methods__(new_property, buffer = +"")
|
100
|
+
private def __generate_literal_methods__(new_property, buffer = +"")
|
101
101
|
buffer << "# frozen_string_literal: true\n"
|
102
102
|
literal_properties.generate_initializer(buffer)
|
103
103
|
literal_properties.generate_to_h(buffer)
|
data/lib/literal/property.rb
CHANGED
@@ -87,9 +87,9 @@ class Literal::Property
|
|
87
87
|
RUBY_KEYWORDS[@name] || @name.name
|
88
88
|
end
|
89
89
|
|
90
|
-
def default_value
|
90
|
+
def default_value(receiver)
|
91
91
|
case @default
|
92
|
-
when Proc then
|
92
|
+
when Proc then receiver.instance_exec(&@default)
|
93
93
|
else @default
|
94
94
|
end
|
95
95
|
end
|
@@ -164,9 +164,7 @@ class Literal::Property
|
|
164
164
|
generate_initializer_assign_value(buffer)
|
165
165
|
end
|
166
166
|
|
167
|
-
private
|
168
|
-
|
169
|
-
def generate_initializer_escape_keyword(buffer = +"")
|
167
|
+
private def generate_initializer_escape_keyword(buffer = +"")
|
170
168
|
buffer <<
|
171
169
|
escaped_name <<
|
172
170
|
" = binding.local_variable_get(:" <<
|
@@ -174,7 +172,7 @@ class Literal::Property
|
|
174
172
|
")\n"
|
175
173
|
end
|
176
174
|
|
177
|
-
def generate_initializer_coerce_property(buffer = +"")
|
175
|
+
private def generate_initializer_coerce_property(buffer = +"")
|
178
176
|
buffer <<
|
179
177
|
escaped_name <<
|
180
178
|
"= __property__.coerce(" <<
|
@@ -182,7 +180,7 @@ class Literal::Property
|
|
182
180
|
", context: self)\n"
|
183
181
|
end
|
184
182
|
|
185
|
-
def generate_initializer_assign_default(buffer = +"")
|
183
|
+
private def generate_initializer_assign_default(buffer = +"")
|
186
184
|
buffer <<
|
187
185
|
" if " <<
|
188
186
|
((@kind == :&) ? "nil" : "Literal::Null") <<
|
@@ -190,15 +188,15 @@ class Literal::Property
|
|
190
188
|
escaped_name <<
|
191
189
|
"\n " <<
|
192
190
|
escaped_name <<
|
193
|
-
" = __property__.default_value\n end\n"
|
191
|
+
" = __property__.default_value(self)\n end\n"
|
194
192
|
end
|
195
193
|
|
196
|
-
def generate_initializer_check_type(buffer = +"")
|
194
|
+
private def generate_initializer_check_type(buffer = +"")
|
197
195
|
buffer <<
|
198
196
|
" __property__.check_initializer(self, " << escaped_name << ")\n"
|
199
197
|
end
|
200
198
|
|
201
|
-
def generate_initializer_assign_value(buffer = +"")
|
199
|
+
private def generate_initializer_assign_value(buffer = +"")
|
202
200
|
buffer <<
|
203
201
|
" @" <<
|
204
202
|
@name.name <<
|
@@ -4,7 +4,7 @@
|
|
4
4
|
class Literal::Types::ConstraintType
|
5
5
|
include Literal::Type
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(object_constraints, property_constraints)
|
8
8
|
@object_constraints = object_constraints
|
9
9
|
@property_constraints = property_constraints
|
10
10
|
freeze
|
@@ -85,19 +85,17 @@ class Literal::Types::ConstraintType
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
private
|
89
|
-
|
90
|
-
def inspect_constraints
|
88
|
+
private def inspect_constraints
|
91
89
|
[inspect_object_constraints, inspect_property_constraints].compact.join(", ")
|
92
90
|
end
|
93
91
|
|
94
|
-
def inspect_object_constraints
|
92
|
+
private def inspect_object_constraints
|
95
93
|
if @object_constraints.length > 0
|
96
94
|
@object_constraints.map(&:inspect).join(", ")
|
97
95
|
end
|
98
96
|
end
|
99
97
|
|
100
|
-
def inspect_property_constraints
|
98
|
+
private def inspect_property_constraints
|
101
99
|
if @property_constraints.length > 0
|
102
100
|
@property_constraints.map { |k, t| "#{k}: #{t.inspect}" }.join(", ")
|
103
101
|
end
|
@@ -7,7 +7,7 @@ class Literal::Types::InterfaceType
|
|
7
7
|
# List of `===` method owners where the comparison will only match for objects with the same class
|
8
8
|
OwnClassTypeMethodOwners = Set[String, Integer, Kernel, Float, NilClass, TrueClass, FalseClass].freeze
|
9
9
|
|
10
|
-
def initialize(
|
10
|
+
def initialize(methods)
|
11
11
|
raise Literal::ArgumentError.new("_Interface type must have at least one method.") if methods.size < 1
|
12
12
|
@methods = methods.to_set.freeze
|
13
13
|
freeze
|
@@ -4,7 +4,7 @@ class Literal::Types::UnionType
|
|
4
4
|
include Enumerable
|
5
5
|
include Literal::Type
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(queue)
|
8
8
|
raise Literal::ArgumentError.new("_Union type must have at least one type.") if queue.size < 1
|
9
9
|
types = []
|
10
10
|
primitives = Set[]
|
@@ -22,11 +22,9 @@ class Literal::Types::UnionType
|
|
22
22
|
end
|
23
23
|
|
24
24
|
types.uniq!
|
25
|
-
@types = types
|
26
|
-
@primitives = primitives
|
25
|
+
@types = types.freeze
|
26
|
+
@primitives = primitives.freeze
|
27
27
|
|
28
|
-
@types.freeze
|
29
|
-
@primitives.freeze
|
30
28
|
freeze
|
31
29
|
end
|
32
30
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
class Literal::Types::UnitType
|
5
|
+
include Literal::Type
|
6
|
+
|
7
|
+
EQUAL_METHOD = BasicObject.instance_method(:equal?)
|
8
|
+
|
9
|
+
def initialize(object)
|
10
|
+
@object = object
|
11
|
+
freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :object
|
15
|
+
|
16
|
+
def ===(value)
|
17
|
+
EQUAL_METHOD.bind_call(@object, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def >=(other)
|
21
|
+
case other
|
22
|
+
when Literal::Types::UnitType
|
23
|
+
EQUAL_METHOD.bind_call(@object, other.object)
|
24
|
+
else
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
freeze
|
30
|
+
end
|
data/lib/literal/types.rb
CHANGED
@@ -95,7 +95,7 @@ module Literal::Types
|
|
95
95
|
if a.length == 1 && k.length == 0
|
96
96
|
a[0]
|
97
97
|
else
|
98
|
-
ConstraintType.new(
|
98
|
+
ConstraintType.new(a, k)
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
@@ -234,8 +234,8 @@ module Literal::Types
|
|
234
234
|
end
|
235
235
|
|
236
236
|
# Matches if the value responds to all the given methods.
|
237
|
-
def _Interface(
|
238
|
-
InterfaceType.new(
|
237
|
+
def _Interface(*methods)
|
238
|
+
InterfaceType.new(methods)
|
239
239
|
end
|
240
240
|
|
241
241
|
# Nilable version of `_Interface`
|
@@ -246,8 +246,8 @@ module Literal::Types
|
|
246
246
|
end
|
247
247
|
|
248
248
|
# Matches if *all* given types are matched.
|
249
|
-
def _Intersection(
|
250
|
-
IntersectionType.new(
|
249
|
+
def _Intersection(*types)
|
250
|
+
IntersectionType.new(types)
|
251
251
|
end
|
252
252
|
|
253
253
|
# Nilable version of `_Intersection`
|
@@ -258,13 +258,19 @@ module Literal::Types
|
|
258
258
|
end
|
259
259
|
|
260
260
|
# Ensures the value is valid JSON data (i.e. it came from JSON.parse).
|
261
|
-
def _JSONData
|
262
|
-
|
261
|
+
def _JSONData(*a, **k)
|
262
|
+
if a.length > 0 || k.length > 0
|
263
|
+
_Constraint(JSONDataType::Instance, *a, **k)
|
264
|
+
else
|
265
|
+
JSONDataType::Instance
|
266
|
+
end
|
263
267
|
end
|
264
268
|
|
265
269
|
# Nilable version of `_JSONData`
|
266
|
-
def _JSONData?
|
267
|
-
|
270
|
+
def _JSONData?(...)
|
271
|
+
_Nilable(
|
272
|
+
_JSONData(...)
|
273
|
+
)
|
268
274
|
end
|
269
275
|
|
270
276
|
# Matches if the value is a `Proc` and `#lambda?` returns truthy.
|
@@ -280,8 +286,8 @@ module Literal::Types
|
|
280
286
|
# ```ruby
|
281
287
|
# _Map(name: String, age: Integer)
|
282
288
|
# ```
|
283
|
-
def _Map(
|
284
|
-
MapType.new(
|
289
|
+
def _Map(**shape)
|
290
|
+
MapType.new(shape)
|
285
291
|
end
|
286
292
|
|
287
293
|
# Nilable version of `_Map`
|
@@ -305,15 +311,35 @@ module Literal::Types
|
|
305
311
|
end
|
306
312
|
|
307
313
|
# Matches if the given type is *not* matched.
|
308
|
-
def _Not(
|
309
|
-
|
310
|
-
|
311
|
-
|
314
|
+
def _Not(*types)
|
315
|
+
if types.length > 1
|
316
|
+
NotType.new(
|
317
|
+
_Union(*types)
|
318
|
+
)
|
312
319
|
else
|
313
|
-
|
320
|
+
type = types[0]
|
321
|
+
|
322
|
+
case type
|
323
|
+
when NotType
|
324
|
+
type.type
|
325
|
+
else
|
326
|
+
NotType.new(type)
|
327
|
+
end
|
314
328
|
end
|
315
329
|
end
|
316
330
|
|
331
|
+
def _Pattern(regex, &block)
|
332
|
+
raise ArgumentError.new("Block required for Pattern") unless block
|
333
|
+
|
334
|
+
-> (value) {
|
335
|
+
if (data = regex.match(value))
|
336
|
+
!!block.call(*data.captures, **data.named_captures&.transform_keys(&:to_sym))
|
337
|
+
else
|
338
|
+
false
|
339
|
+
end
|
340
|
+
}
|
341
|
+
end
|
342
|
+
|
317
343
|
def _Predicate(message, &block)
|
318
344
|
PredicateType.new(message:, block:)
|
319
345
|
end
|
@@ -399,8 +425,8 @@ module Literal::Types
|
|
399
425
|
# ```ruby
|
400
426
|
# _Tuple(String, Integer, Integer)
|
401
427
|
# ```
|
402
|
-
def _Tuple(
|
403
|
-
TupleType.new(
|
428
|
+
def _Tuple(*types)
|
429
|
+
TupleType.new(types)
|
404
430
|
end
|
405
431
|
|
406
432
|
# Nilable version of `_Typle`
|
@@ -414,8 +440,8 @@ module Literal::Types
|
|
414
440
|
end
|
415
441
|
|
416
442
|
# Matches if *any* given type is matched.
|
417
|
-
def _Union(
|
418
|
-
UnionType.new(
|
443
|
+
def _Union(*types)
|
444
|
+
UnionType.new(types)
|
419
445
|
end
|
420
446
|
|
421
447
|
# Nilable version of `_Union`
|
@@ -425,6 +451,18 @@ module Literal::Types
|
|
425
451
|
)
|
426
452
|
end
|
427
453
|
|
454
|
+
# The unit type is a type that matches only the same object
|
455
|
+
def _Unit(object)
|
456
|
+
UnitType.new(object)
|
457
|
+
end
|
458
|
+
|
459
|
+
# Nilable version of `_Unit`
|
460
|
+
def _Unit?(...)
|
461
|
+
_Nilable(
|
462
|
+
_Unit(...)
|
463
|
+
)
|
464
|
+
end
|
465
|
+
|
428
466
|
def _Void
|
429
467
|
VoidType::Instance
|
430
468
|
end
|
data/lib/literal/version.rb
CHANGED
data/lib/literal.rb
CHANGED
@@ -7,6 +7,7 @@ module Literal
|
|
7
7
|
Loader = Zeitwerk::Loader.for_gem.tap do |loader|
|
8
8
|
loader.ignore("#{__dir__}/literal/rails")
|
9
9
|
loader.ignore("#{__dir__}/literal/railtie.rb")
|
10
|
+
loader.ignore("#{__dir__}/ruby_lsp")
|
10
11
|
|
11
12
|
loader.inflector.inflect(
|
12
13
|
"json_data_type" => "JSONDataType"
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ruby_lsp/addon"
|
4
|
+
|
5
|
+
module RubyLsp
|
6
|
+
module Literal
|
7
|
+
class Addon < ::RubyLsp::Addon
|
8
|
+
def activate(global_state, message_queue)
|
9
|
+
end
|
10
|
+
|
11
|
+
def deactivate
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
"Literal"
|
16
|
+
end
|
17
|
+
|
18
|
+
def version
|
19
|
+
"0.1.0"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class MyIndexingEnhancement < RubyIndexer::Enhancement
|
24
|
+
def on_call_node_enter(node)
|
25
|
+
name = node.name
|
26
|
+
owner = @listener.current_owner
|
27
|
+
location = node.location
|
28
|
+
arguments = node.arguments&.arguments
|
29
|
+
|
30
|
+
return unless owner
|
31
|
+
return unless :prop == name
|
32
|
+
|
33
|
+
args = arguments&.reject { |it| it.is_a?(Prism::KeywordHashNode) }
|
34
|
+
kwargs = arguments.find { |it| it.is_a?(Prism::KeywordHashNode) }&.elements.to_h do |element|
|
35
|
+
case element
|
36
|
+
in { key: Prism::SymbolNode[unescaped: String => key], value: value }
|
37
|
+
[key, value]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
case args
|
42
|
+
in [Prism::SymbolNode[unescaped: String => prop_name], *]
|
43
|
+
@listener.instance_exec do
|
44
|
+
@index.add(RubyIndexer::Entry::InstanceVariable.new(
|
45
|
+
"@#{prop_name}",
|
46
|
+
@uri,
|
47
|
+
RubyIndexer::Location.from_prism_location(node.location, @code_units_cache),
|
48
|
+
collect_comments(node),
|
49
|
+
owner,
|
50
|
+
))
|
51
|
+
end
|
52
|
+
|
53
|
+
if kwargs["reader"] in Prism::SymbolNode[unescaped: "private" | "protected" | "public" => visibility]
|
54
|
+
@listener.add_method(prop_name, location, [
|
55
|
+
RubyIndexer::Entry::Signature.new([]),
|
56
|
+
], visibility: visibility.to_sym)
|
57
|
+
end
|
58
|
+
|
59
|
+
if kwargs["writer"] in Prism::SymbolNode[unescaped: "private" | "protected" | "public" => visibility]
|
60
|
+
@listener.add_method("#{prop_name}=", location, [
|
61
|
+
RubyIndexer::Entry::Signature.new([
|
62
|
+
RubyIndexer::Entry::RequiredParameter.new(name: "value"),
|
63
|
+
]),
|
64
|
+
], visibility: visibility.to_sym)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: literal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
@@ -92,9 +92,11 @@ files:
|
|
92
92
|
- lib/literal/types/truthy_type.rb
|
93
93
|
- lib/literal/types/tuple_type.rb
|
94
94
|
- lib/literal/types/union_type.rb
|
95
|
+
- lib/literal/types/unit_type.rb
|
95
96
|
- lib/literal/types/void_type.rb
|
96
97
|
- lib/literal/value.rb
|
97
98
|
- lib/literal/version.rb
|
99
|
+
- lib/ruby_lsp/literal/addon.rb
|
98
100
|
homepage: https://literal.fun
|
99
101
|
licenses:
|
100
102
|
- MIT
|