rbs 3.2.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/comments.yml +1 -1
- data/.github/workflows/ruby.yml +7 -2
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +134 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +21 -15
- data/README.md +11 -2
- data/Rakefile +10 -7
- data/Steepfile +7 -7
- data/core/basic_object.rbs +7 -7
- data/core/binding.rbs +3 -3
- data/core/builtin.rbs +171 -5
- data/core/constants.rbs +17 -17
- data/core/dir.rbs +3 -3
- data/core/encoding.rbs +434 -628
- data/core/enumerator.rbs +37 -0
- data/core/exception.rbs +11 -11
- data/core/false_class.rbs +5 -11
- data/core/fiber.rbs +5 -5
- data/core/file_test.rbs +28 -26
- data/core/kernel.rbs +900 -21
- data/core/marshal.rbs +24 -14
- data/core/match_data.rbs +8 -8
- data/core/math.rbs +57 -53
- data/core/method.rbs +3 -1
- data/core/module.rbs +38 -36
- data/core/nil_class.rbs +7 -13
- data/core/object.rbs +3 -966
- data/core/process.rbs +3 -3
- data/core/ractor.rbs +2 -2
- data/core/rb_config.rbs +64 -43
- data/core/regexp.rbs +3 -3
- data/core/set.rbs +3 -2
- data/core/signal.rbs +10 -4
- data/core/struct.rbs +1 -1
- data/core/thread.rbs +7 -7
- data/core/thread_group.rbs +9 -9
- data/core/true_class.rbs +5 -11
- data/core/unbound_method.rbs +56 -7
- data/core/warning.rbs +33 -0
- data/docs/collection.md +56 -6
- data/docs/data_and_struct.md +57 -0
- data/docs/stdlib.md +61 -2
- data/docs/syntax.md +123 -2
- data/ext/rbs_extension/constants.c +73 -72
- data/ext/rbs_extension/lexer.c +624 -569
- data/ext/rbs_extension/lexer.h +1 -0
- data/ext/rbs_extension/lexer.re +1 -0
- data/ext/rbs_extension/lexstate.c +1 -0
- data/ext/rbs_extension/parser.c +6 -0
- data/goodcheck.yml +2 -2
- data/lib/rbs/annotate/formatter.rb +13 -3
- data/lib/rbs/annotate/rdoc_source.rb +10 -1
- data/lib/rbs/cli/colored_io.rb +48 -0
- data/lib/rbs/cli/diff.rb +80 -0
- data/lib/rbs/cli.rb +169 -17
- data/lib/rbs/collection/config/lockfile.rb +0 -25
- data/lib/rbs/collection/config/lockfile_generator.rb +0 -6
- data/lib/rbs/collection/installer.rb +1 -1
- data/lib/rbs/collection/sources/git.rb +6 -4
- data/lib/rbs/collection/sources/local.rb +7 -5
- data/lib/rbs/diff.rb +121 -0
- data/lib/rbs/environment.rb +7 -4
- data/lib/rbs/method_type.rb +23 -0
- data/lib/rbs/prototype/rb.rb +2 -9
- data/lib/rbs/prototype/rbi.rb +1 -1
- data/lib/rbs/prototype/runtime/helpers.rb +59 -0
- data/lib/rbs/prototype/runtime/reflection.rb +19 -0
- data/lib/rbs/prototype/runtime/value_object_generator.rb +275 -0
- data/lib/rbs/prototype/runtime.rb +233 -153
- data/lib/rbs/resolver/constant_resolver.rb +1 -1
- data/lib/rbs/sorter.rb +144 -117
- data/lib/rbs/test/guaranteed.rb +31 -0
- data/lib/rbs/test/type_check.rb +4 -4
- data/lib/rbs/test.rb +3 -0
- data/lib/rbs/types.rb +184 -3
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +4 -4
- data/lib/rbs.rb +1 -0
- data/rbs.gemspec +1 -0
- data/sig/annotate/formatter.rbs +2 -2
- data/sig/annotate/rdoc_annotater.rbs +1 -1
- data/sig/cli/colored_io.rbs +15 -0
- data/sig/cli/diff.rbs +21 -0
- data/sig/cli.rbs +2 -0
- data/sig/collection/config/lockfile.rbs +0 -6
- data/sig/diff.rbs +23 -0
- data/sig/errors.rbs +1 -5
- data/sig/method_types.rbs +6 -0
- data/sig/prototype/runtime.rbs +166 -0
- data/sig/rdoc/rbs.rbs +4 -0
- data/sig/shims/bundler.rbs +5 -0
- data/sig/sorter.rbs +23 -5
- data/sig/types.rbs +29 -0
- data/stdlib/benchmark/0/benchmark.rbs +1 -1
- data/stdlib/cgi/0/core.rbs +2 -2
- data/stdlib/did_you_mean/0/did_you_mean.rbs +2 -2
- data/stdlib/digest/0/digest.rbs +1 -1
- data/stdlib/fileutils/0/fileutils.rbs +1 -1
- data/stdlib/forwardable/0/forwardable.rbs +4 -4
- data/stdlib/io-console/0/io-console.rbs +1 -1
- data/stdlib/json/0/json.rbs +37 -0
- data/stdlib/logger/0/logger.rbs +2 -2
- data/stdlib/net-http/0/manifest.yaml +1 -1
- data/stdlib/net-http/0/net-http.rbs +16 -63
- data/stdlib/net-protocol/0/manifest.yaml +2 -0
- data/stdlib/net-protocol/0/net-protocol.rbs +56 -0
- data/stdlib/net-smtp/0/manifest.yaml +2 -0
- data/stdlib/net-smtp/0/net-smtp.rbs +55 -0
- data/stdlib/open-uri/0/manifest.yaml +3 -0
- data/stdlib/open-uri/0/open-uri.rbs +341 -0
- data/stdlib/openssl/0/openssl.rbs +1 -1
- data/stdlib/pp/0/manifest.yaml +2 -0
- data/stdlib/pp/0/pp.rbs +301 -0
- data/stdlib/{yaml → psych}/0/dbm.rbs +3 -3
- data/stdlib/psych/0/manifest.yaml +3 -0
- data/stdlib/psych/0/psych.rbs +391 -0
- data/stdlib/{yaml → psych}/0/store.rbs +2 -2
- data/stdlib/rdoc/0/code_object.rbs +55 -0
- data/stdlib/rdoc/0/comment.rbs +60 -0
- data/stdlib/rdoc/0/context.rbs +153 -0
- data/stdlib/rdoc/0/markup.rbs +119 -0
- data/stdlib/rdoc/0/parser.rbs +56 -0
- data/stdlib/rdoc/0/rdoc.rbs +0 -372
- data/stdlib/rdoc/0/ri.rbs +17 -0
- data/stdlib/rdoc/0/store.rbs +48 -0
- data/stdlib/rdoc/0/top_level.rbs +97 -0
- data/stdlib/socket/0/basic_socket.rbs +1 -1
- data/stdlib/socket/0/socket.rbs +1 -1
- data/stdlib/uri/0/common.rbs +1 -1
- data/stdlib/yaml/0/manifest.yaml +1 -2
- data/stdlib/yaml/0/yaml.rbs +1 -199
- metadata +49 -7
- data/sig/shims/pp.rbs +0 -3
- data/sig/shims.rbs +0 -47
@@ -7,7 +7,7 @@ module RBS
|
|
7
7
|
include Base
|
8
8
|
|
9
9
|
attr_reader :path, :full_path
|
10
|
-
|
10
|
+
|
11
11
|
def initialize(path:, base_directory:)
|
12
12
|
# TODO: resolve relative path from dir of rbs_collection.yaml
|
13
13
|
@path = Pathname(path)
|
@@ -33,22 +33,24 @@ module RBS
|
|
33
33
|
from = @full_path.join(name, version)
|
34
34
|
gem_dir = dest.join(name, version)
|
35
35
|
|
36
|
+
colored_io = CLI::ColoredIO.new(stdout: stdout)
|
37
|
+
|
36
38
|
case
|
37
39
|
when gem_dir.symlink? && gem_dir.readlink == from
|
38
|
-
|
40
|
+
colored_io.puts "Using #{name}:#{version} (#{from})"
|
39
41
|
when gem_dir.symlink?
|
40
42
|
prev = gem_dir.readlink
|
41
43
|
gem_dir.unlink
|
42
44
|
_install(from, dest.join(name, version))
|
43
|
-
|
45
|
+
colored_io.puts_green("Updating #{name}:#{version} to #{from} from #{prev}")
|
44
46
|
when gem_dir.directory?
|
45
47
|
# TODO: Show version of git source
|
46
48
|
FileUtils.remove_entry_secure(gem_dir.to_s)
|
47
49
|
_install(from, dest.join(name, version))
|
48
|
-
|
50
|
+
colored_io.puts_green("Updating #{name}:#{version} from git source")
|
49
51
|
when !gem_dir.exist?
|
50
52
|
_install(from, dest.join(name, version))
|
51
|
-
|
53
|
+
colored_io.puts_green("Installing #{name}:#{version} (#{from})")
|
52
54
|
else
|
53
55
|
raise
|
54
56
|
end
|
data/lib/rbs/diff.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Diff
|
5
|
+
def initialize(type_name:, library_options:, after_path: [], before_path: [])
|
6
|
+
@type_name = type_name
|
7
|
+
@library_options = library_options
|
8
|
+
@after_path = after_path
|
9
|
+
@before_path = before_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def each_diff(&block)
|
13
|
+
return to_enum(:each_diff) unless block
|
14
|
+
|
15
|
+
before_instance_methods, before_singleton_methods, before_constant_children = build_methods(@before_path)
|
16
|
+
after_instance_methods, after_singleton_methods, after_constant_children = build_methods(@after_path)
|
17
|
+
|
18
|
+
each_diff_methods(:instance, before_instance_methods, after_instance_methods, &block)
|
19
|
+
each_diff_methods(:singleton, before_singleton_methods, after_singleton_methods, &block)
|
20
|
+
|
21
|
+
each_diff_constants(before_constant_children, after_constant_children, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def each_diff_methods(kind, before_methods, after_methods)
|
27
|
+
all_keys = before_methods.keys.to_set + after_methods.keys.to_set
|
28
|
+
all_keys.each do |key|
|
29
|
+
before = definition_method_to_s(key, kind, before_methods[key]) or next
|
30
|
+
after = definition_method_to_s(key, kind, after_methods[key]) or next
|
31
|
+
next if before == after
|
32
|
+
|
33
|
+
yield before, after
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def each_diff_constants(before_constant_children, after_constant_children)
|
38
|
+
all_keys = before_constant_children.keys.to_set + after_constant_children.keys.to_set
|
39
|
+
all_keys.each do |key|
|
40
|
+
before = constant_to_s(before_constant_children[key]) or next
|
41
|
+
after = constant_to_s(after_constant_children[key]) or next
|
42
|
+
next if before == after
|
43
|
+
|
44
|
+
yield before, after
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_methods(path)
|
49
|
+
env = build_env(path)
|
50
|
+
builder = build_builder(env)
|
51
|
+
|
52
|
+
instance_methods = begin
|
53
|
+
builder.build_instance(@type_name).methods
|
54
|
+
rescue => e
|
55
|
+
RBS.logger.warn("#{path}: (#{e.class}) #{e.message}")
|
56
|
+
{}
|
57
|
+
end
|
58
|
+
singleton_methods = begin
|
59
|
+
builder.build_singleton(@type_name).methods
|
60
|
+
rescue => e
|
61
|
+
RBS.logger.warn("#{path}: (#{e.class}) #{e.message}")
|
62
|
+
{}
|
63
|
+
end
|
64
|
+
|
65
|
+
constant_children = begin
|
66
|
+
constant_resolver = RBS::Resolver::ConstantResolver.new(builder: builder)
|
67
|
+
constant_resolver.children(@type_name)
|
68
|
+
rescue => e
|
69
|
+
RBS.logger.warn("#{path}: (#{e.class}) #{e.message}")
|
70
|
+
{}
|
71
|
+
end
|
72
|
+
|
73
|
+
[ instance_methods, singleton_methods, constant_children ]
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_env(path)
|
77
|
+
loader = @library_options.loader()
|
78
|
+
path&.each do |dir|
|
79
|
+
dir_pathname = Pathname(dir)
|
80
|
+
loader.add(path: dir_pathname)
|
81
|
+
|
82
|
+
manifest_pathname = dir_pathname / 'manifest.yaml'
|
83
|
+
if manifest_pathname.exist?
|
84
|
+
manifest = YAML.safe_load(manifest_pathname.read)
|
85
|
+
if manifest['dependencies']
|
86
|
+
manifest['dependencies'].each do |dependency|
|
87
|
+
loader.add(library: dependency['name'], version: nil)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
Environment.from_loader(loader)
|
93
|
+
end
|
94
|
+
|
95
|
+
def build_builder(env)
|
96
|
+
DefinitionBuilder.new(env: env.resolve_type_names)
|
97
|
+
end
|
98
|
+
|
99
|
+
def definition_method_to_s(key, kind, definition_method)
|
100
|
+
if definition_method
|
101
|
+
prefix = kind == :instance ? "" : "self."
|
102
|
+
|
103
|
+
if definition_method.alias_of
|
104
|
+
"alias #{prefix}#{key} #{prefix}#{definition_method.alias_of.defs.first.member.name}"
|
105
|
+
else
|
106
|
+
"def #{prefix}#{key}: #{definition_method.method_types.join(" | ")}"
|
107
|
+
end
|
108
|
+
else
|
109
|
+
+"-"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def constant_to_s(constant)
|
114
|
+
if constant
|
115
|
+
"#{constant.name.name}: #{constant.type}"
|
116
|
+
else
|
117
|
+
+"-"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/rbs/environment.rb
CHANGED
@@ -276,9 +276,9 @@ module RBS
|
|
276
276
|
end
|
277
277
|
|
278
278
|
def normalize_type_name?(name)
|
279
|
-
if name.class?
|
280
|
-
|
281
|
-
|
279
|
+
return normalize_module_name?(name) if name.class?
|
280
|
+
|
281
|
+
type_name =
|
282
282
|
unless name.namespace.empty?
|
283
283
|
parent = name.namespace.to_type_name
|
284
284
|
parent = normalize_module_name?(parent)
|
@@ -288,6 +288,9 @@ module RBS
|
|
288
288
|
else
|
289
289
|
name
|
290
290
|
end
|
291
|
+
|
292
|
+
if type_name?(type_name)
|
293
|
+
type_name
|
291
294
|
end
|
292
295
|
end
|
293
296
|
|
@@ -438,7 +441,7 @@ module RBS
|
|
438
441
|
|
439
442
|
when AST::Declarations::Global
|
440
443
|
if entry = global_decls[decl.name]
|
441
|
-
raise DuplicatedDeclarationError.new(name, decl, entry.decl)
|
444
|
+
raise DuplicatedDeclarationError.new(decl.name, decl, entry.decl)
|
442
445
|
end
|
443
446
|
|
444
447
|
global_decls[decl.name] = GlobalEntry.new(name: decl.name, decl: decl, outer: outer)
|
data/lib/rbs/method_type.rb
CHANGED
@@ -86,6 +86,9 @@ module RBS
|
|
86
86
|
type.each_type(&block)
|
87
87
|
self.block&.yield_self do |b|
|
88
88
|
b.type.each_type(&block)
|
89
|
+
if b.self_type
|
90
|
+
yield b.self_type
|
91
|
+
end
|
89
92
|
end
|
90
93
|
else
|
91
94
|
enum_for :each_type
|
@@ -114,5 +117,25 @@ module RBS
|
|
114
117
|
def type_param_names
|
115
118
|
type_params.map(&:name)
|
116
119
|
end
|
120
|
+
|
121
|
+
def has_self_type?
|
122
|
+
each_type.any? {|type| type.has_self_type? }
|
123
|
+
end
|
124
|
+
|
125
|
+
def has_classish_type?
|
126
|
+
each_type.any? {|type| type.has_classish_type? }
|
127
|
+
end
|
128
|
+
|
129
|
+
def with_nonreturn_void?
|
130
|
+
if type.with_nonreturn_void?
|
131
|
+
true
|
132
|
+
else
|
133
|
+
if block = block()
|
134
|
+
block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false
|
135
|
+
else
|
136
|
+
false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
117
140
|
end
|
118
141
|
end
|
data/lib/rbs/prototype/rb.rb
CHANGED
@@ -89,8 +89,7 @@ module RBS
|
|
89
89
|
body = "\n" if body.empty?
|
90
90
|
|
91
91
|
comment = AST::Comment.new(string: body, location: nil)
|
92
|
-
if
|
93
|
-
hash[line - 1] = nil
|
92
|
+
if prev_comment = hash.delete(line - 1)
|
94
93
|
hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
|
95
94
|
location: nil)
|
96
95
|
else
|
@@ -362,13 +361,7 @@ module RBS
|
|
362
361
|
end
|
363
362
|
|
364
363
|
when :ITER
|
365
|
-
|
366
|
-
case method_name
|
367
|
-
when :refine
|
368
|
-
# ignore
|
369
|
-
else
|
370
|
-
process_children(node, decls: decls, comments: comments, context: context)
|
371
|
-
end
|
364
|
+
# ignore
|
372
365
|
|
373
366
|
when :CDECL
|
374
367
|
const_name = case
|
data/lib/rbs/prototype/rbi.rb
CHANGED
@@ -246,7 +246,7 @@ module RBS
|
|
246
246
|
end
|
247
247
|
end
|
248
248
|
value_node = node.children.last
|
249
|
-
type = if value_node.type == :CALL && value_node.children[1] == :let
|
249
|
+
type = if value_node && value_node.type == :CALL && value_node.children[1] == :let
|
250
250
|
type_node = each_arg(value_node.children[2]).to_a[1]
|
251
251
|
type_of type_node, variables: current_module&.type_params || []
|
252
252
|
else
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
module Prototype
|
5
|
+
class Runtime
|
6
|
+
module Helpers
|
7
|
+
private
|
8
|
+
|
9
|
+
# Returns the exact name & not compactly declared name
|
10
|
+
def only_name(mod)
|
11
|
+
# No nil check because this method is invoked after checking if the module exists
|
12
|
+
const_name!(mod).split(/::/).last or raise # (A::B::C) => C
|
13
|
+
end
|
14
|
+
|
15
|
+
def const_name!(const)
|
16
|
+
const_name(const) or raise
|
17
|
+
end
|
18
|
+
|
19
|
+
def const_name(const)
|
20
|
+
@module_name_method ||= Module.instance_method(:name)
|
21
|
+
name = @module_name_method.bind(const).call
|
22
|
+
return nil unless name
|
23
|
+
|
24
|
+
begin
|
25
|
+
deprecated, Warning[:deprecated] = Warning[:deprecated], false
|
26
|
+
Object.const_get(name)
|
27
|
+
rescue NameError
|
28
|
+
# Should generate const name if anonymous or internal module (e.g. NameError::message)
|
29
|
+
nil
|
30
|
+
else
|
31
|
+
name
|
32
|
+
ensure
|
33
|
+
Warning[:deprecated] = deprecated
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_type_name(name, full_name: false)
|
38
|
+
*prefix, last = name.split(/::/)
|
39
|
+
|
40
|
+
last or raise
|
41
|
+
|
42
|
+
if full_name
|
43
|
+
if prefix.empty?
|
44
|
+
TypeName.new(name: last.to_sym, namespace: Namespace.empty)
|
45
|
+
else
|
46
|
+
TypeName.new(name: last.to_sym, namespace: Namespace.parse(prefix.join("::")))
|
47
|
+
end
|
48
|
+
else
|
49
|
+
TypeName.new(name: last.to_sym, namespace: Namespace.empty)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def untyped
|
54
|
+
@untyped ||= Types::Bases::Any.new(location: nil)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
module Prototype
|
5
|
+
class Runtime
|
6
|
+
module Reflection
|
7
|
+
def self.object_class(value)
|
8
|
+
@object_class ||= Object.instance_method(:class)
|
9
|
+
@object_class.bind_call(value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.constants_of(mod, inherit = true)
|
13
|
+
@constants_of ||= Module.instance_method(:constants)
|
14
|
+
@constants_of.bind_call(mod, inherit)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module RBS
|
6
|
+
module Prototype
|
7
|
+
class Runtime
|
8
|
+
class ValueObjectBase
|
9
|
+
include Helpers
|
10
|
+
|
11
|
+
def initialize(target_class)
|
12
|
+
@target_class = target_class
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_decl
|
16
|
+
decl = AST::Declarations::Class.new(
|
17
|
+
name: to_type_name(only_name(@target_class)),
|
18
|
+
type_params: [],
|
19
|
+
super_class: build_super_class,
|
20
|
+
members: [],
|
21
|
+
annotations: [],
|
22
|
+
location: nil,
|
23
|
+
comment: nil
|
24
|
+
)
|
25
|
+
|
26
|
+
add_decl_members(decl)
|
27
|
+
|
28
|
+
decl
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# def self.members: () -> [ :foo, :bar ]
|
34
|
+
# def members: () -> [ :foo, :bar ]
|
35
|
+
def build_s_members
|
36
|
+
[:singleton, :instance].map do |kind|
|
37
|
+
AST::Members::MethodDefinition.new(
|
38
|
+
name: :members,
|
39
|
+
overloads: [
|
40
|
+
AST::Members::MethodDefinition::Overload.new(
|
41
|
+
annotations: [],
|
42
|
+
method_type: MethodType.new(
|
43
|
+
type: Types::Function.empty(
|
44
|
+
Types::Tuple.new(
|
45
|
+
types: @target_class.members.map do |member|
|
46
|
+
if member.to_s.ascii_only?
|
47
|
+
Types::Literal.new(literal: member, location: nil)
|
48
|
+
else
|
49
|
+
BuiltinNames::Symbol.instance_type
|
50
|
+
end
|
51
|
+
end,
|
52
|
+
location: nil
|
53
|
+
)
|
54
|
+
),
|
55
|
+
type_params: [],
|
56
|
+
block: nil,
|
57
|
+
location: nil,
|
58
|
+
)
|
59
|
+
)
|
60
|
+
],
|
61
|
+
kind: kind,
|
62
|
+
location: nil,
|
63
|
+
comment: nil,
|
64
|
+
annotations: [],
|
65
|
+
overloading: false,
|
66
|
+
visibility: nil
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# attr_accessor foo: untyped
|
72
|
+
def build_member_accessors(ast_members_class)
|
73
|
+
@target_class.members.map do |member|
|
74
|
+
ast_members_class.new(
|
75
|
+
name: member,
|
76
|
+
ivar_name: nil,
|
77
|
+
type: untyped,
|
78
|
+
kind: :instance,
|
79
|
+
location: nil,
|
80
|
+
comment: nil,
|
81
|
+
annotations: []
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class StructGenerator < ValueObjectBase
|
88
|
+
def self.generatable?(target)
|
89
|
+
return false unless target < Struct
|
90
|
+
# Avoid direct inherited class like `class Option < Struct`
|
91
|
+
return false unless target.respond_to?(:members)
|
92
|
+
|
93
|
+
true
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
CAN_CALL_KEYWORD_INIT_P = Struct.new(:tmp).respond_to?(:keyword_init?)
|
99
|
+
|
100
|
+
def build_super_class
|
101
|
+
AST::Declarations::Class::Super.new(name: TypeName("::Struct"), args: [untyped], location: nil)
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_decl_members(decl)
|
105
|
+
decl.members.concat build_s_new
|
106
|
+
decl.members.concat build_s_keyword_init_p
|
107
|
+
decl.members.concat build_s_members
|
108
|
+
decl.members.concat build_member_accessors(AST::Members::AttrAccessor)
|
109
|
+
end
|
110
|
+
|
111
|
+
# def self.new: (?untyped foo, ?untyped bar) -> instance
|
112
|
+
# | (?foo: untyped, ?bar: untyped) -> instance
|
113
|
+
def build_s_new
|
114
|
+
[:new, :[]].map do |name|
|
115
|
+
new_overloads = []
|
116
|
+
|
117
|
+
if CAN_CALL_KEYWORD_INIT_P
|
118
|
+
case @target_class.keyword_init?
|
119
|
+
when false
|
120
|
+
new_overloads << build_overload_for_positional_arguments
|
121
|
+
when true
|
122
|
+
new_overloads << build_overload_for_keyword_arguments
|
123
|
+
when nil
|
124
|
+
new_overloads << build_overload_for_positional_arguments
|
125
|
+
new_overloads << build_overload_for_keyword_arguments
|
126
|
+
else
|
127
|
+
raise
|
128
|
+
end
|
129
|
+
else
|
130
|
+
new_overloads << build_overload_for_positional_arguments
|
131
|
+
new_overloads << build_overload_for_keyword_arguments
|
132
|
+
end
|
133
|
+
|
134
|
+
AST::Members::MethodDefinition.new(
|
135
|
+
name: name,
|
136
|
+
overloads: new_overloads,
|
137
|
+
kind: :singleton,
|
138
|
+
location: nil,
|
139
|
+
comment: nil,
|
140
|
+
annotations: [],
|
141
|
+
overloading: false,
|
142
|
+
visibility: nil
|
143
|
+
)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def build_overload_for_positional_arguments
|
148
|
+
AST::Members::MethodDefinition::Overload.new(
|
149
|
+
annotations: [],
|
150
|
+
method_type: MethodType.new(
|
151
|
+
type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
|
152
|
+
optional_positionals: @target_class.members.map { |m| Types::Function::Param.new(name: m, type: untyped) },
|
153
|
+
),
|
154
|
+
type_params: [],
|
155
|
+
block: nil,
|
156
|
+
location: nil,
|
157
|
+
)
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
161
|
+
def build_overload_for_keyword_arguments
|
162
|
+
AST::Members::MethodDefinition::Overload.new(
|
163
|
+
annotations: [],
|
164
|
+
method_type: MethodType.new(
|
165
|
+
type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
|
166
|
+
optional_keywords: @target_class.members.to_h { |m| [m, Types::Function::Param.new(name: nil, type: untyped)] },
|
167
|
+
),
|
168
|
+
type_params: [],
|
169
|
+
block: nil,
|
170
|
+
location: nil,
|
171
|
+
)
|
172
|
+
)
|
173
|
+
end
|
174
|
+
|
175
|
+
# def self.keyword_init?: () -> bool?
|
176
|
+
def build_s_keyword_init_p
|
177
|
+
return [] unless CAN_CALL_KEYWORD_INIT_P
|
178
|
+
|
179
|
+
return_type = @target_class.keyword_init?.nil? \
|
180
|
+
? Types::Bases::Nil.new(location: nil)
|
181
|
+
: Types::Literal.new(literal: @target_class.keyword_init?, location: nil)
|
182
|
+
type = Types::Function.empty(return_type)
|
183
|
+
|
184
|
+
[
|
185
|
+
AST::Members::MethodDefinition.new(
|
186
|
+
name: :keyword_init?,
|
187
|
+
overloads: [
|
188
|
+
AST::Members::MethodDefinition::Overload.new(
|
189
|
+
annotations: [],
|
190
|
+
method_type: MethodType.new(
|
191
|
+
type: type,
|
192
|
+
type_params: [],
|
193
|
+
block: nil,
|
194
|
+
location: nil,
|
195
|
+
)
|
196
|
+
)
|
197
|
+
],
|
198
|
+
kind: :singleton,
|
199
|
+
location: nil,
|
200
|
+
comment: nil,
|
201
|
+
annotations: [],
|
202
|
+
overloading: false,
|
203
|
+
visibility: nil
|
204
|
+
)
|
205
|
+
]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class DataGenerator < ValueObjectBase
|
210
|
+
def self.generatable?(target)
|
211
|
+
return false unless RUBY_VERSION >= '3.2'
|
212
|
+
return false unless target < Data
|
213
|
+
# Avoid direct inherited class like `class Option < Data`
|
214
|
+
return false unless target.respond_to?(:members)
|
215
|
+
|
216
|
+
true
|
217
|
+
end
|
218
|
+
|
219
|
+
private
|
220
|
+
|
221
|
+
def build_super_class
|
222
|
+
AST::Declarations::Class::Super.new(name: TypeName("::Data"), args: [], location: nil)
|
223
|
+
end
|
224
|
+
|
225
|
+
def add_decl_members(decl)
|
226
|
+
decl.members.concat build_s_new
|
227
|
+
decl.members.concat build_s_members
|
228
|
+
decl.members.concat build_member_accessors(AST::Members::AttrReader)
|
229
|
+
end
|
230
|
+
|
231
|
+
# def self.new: (untyped foo, untyped bar) -> instance
|
232
|
+
# | (foo: untyped, bar: untyped) -> instance
|
233
|
+
def build_s_new
|
234
|
+
[:new, :[]].map do |name|
|
235
|
+
new_overloads = []
|
236
|
+
|
237
|
+
new_overloads << AST::Members::MethodDefinition::Overload.new(
|
238
|
+
annotations: [],
|
239
|
+
method_type: MethodType.new(
|
240
|
+
type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
|
241
|
+
required_positionals: @target_class.members.map { |m| Types::Function::Param.new(name: m, type: untyped) },
|
242
|
+
),
|
243
|
+
type_params: [],
|
244
|
+
block: nil,
|
245
|
+
location: nil,
|
246
|
+
)
|
247
|
+
)
|
248
|
+
new_overloads << AST::Members::MethodDefinition::Overload.new(
|
249
|
+
annotations: [],
|
250
|
+
method_type: MethodType.new(
|
251
|
+
type: Types::Function.empty(Types::Bases::Instance.new(location: nil)).update(
|
252
|
+
required_keywords: @target_class.members.to_h { |m| [m, Types::Function::Param.new(name: nil, type: untyped)] },
|
253
|
+
),
|
254
|
+
type_params: [],
|
255
|
+
block: nil,
|
256
|
+
location: nil,
|
257
|
+
)
|
258
|
+
)
|
259
|
+
|
260
|
+
AST::Members::MethodDefinition.new(
|
261
|
+
name: name,
|
262
|
+
overloads: new_overloads,
|
263
|
+
kind: :singleton,
|
264
|
+
location: nil,
|
265
|
+
comment: nil,
|
266
|
+
annotations: [],
|
267
|
+
overloading: false,
|
268
|
+
visibility: nil
|
269
|
+
)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|