yoda-language-server 0.4.0 → 0.5.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/Gemfile.lock +5 -3
- data/README.md +50 -48
- data/client/atom/main.js +13 -3
- data/client/vscode/.vscode/launch.json +7 -4
- data/client/vscode/package-lock.json +585 -1454
- data/client/vscode/package.json +10 -7
- data/client/vscode/src/extension.ts +3 -3
- data/client/vscode/src/test/completion.test.ts +39 -0
- data/client/vscode/src/test/helper.ts +38 -0
- data/client/vscode/src/test/index.ts +5 -3
- data/client/vscode/testFixture/completion.rb +1 -0
- data/exe/yoda +1 -20
- data/lib/yoda.rb +2 -1
- data/lib/yoda/commands.rb +34 -0
- data/lib/yoda/commands/base.rb +10 -0
- data/lib/yoda/commands/complete.rb +36 -0
- data/lib/yoda/commands/file_cursor_parsable.rb +29 -0
- data/lib/yoda/{runner → commands}/infer.rb +4 -9
- data/lib/yoda/commands/setup.rb +37 -0
- data/lib/yoda/errors.rb +34 -0
- data/lib/yoda/evaluation/evaluator.rb +2 -0
- data/lib/yoda/server.rb +60 -15
- data/lib/yoda/server/completion_provider.rb +8 -8
- data/lib/yoda/server/definition_provider.rb +8 -8
- data/lib/yoda/server/hover_provider.rb +6 -6
- data/lib/yoda/server/initialization_provider.rb +85 -0
- data/lib/yoda/server/{client_info.rb → session.rb} +6 -2
- data/lib/yoda/server/signature_provider.rb +6 -6
- data/lib/yoda/store/actions.rb +3 -1
- data/lib/yoda/store/actions/build_core_index.rb +44 -0
- data/lib/yoda/store/actions/import_core_library.rb +14 -9
- data/lib/yoda/store/actions/import_gem.rb +98 -0
- data/lib/yoda/store/actions/import_std_library.rb +35 -0
- data/lib/yoda/store/adapters.rb +1 -0
- data/lib/yoda/store/adapters/memory_adapter.rb +81 -0
- data/lib/yoda/store/objects.rb +4 -0
- data/lib/yoda/store/objects/addressable.rb +0 -12
- data/lib/yoda/store/objects/base.rb +4 -14
- data/lib/yoda/store/objects/merger.rb +4 -4
- data/lib/yoda/store/objects/patchable.rb +19 -0
- data/lib/yoda/store/objects/project_status.rb +169 -0
- data/lib/yoda/store/objects/serializable.rb +39 -0
- data/lib/yoda/store/project.rb +28 -114
- data/lib/yoda/store/project/cache.rb +79 -0
- data/lib/yoda/store/project/library_doc_loader.rb +102 -0
- data/lib/yoda/store/query/find_constant.rb +2 -1
- data/lib/yoda/store/registry.rb +15 -0
- data/lib/yoda/store/yard_importer.rb +58 -28
- data/lib/yoda/typing/evaluator.rb +8 -5
- data/lib/yoda/version.rb +1 -1
- data/package.json +32 -11
- data/scripts/benchmark.rb +1 -1
- data/yoda-language-server.gemspec +1 -0
- metadata +37 -7
- data/client/vscode/src/test/extension.test.ts +0 -22
- data/lib/yoda/runner/setup.rb +0 -26
- data/lib/yoda/store/actions/import_gems.rb +0 -91
data/lib/yoda/store/project.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require 'bundler'
|
2
|
-
require 'tmpdir'
|
3
1
|
require 'fileutils'
|
4
|
-
require 'digest'
|
5
2
|
|
6
3
|
module Yoda
|
7
4
|
module Store
|
8
5
|
class Project
|
6
|
+
require 'yoda/store/project/cache'
|
7
|
+
require 'yoda/store/project/library_doc_loader'
|
8
|
+
|
9
9
|
# @type String
|
10
10
|
attr_reader :root_path
|
11
11
|
|
@@ -20,20 +20,33 @@ module Yoda
|
|
20
20
|
@registry = Registry.new
|
21
21
|
end
|
22
22
|
|
23
|
-
def clean
|
24
|
-
end
|
25
|
-
|
26
23
|
def setup
|
27
24
|
YARD::Logger.instance(STDERR)
|
28
25
|
make_dir
|
29
|
-
cache.
|
26
|
+
cache.register_adapter(registry)
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear
|
30
|
+
setup
|
31
|
+
registry.adapter.clear
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Array<BaseError>]
|
35
|
+
def build_cache(progress: false)
|
36
|
+
setup
|
37
|
+
loader = LibraryDocLoader.build_for(self)
|
38
|
+
loader.run(progress: progress)
|
30
39
|
load_project_files
|
31
|
-
|
40
|
+
loader.errors
|
32
41
|
end
|
33
42
|
|
34
43
|
def rebuild_cache(progress: false)
|
35
|
-
|
36
|
-
|
44
|
+
clear
|
45
|
+
build_cache(progress: progress)
|
46
|
+
end
|
47
|
+
|
48
|
+
def yoda_dir
|
49
|
+
File.expand_path('.yoda', root_path)
|
37
50
|
end
|
38
51
|
|
39
52
|
# @param source_path [String]
|
@@ -41,118 +54,19 @@ module Yoda
|
|
41
54
|
Actions::ReadFile.run(registry, source_path)
|
42
55
|
end
|
43
56
|
|
44
|
-
def yoda_dir
|
45
|
-
File.expand_path('.yoda', root_path)
|
46
|
-
end
|
47
|
-
|
48
57
|
private
|
49
58
|
|
50
|
-
def make_dir
|
51
|
-
File.exist?(yoda_dir) || FileUtils.mkdir(yoda_dir)
|
52
|
-
end
|
53
|
-
|
54
59
|
def load_project_files
|
55
60
|
Actions::ReadProjectFiles.new(registry, root_path).run
|
56
61
|
end
|
57
62
|
|
58
|
-
def
|
59
|
-
|
63
|
+
def make_dir
|
64
|
+
File.exist?(yoda_dir) || FileUtils.mkdir(yoda_dir)
|
60
65
|
end
|
61
66
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
attr_reader :registry
|
66
|
-
|
67
|
-
# @return [String]
|
68
|
-
attr_reader :root_path
|
69
|
-
|
70
|
-
# @return [String]
|
71
|
-
attr_reader :gemfile_lock_path
|
72
|
-
|
73
|
-
def initialize(registry, root_path, gemfile_lock_path)
|
74
|
-
@registry = registry
|
75
|
-
@root_path = root_path
|
76
|
-
@gemfile_lock_path = gemfile_lock_path
|
77
|
-
end
|
78
|
-
|
79
|
-
def run(progress: false)
|
80
|
-
Actions::ImportCoreLibrary.new(registry).run
|
81
|
-
if File.exist?(gemfile_lock_path)
|
82
|
-
Actions::ImportGems.new(registry, gemfile_lock_parser.specs).run
|
83
|
-
end
|
84
|
-
registry.compress_and_save(progress: progress)
|
85
|
-
end
|
86
|
-
|
87
|
-
def gemfile_lock_parser
|
88
|
-
Dir.chdir(root_path) do
|
89
|
-
Bundler::LockfileParser.new(File.read(gemfile_lock_path))
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# @return [Project]
|
95
|
-
attr_reader :project
|
96
|
-
|
97
|
-
def initialize(project)
|
98
|
-
@project = project
|
99
|
-
end
|
100
|
-
|
101
|
-
def build(progress: false)
|
102
|
-
STDERR.puts 'Constructing database for the current project.'
|
103
|
-
YARD::Logger.instance(STDERR)
|
104
|
-
make_cache_dir
|
105
|
-
register_adapter
|
106
|
-
project.registry.adapter.clear
|
107
|
-
Builder.new(project.registry, project.root_path, gemfile_lock_path).run(progress: progress)
|
108
|
-
STDERR.puts 'Finished to construct database for the current project.'
|
109
|
-
end
|
110
|
-
|
111
|
-
def setup
|
112
|
-
if present?
|
113
|
-
register_adapter
|
114
|
-
else
|
115
|
-
build
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
private
|
120
|
-
|
121
|
-
# @return [true, false]
|
122
|
-
def present?
|
123
|
-
File.exist?(cache_path)
|
124
|
-
end
|
125
|
-
|
126
|
-
def register_adapter
|
127
|
-
return if project.registry.adapter
|
128
|
-
project.registry.adapter = Adapters.default_adapter_class.for(cache_path)
|
129
|
-
end
|
130
|
-
|
131
|
-
def cache_dir
|
132
|
-
File.expand_path('cache', project.yoda_dir)
|
133
|
-
end
|
134
|
-
|
135
|
-
def cache_name
|
136
|
-
@cache_path ||= begin
|
137
|
-
digest = Digest::SHA256.new
|
138
|
-
digest.file(gemfile_lock_path) if File.exist?(gemfile_lock_path)
|
139
|
-
digest.update(Yoda::VERSION)
|
140
|
-
digest.update(Adapters.default_adapter_class.type.to_s)
|
141
|
-
digest.hexdigest
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def cache_path
|
146
|
-
File.expand_path(cache_name, cache_dir)
|
147
|
-
end
|
148
|
-
|
149
|
-
def make_cache_dir
|
150
|
-
File.exist?(cache_dir) || FileUtils.mkdir_p(cache_dir)
|
151
|
-
end
|
152
|
-
|
153
|
-
def gemfile_lock_path
|
154
|
-
File.absolute_path('Gemfile.lock', project.root_path)
|
155
|
-
end
|
67
|
+
# @return [Cache]
|
68
|
+
def cache
|
69
|
+
@cache ||= Cache.build_for(self)
|
156
70
|
end
|
157
71
|
end
|
158
72
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'bundler'
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'digest'
|
5
|
+
|
6
|
+
module Yoda
|
7
|
+
module Store
|
8
|
+
class Project
|
9
|
+
# Find registry file for the current project settings.
|
10
|
+
class Cache
|
11
|
+
class << self
|
12
|
+
# @param project_dir [String]
|
13
|
+
# @return [String]
|
14
|
+
def cache_dir(project_dir)
|
15
|
+
File.expand_path('.yoda/cache', project_dir)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param project_dir [String]
|
19
|
+
# @return [String]
|
20
|
+
def gemfile_lock_path(project_dir)
|
21
|
+
File.absolute_path('Gemfile.lock', project_dir)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param project [Project]
|
25
|
+
def build_for(project)
|
26
|
+
new(cache_dir_path: cache_dir(project.root_path), gemfile_lock_path: gemfile_lock_path(project.root_path))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [String]
|
31
|
+
attr_reader :cache_dir_path
|
32
|
+
|
33
|
+
# @return [String, nil]
|
34
|
+
attr_reader :gemfile_lock_path
|
35
|
+
|
36
|
+
# @param cache_dir_path [String]
|
37
|
+
# @param gemfile_lock_path [String, nil]
|
38
|
+
def initialize(cache_dir_path:, gemfile_lock_path: nil)
|
39
|
+
@cache_dir_path = cache_dir_path
|
40
|
+
@gemfile_lock_path = gemfile_lock_path
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [true, false]
|
44
|
+
def present?
|
45
|
+
File.exist?(cache_path)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param registry [Registry]
|
49
|
+
def register_adapter(registry)
|
50
|
+
return if registry.adapter
|
51
|
+
make_cache_dir
|
52
|
+
registry.adapter = Adapters.default_adapter_class.for(cache_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String]
|
56
|
+
def cache_path
|
57
|
+
File.expand_path(cache_name, cache_dir_path)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# @return [String]
|
63
|
+
def cache_name
|
64
|
+
@cache_path ||= begin
|
65
|
+
digest = Digest::SHA256.new
|
66
|
+
digest.file(gemfile_lock_path) if gemfile_lock_path && File.exist?(gemfile_lock_path)
|
67
|
+
digest.update(Registry::REGISTRY_VERSION.to_s)
|
68
|
+
digest.update(Adapters.default_adapter_class.type.to_s)
|
69
|
+
digest.hexdigest
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def make_cache_dir
|
74
|
+
File.exist?(cache_dir_path) || FileUtils.mkdir_p(cache_dir_path)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Yoda
|
2
|
+
module Store
|
3
|
+
class Project
|
4
|
+
class LibraryDocLoader
|
5
|
+
# @return [Registry]
|
6
|
+
attr_reader :registry
|
7
|
+
|
8
|
+
# @param gem_specs [Array<Objects::ProjectStatus::GemStatus, Bundler::LazySpecification>]
|
9
|
+
attr_reader :gem_specs
|
10
|
+
|
11
|
+
# @param errors [Array<BaseError>]
|
12
|
+
attr_reader :errors
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# @param project [Project]
|
16
|
+
# @return [LibraryDocLoader]
|
17
|
+
def build_for(project)
|
18
|
+
lockfile_parser = parse_gemfile_lock(project.root_path, Cache.gemfile_lock_path(project.root_path))
|
19
|
+
new(registry: project.registry, gem_specs: lockfile_parser&.specs || [])
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# @return [Bundler::LockfileParser, nil]
|
25
|
+
def parse_gemfile_lock(root_path, gemfile_lock_path)
|
26
|
+
return if !gemfile_lock_path || !File.exists?(gemfile_lock_path)
|
27
|
+
Dir.chdir(root_path) do
|
28
|
+
Bundler::LockfileParser.new(File.read(gemfile_lock_path))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param registry [Registry]
|
34
|
+
# @param gem_specs [Array<Objects::ProjectStatus::GemStatus, Bundler::LazySpecification>]
|
35
|
+
def initialize(registry:, gem_specs:)
|
36
|
+
@registry = registry
|
37
|
+
@gem_specs = gem_specs
|
38
|
+
@errors = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def run(progress: false)
|
42
|
+
project_status = registry.project_status || Objects::ProjectStatus.initial_build(specs: gem_specs)
|
43
|
+
new_bundle_status = update_bundle(project_status.bundle, progress: progress)
|
44
|
+
registry.save_project_status(project_status.derive(bundle: new_bundle_status))
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
50
|
+
# @return [Objects::ProjectStatus::BundleStatus]
|
51
|
+
def update_bundle(bundle_status, progress: false)
|
52
|
+
unless bundle_status.all_present?
|
53
|
+
STDERR.puts 'Constructing database for the current project.'
|
54
|
+
bundle_status = import_deps(bundle_status)
|
55
|
+
registry.compress_and_save(progress: progress)
|
56
|
+
end
|
57
|
+
bundle_status
|
58
|
+
end
|
59
|
+
|
60
|
+
# Try to import missing gems and core libraries.
|
61
|
+
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
62
|
+
# @return [Objects::ProjectStatus::BundleStatus]
|
63
|
+
def import_deps(bundle_status)
|
64
|
+
bundle_status = import_core(bundle_status) unless bundle_status.std_status.core_present?
|
65
|
+
bundle_status = import_std(bundle_status) unless bundle_status.std_status.std_present?
|
66
|
+
import_gems(bundle_status)
|
67
|
+
end
|
68
|
+
|
69
|
+
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
70
|
+
# @return [Objects::ProjectStatus::BundleStatus]
|
71
|
+
def import_core(bundle_status)
|
72
|
+
result = Actions::ImportCoreLibrary.run(registry)
|
73
|
+
errors.push(CoreImportError.new('core')) unless result
|
74
|
+
bundle_status.derive(std_status: bundle_status.std_status.derive(core_present: !!result))
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
78
|
+
# @return [Objects::ProjectStatus::BundleStatus]
|
79
|
+
def import_std(bundle_status)
|
80
|
+
result = Actions::ImportStdLibrary.run(registry)
|
81
|
+
errors.push(CoreImportError.new('std')) unless result
|
82
|
+
bundle_status.derive(std_status: bundle_status.std_status.derive(std_present: !!result))
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
86
|
+
# @return [Objects::ProjectStatus::BundleStatus]
|
87
|
+
def import_gems(bundle_status)
|
88
|
+
gem_statuses = bundle_status.gem_statuses.map do |gem_status|
|
89
|
+
if gem_status.present?
|
90
|
+
gem_status
|
91
|
+
else
|
92
|
+
result = Actions::ImportGem.run(registry: registry, gem_name: gem_status.name, gem_version: gem_status.version)
|
93
|
+
errors.push(GemImportError.new(name: gem_status.name, version: gem_status.version)) unless result
|
94
|
+
gem_status.derive(present: result)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
bundle_status.derive(gem_statuses: gem_statuses)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -62,7 +62,8 @@ module Yoda
|
|
62
62
|
constant_names = path_of(name).split
|
63
63
|
namespace = registry.find('Object') unless namespace
|
64
64
|
constant_names.reduce(namespace) do |namespace, name|
|
65
|
-
if namespace
|
65
|
+
# @todo resolve its value if namespace is ValueObject
|
66
|
+
if namespace && namespace.is_a?(Objects::NamespaceObject)
|
66
67
|
select_constants_from_ancestors(namespace, name).first
|
67
68
|
else
|
68
69
|
return nil
|
data/lib/yoda/store/registry.rb
CHANGED
@@ -4,6 +4,9 @@ require 'ruby-progressbar'
|
|
4
4
|
module Yoda
|
5
5
|
module Store
|
6
6
|
class Registry
|
7
|
+
# @note This number must be updated when breaking change is added.
|
8
|
+
REGISTRY_VERSION = 1
|
9
|
+
|
7
10
|
# @return [Adapters::LmdbAdapter, nil]
|
8
11
|
attr_reader :adapter
|
9
12
|
|
@@ -13,11 +16,23 @@ module Yoda
|
|
13
16
|
# @return [Objects::PatchSet]
|
14
17
|
attr_reader :patch_set
|
15
18
|
|
19
|
+
PROJECT_STATUS_KEY = '%project_status'
|
20
|
+
|
16
21
|
def initialize(adapter = nil)
|
17
22
|
@patch_set = Objects::PatchSet.new
|
18
23
|
@adapter = adapter
|
19
24
|
end
|
20
25
|
|
26
|
+
# @return [Objects::ProjectStatus, nil]
|
27
|
+
def project_status
|
28
|
+
adapter&.exist?(PROJECT_STATUS_KEY) && adapter.get(PROJECT_STATUS_KEY)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param new_project_status [Objects::ProjectStatus]
|
32
|
+
def save_project_status(new_project_status)
|
33
|
+
adapter.put(PROJECT_STATUS_KEY, new_project_status)
|
34
|
+
end
|
35
|
+
|
21
36
|
# @param path [String]
|
22
37
|
# @return [Objects::Base, nil]
|
23
38
|
def find(path)
|
@@ -73,26 +73,33 @@ module Yoda
|
|
73
73
|
# @param code_object [::YARD::CodeObjects::NamespaceObject]
|
74
74
|
# @return [Objects::ClassObject]
|
75
75
|
def convert_root_object(code_object)
|
76
|
-
|
77
|
-
|
78
|
-
path: 'Object',
|
76
|
+
object_class = Objects::ClassObject.new(
|
77
|
+
path: path_to_store(code_object),
|
79
78
|
document: code_object.docstring.to_s,
|
80
79
|
tag_list: code_object.tags.map { |tag| convert_tag(tag, '') },
|
81
80
|
sources: code_object.files.map(&method(:convert_source)),
|
82
81
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
83
82
|
instance_method_addresses: code_object.meths(included: false, scope: :instance).map(&:path),
|
84
|
-
mixin_addresses: code_object.instance_mixins.map { |mixin| mixin
|
83
|
+
mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
|
85
84
|
constant_addresses: (code_object.children.select{ |child| %i(constant module class).include?(child.type) }.map { |constant| constant.path } + ['Object']).uniq,
|
86
85
|
)
|
86
|
+
object_meta_class = Objects::MetaClassObject.new(
|
87
|
+
path: path_to_store(code_object),
|
88
|
+
sources: code_object.files.map(&method(:convert_source)),
|
89
|
+
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
90
|
+
instance_method_addresses: code_object.meths(included: false, scope: :class).map(&:path),
|
91
|
+
mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
|
92
|
+
)
|
93
|
+
[object_class, object_meta_class]
|
87
94
|
end
|
88
95
|
|
89
96
|
# @param code_object [::YARD::CodeObjects::ConstantObject]
|
90
97
|
# @return [Objects::ValueObject]
|
91
98
|
def convert_constant_object(code_object)
|
92
99
|
Objects::ValueObject.new(
|
93
|
-
path: code_object
|
100
|
+
path: path_to_store(code_object),
|
94
101
|
document: code_object.docstring.to_s,
|
95
|
-
tag_list: code_object.tags.map { |tag| convert_tag(tag, code_object.namespace
|
102
|
+
tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object.namespace)) },
|
96
103
|
sources: code_object.files.map(&method(:convert_source)),
|
97
104
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
98
105
|
value: code_object.value,
|
@@ -107,8 +114,8 @@ module Yoda
|
|
107
114
|
method_object = Objects::MethodObject.new(
|
108
115
|
path: "Object#{code_object.sep}#{code_object.name}",
|
109
116
|
document: code_object.docstring.to_s,
|
110
|
-
tag_list: code_object.tags.map { |tag| convert_tag(tag, code_object.namespace
|
111
|
-
overloads: code_object.tags(:overload).map { |tag| convert_overload_tag(tag, code_object.namespace
|
117
|
+
tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object.namespace)) },
|
118
|
+
overloads: code_object.tags(:overload).map { |tag| convert_overload_tag(tag, path_to_store(code_object.namespace)) },
|
112
119
|
sources: code_object.files.map(&method(:convert_source)),
|
113
120
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
114
121
|
parameters: code_object.parameters,
|
@@ -121,10 +128,10 @@ module Yoda
|
|
121
128
|
[method_object, object_object]
|
122
129
|
else
|
123
130
|
Objects::MethodObject.new(
|
124
|
-
path: code_object
|
131
|
+
path: path_to_store(code_object),
|
125
132
|
document: code_object.docstring.to_s,
|
126
|
-
tag_list: code_object.tags.map { |tag| convert_tag(tag, code_object.namespace
|
127
|
-
overloads: code_object.tags(:overload).map { |tag| convert_overload_tag(tag, code_object.namespace
|
133
|
+
tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object.namespace)) },
|
134
|
+
overloads: code_object.tags(:overload).map { |tag| convert_overload_tag(tag, path_to_store(code_object.namespace)) },
|
128
135
|
sources: code_object.files.map(&method(:convert_source)),
|
129
136
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
130
137
|
parameters: code_object.parameters,
|
@@ -137,22 +144,22 @@ module Yoda
|
|
137
144
|
# @return [Array<Objects::ModuleObject, Objects::MetaClassObject>]
|
138
145
|
def convert_module_object(code_object)
|
139
146
|
module_object = Objects::ModuleObject.new(
|
140
|
-
path: code_object
|
147
|
+
path: path_to_store(code_object),
|
141
148
|
document: code_object.docstring.to_s,
|
142
|
-
tag_list: code_object.tags.map { |tag| convert_tag(tag, code_object
|
149
|
+
tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object)) },
|
143
150
|
sources: code_object.files.map(&method(:convert_source)),
|
144
151
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
145
152
|
instance_method_addresses: code_object.meths(included: false, scope: :instance).map(&:path),
|
146
|
-
mixin_addresses: code_object.instance_mixins.map { |mixin| mixin
|
153
|
+
mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
|
147
154
|
constant_addresses: code_object.children.select{ |child| %i(constant module class).include?(child.type) }.map { |constant| constant.path },
|
148
155
|
)
|
149
156
|
|
150
157
|
meta_class_object = Objects::MetaClassObject.new(
|
151
|
-
path: code_object
|
158
|
+
path: path_to_store(code_object),
|
152
159
|
sources: code_object.files.map(&method(:convert_source)),
|
153
160
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
154
161
|
instance_method_addresses: code_object.meths(included: false, scope: :class).map(&:path),
|
155
|
-
mixin_addresses: code_object.instance_mixins.map { |mixin| mixin
|
162
|
+
mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
|
156
163
|
)
|
157
164
|
|
158
165
|
[module_object, meta_class_object]
|
@@ -162,23 +169,23 @@ module Yoda
|
|
162
169
|
# @return [Array<Objects::ClassObject, Objects::MetaClassObject>]
|
163
170
|
def convert_class_object(code_object)
|
164
171
|
class_object = Objects::ClassObject.new(
|
165
|
-
path: code_object
|
172
|
+
path: path_to_store(code_object),
|
166
173
|
document: code_object.docstring.to_s,
|
167
|
-
tag_list: code_object.tags.map { |tag| convert_tag(tag, code_object
|
174
|
+
tag_list: code_object.tags.map { |tag| convert_tag(tag, path_to_store(code_object)) },
|
168
175
|
sources: code_object.files.map(&method(:convert_source)),
|
169
176
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
170
177
|
instance_method_addresses: code_object.meths(included: false, scope: :instance).map(&:path),
|
171
|
-
mixin_addresses: code_object.instance_mixins.map { |mixin| mixin
|
172
|
-
constant_addresses: code_object.children.select{ |child| %i(constant module class).include?(child.type) }.map { |constant| constant
|
173
|
-
superclass_path: code_object.superclass&.path == 'Qnil' ? nil : code_object.superclass
|
178
|
+
mixin_addresses: code_object.instance_mixins.map { |mixin| path_to_store(mixin) },
|
179
|
+
constant_addresses: code_object.children.select{ |child| %i(constant module class).include?(child.type) }.map { |constant| path_to_store(constant) },
|
180
|
+
superclass_path: !code_object.superclass || code_object.superclass&.path == 'Qnil' ? nil : path_to_store(code_object.superclass),
|
174
181
|
)
|
175
182
|
|
176
183
|
meta_class_object = Objects::MetaClassObject.new(
|
177
|
-
path: code_object
|
184
|
+
path: path_to_store(code_object),
|
178
185
|
sources: code_object.files.map(&method(:convert_source)),
|
179
186
|
primary_source: code_object[:current_file_has_comments] ? convert_source(code_object.files.first) : nil,
|
180
187
|
instance_method_addresses: code_object.meths(included: false, scope: :class).map(&:path),
|
181
|
-
mixin_addresses: code_object.class_mixins.map { |mixin| mixin
|
188
|
+
mixin_addresses: code_object.class_mixins.map { |mixin| path_to_store(mixin) },
|
182
189
|
)
|
183
190
|
|
184
191
|
[class_object, meta_class_object]
|
@@ -220,7 +227,7 @@ module Yoda
|
|
220
227
|
# @return [Array<Objects::ModuleObject>]
|
221
228
|
def create_proxy_module(code_object)
|
222
229
|
module_object = Objects::ModuleObject.new(
|
223
|
-
path: code_object
|
230
|
+
path: path_to_store(code_object),
|
224
231
|
document: '',
|
225
232
|
tag_list: [],
|
226
233
|
sources: [],
|
@@ -231,7 +238,7 @@ module Yoda
|
|
231
238
|
)
|
232
239
|
|
233
240
|
meta_class_object = Objects::MetaClassObject.new(
|
234
|
-
path: code_object
|
241
|
+
path: path_to_store(code_object),
|
235
242
|
sources: [],
|
236
243
|
primary_source: nil,
|
237
244
|
instance_method_addresses: [],
|
@@ -244,9 +251,9 @@ module Yoda
|
|
244
251
|
# @param code_object [::YARD::CodeObjects::Base]
|
245
252
|
# @return [vaid]
|
246
253
|
def register_to_parent_proxy(code_object)
|
247
|
-
proxy_module = patch.find(code_object.parent
|
248
|
-
proxy_module.instance_method_addresses.push(code_object
|
249
|
-
proxy_module.constant_addresses.push(code_object
|
254
|
+
proxy_module = patch.find(path_to_store(code_object.parent))
|
255
|
+
proxy_module.instance_method_addresses.push(path_to_store(code_object)) if code_object.type == :method
|
256
|
+
proxy_module.constant_addresses.push(path_to_store(code_object)) if [:class, :module, :proxy].include?(code_object.type)
|
250
257
|
end
|
251
258
|
|
252
259
|
# @param source [(String, Integer)]
|
@@ -255,6 +262,29 @@ module Yoda
|
|
255
262
|
file, line = source
|
256
263
|
[root_path ? File.expand_path(file, root_path) : file, line, 0]
|
257
264
|
end
|
265
|
+
|
266
|
+
# @param code_object [::YARD::CodeObjects::Base]
|
267
|
+
# @return [String]
|
268
|
+
def path_to_store(object)
|
269
|
+
@paths_to_store ||= {}
|
270
|
+
@paths_to_store[[object.type, object.path]] ||= calc_path_to_store(object)
|
271
|
+
end
|
272
|
+
|
273
|
+
# @param code_object [::YARD::CodeObjects::Base]
|
274
|
+
# @return [String]
|
275
|
+
def calc_path_to_store(object)
|
276
|
+
return 'Object' if object.root?
|
277
|
+
parent_path = path_to_store(object.parent)
|
278
|
+
|
279
|
+
if object.type == :proxy || object.is_a?(YARD::CodeObjects::Proxy)
|
280
|
+
# For now, we suppose the proxy object exists directly under its lexical namespace.
|
281
|
+
[path_to_store(object.parent), object.name].join('::')
|
282
|
+
elsif object.parent.path == path_to_store(object.parent)
|
283
|
+
object.path
|
284
|
+
else
|
285
|
+
[path_to_store(object.parent), object.name].join(object.sep)
|
286
|
+
end.gsub(/^Object::/, '')
|
287
|
+
end
|
258
288
|
end
|
259
289
|
end
|
260
290
|
end
|