yoda-language-server 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/client/vscode/package-lock.json +6 -6
  4. data/client/vscode/src/check-versions.ts +5 -11
  5. data/client/vscode/src/install-tools.ts +1 -1
  6. data/lib/yoda/cli/analyze_deps.rb +46 -25
  7. data/lib/yoda/id_mask.rb +84 -0
  8. data/lib/yoda/model/descriptions/require_path_description.rb +45 -0
  9. data/lib/yoda/model/descriptions.rb +1 -0
  10. data/lib/yoda/model/node_signatures/node.rb +9 -1
  11. data/lib/yoda/model/values/literal_value.rb +3 -0
  12. data/lib/yoda/parsing/location.rb +9 -0
  13. data/lib/yoda/services/loadable_path_resolver.rb +33 -0
  14. data/lib/yoda/services.rb +1 -0
  15. data/lib/yoda/store/actions/read_project_files.rb +9 -7
  16. data/lib/yoda/store/adapters/gdbm_adapter/namespace_accessor.rb +1 -1
  17. data/lib/yoda/store/adapters/memory_adapter.rb +1 -1
  18. data/lib/yoda/store/objects/libraries_status.rb +1 -1
  19. data/lib/yoda/store/objects/library/core.rb +8 -0
  20. data/lib/yoda/store/objects/library/gem.rb +14 -3
  21. data/lib/yoda/store/objects/library/path_resolvable.rb +29 -0
  22. data/lib/yoda/store/objects/library/std.rb +9 -0
  23. data/lib/yoda/store/objects/library.rb +1 -0
  24. data/lib/yoda/store/objects/patch.rb +1 -1
  25. data/lib/yoda/store/objects/patch_set.rb +2 -2
  26. data/lib/yoda/store/project/dependency.rb +22 -4
  27. data/lib/yoda/store/project/file_finder.rb +20 -0
  28. data/lib/yoda/store/project.rb +2 -0
  29. data/lib/yoda/store/registry/cache.rb +2 -2
  30. data/lib/yoda/store/registry/composer.rb +9 -7
  31. data/lib/yoda/store/registry/index.rb +14 -10
  32. data/lib/yoda/store/registry/library_registry.rb +1 -1
  33. data/lib/yoda/store/registry.rb +1 -1
  34. data/lib/yoda/typing/constant_resolver/code_query.rb +25 -0
  35. data/lib/yoda/typing/constant_resolver/query.rb +12 -1
  36. data/lib/yoda/typing/constant_resolver.rb +13 -8
  37. data/lib/yoda/typing/inferencer/load_resolver.rb +37 -0
  38. data/lib/yoda/typing/inferencer/tracer.rb +32 -0
  39. data/lib/yoda/typing/inferencer.rb +3 -2
  40. data/lib/yoda/typing/node_info.rb +5 -0
  41. data/lib/yoda/typing/tree/{defined.rb → ask_defined.rb} +3 -2
  42. data/lib/yoda/typing/tree/base.rb +65 -20
  43. data/lib/yoda/typing/tree/begin.rb +5 -5
  44. data/lib/yoda/typing/tree/block_call.rb +26 -0
  45. data/lib/yoda/typing/tree/case.rb +8 -19
  46. data/lib/yoda/typing/tree/class_tree.rb +10 -18
  47. data/lib/yoda/typing/tree/conditional_loop.rb +15 -0
  48. data/lib/yoda/typing/tree/constant.rb +19 -0
  49. data/lib/yoda/typing/tree/constant_assignment.rb +2 -2
  50. data/lib/yoda/typing/tree/ensure.rb +17 -0
  51. data/lib/yoda/typing/tree/for.rb +7 -0
  52. data/lib/yoda/typing/tree/hash_tree.rb +32 -0
  53. data/lib/yoda/typing/tree/if.rb +10 -5
  54. data/lib/yoda/typing/tree/interpolation_text.rb +21 -0
  55. data/lib/yoda/typing/tree/literal.rb +8 -36
  56. data/lib/yoda/typing/tree/literal_inferable.rb +48 -0
  57. data/lib/yoda/typing/tree/local_exit.rb +15 -0
  58. data/lib/yoda/typing/tree/logical_assignment.rb +5 -5
  59. data/lib/yoda/typing/tree/logical_operator.rb +6 -5
  60. data/lib/yoda/typing/tree/method_def.rb +41 -0
  61. data/lib/yoda/typing/tree/method_inferable.rb +51 -0
  62. data/lib/yoda/typing/tree/module_tree.rb +7 -20
  63. data/lib/yoda/typing/tree/multiple_assignment.rb +6 -10
  64. data/lib/yoda/typing/tree/namespace_inferable.rb +20 -0
  65. data/lib/yoda/typing/tree/rescue.rb +18 -0
  66. data/lib/yoda/typing/tree/rescue_clause.rb +42 -0
  67. data/lib/yoda/typing/tree/self.rb +2 -1
  68. data/lib/yoda/typing/tree/send.rb +8 -60
  69. data/lib/yoda/typing/tree/send_inferable.rb +89 -0
  70. data/lib/yoda/typing/tree/singleton_class_tree.rb +24 -0
  71. data/lib/yoda/typing/tree/singleton_method_def.rb +41 -0
  72. data/lib/yoda/typing/tree/super.rb +9 -2
  73. data/lib/yoda/typing/tree/variable.rb +5 -10
  74. data/lib/yoda/typing/tree/variable_assignment.rb +11 -8
  75. data/lib/yoda/typing/tree/yield.rb +9 -2
  76. data/lib/yoda/typing/tree.rb +55 -22
  77. data/lib/yoda/typing.rb +1 -0
  78. data/lib/yoda/version.rb +1 -1
  79. data/lib/yoda.rb +1 -0
  80. metadata +25 -13
  81. data/lib/yoda/typing/inferencer/ast_traverser.rb +0 -408
  82. data/lib/yoda/typing/tree/block.rb +0 -12
  83. data/lib/yoda/typing/tree/const.rb +0 -12
  84. data/lib/yoda/typing/tree/escape.rb +0 -12
  85. data/lib/yoda/typing/tree/hash_body.rb +0 -36
  86. data/lib/yoda/typing/tree/literal_with_interpolation.rb +0 -21
  87. data/lib/yoda/typing/tree/method.rb +0 -43
  88. data/lib/yoda/typing/tree/rescue_body.rb +0 -12
  89. data/lib/yoda/typing/tree/singleton_method.rb +0 -47
  90. data/lib/yoda/typing/tree/while.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52ade5f050c0172759a16bc736b42a0f81217b4efb51a6dd926f6c54c53464dc
4
- data.tar.gz: c1e2b2439b0a22948d01cc5886321e9f6fe6f83142aead6d8466b32e7a54b8b7
3
+ metadata.gz: ac5417cb4b65a5825e8cbbafc5e7c2396dd676f8c9be6635b6ae9721a58d9d4e
4
+ data.tar.gz: 93c16d20eeef7a4af4483df0313814529adeefa8f0561e1fa96f72627730eb5a
5
5
  SHA512:
6
- metadata.gz: 84c53ecfb0696eadb924907812d9614d8df2f71b1b9bc8deac0b92dd2d70180aeb708731f75d96508acace9c6bfb027f2b88d509af0dbd0d42ba7418146c8af5
7
- data.tar.gz: a38c732bc5cfa9eee8d2e343d328073e978eae350bf4806e8d8ffc203e0b4ec0061e7fec7df0925375f656a2aa078fd106dc1b695cc87b70c298969bf49a1386
6
+ metadata.gz: 57ab04ba88f6d0047c00ef4a0c92531ddc8a7966dcf10b93c16d01152ea62981bba5eb40d8a94dcaf1c6eea015f710fb44c5a1eca45bc40614b51c5f79325d9e
7
+ data.tar.gz: 7af4d13dd31562946ee5c3dd7e57e5c95b14450dce1b8ab8a9e1719a4b53067f384f069cb522b027158cca2407e9c47d84e86dcf604f940d3cea1cf47318a00d
data/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
1
  ## Unreleased
2
+ ## v0.10.0 - 2022-03-28
3
+
4
+ * Support go to definition on path of require clause
5
+ * Fix inference failure on code with constant node and super node
6
+
2
7
  ## v0.9.0 - 2022-03-22
3
8
 
4
9
  * Support progress report of server initialization
@@ -1472,9 +1472,9 @@
1472
1472
  }
1473
1473
  },
1474
1474
  "node_modules/minimist": {
1475
- "version": "1.2.5",
1476
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
1477
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
1475
+ "version": "1.2.6",
1476
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
1477
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
1478
1478
  "dev": true
1479
1479
  },
1480
1480
  "node_modules/mkdirp": {
@@ -3784,9 +3784,9 @@
3784
3784
  }
3785
3785
  },
3786
3786
  "minimist": {
3787
- "version": "1.2.5",
3788
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
3789
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
3787
+ "version": "1.2.6",
3788
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
3789
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
3790
3790
  "dev": true
3791
3791
  },
3792
3792
  "mkdirp": {
@@ -10,8 +10,11 @@ interface CheckResult {
10
10
  }
11
11
 
12
12
  export async function checkVersions(): Promise<CheckResult> {
13
- const { stdout } = await asyncExec("gem list --both --exact yoda-language-server")
14
- const [localVersion, remoteVersion] = parseGemList(stdout)
13
+ const { stdout: localStdout } = await asyncExec("gem list --local --exact yoda-language-server")
14
+ const localVersion = extractVersion(localStdout)
15
+
16
+ const { stdout: remoteStdout } = await asyncExec("gem list --remote --no-prerelease --exact yoda-language-server")
17
+ const remoteVersion = extractVersion(remoteStdout)
15
18
 
16
19
  return {
17
20
  shouldUpdate: shouldUpdate(localVersion, remoteVersion),
@@ -32,15 +35,6 @@ function shouldUpdate(localVersion: string, remoteVersion: string): boolean {
32
35
  return cmp(localVersion, "<", remoteVersion)
33
36
  }
34
37
 
35
- function parseGemList(stdout: string): [string, string] {
36
- const [local, remote] = stdout.split("*** REMOTE GEMS ***")
37
-
38
- const localVersion = extractVersion(local)
39
- const remoteVersion = extractVersion(remote)
40
-
41
- return [localVersion, remoteVersion]
42
- }
43
-
44
38
  function extractVersion(text: string): string {
45
39
  const lines = text.split("\n")
46
40
  for (const line of lines) {
@@ -44,7 +44,7 @@ export async function promptForInstallTool(update: boolean, newVersion?: string)
44
44
  const newVersionLabel = newVersion ? ` (${newVersion})` : ''
45
45
 
46
46
  const message = update ?
47
- `A newer version of yoda${newVersionLabel} is updatable.` :
47
+ `A newer version of yoda${newVersionLabel} is available.` :
48
48
  'yoda command is not available. Please install.'
49
49
 
50
50
  const selected = await window.showInformationMessage(message, ...choises)
@@ -16,7 +16,7 @@ module Yoda
16
16
 
17
17
  # @param root_path [String]
18
18
  def initialize(root_path)
19
- @root_path = root_path
19
+ @root_path = File.expand_path(root_path)
20
20
  end
21
21
 
22
22
  # @return [Array<Yoda::Store::Objects::Library::Gem>]
@@ -28,6 +28,7 @@ module Yoda
28
28
  {
29
29
  path: root_path,
30
30
  dependencies: gems.map(&:to_h),
31
+ autoload_dependency_ids: autoload_gem_ids,
31
32
  }
32
33
  end
33
34
 
@@ -45,39 +46,47 @@ module Yoda
45
46
  end
46
47
  end
47
48
 
48
- # @return [Array<Bundler::LazySpecification>, nil]
49
+ # @return [Array<String>]
50
+ def autoload_gem_ids
51
+ if has_gemfile?
52
+ gems.map(&:id)
53
+ else
54
+ []
55
+ end
56
+ end
57
+
58
+ # @return [Array<Bundler::LazySpecification, Gem::Specification>, nil]
49
59
  def gem_specs
50
60
  @gem_specs ||= begin
51
- Dir.chdir(root_path) do
52
- with_unbundled_env do
53
- # Suppress bundler outputs to stdout.
54
- Bundler.ui = Bundler::UI::Silent.new
55
-
56
- Bundler.reset!
57
-
58
- if File.exists?("Gemfile")
59
- # Resolve dependencies of uninstalled gems and ensure remote sources are available.
60
- Bundler.definition.resolve_remotely!
61
- spec_set = Bundler.definition.resolve
62
-
63
- if Gem::Version.new(Bundler::VERSION) >= Gem::Version.new('2.2.25')
64
- deps = Bundler.definition.requested_dependencies
65
- spec_set.materialize(deps).to_a
66
- else
67
- # For backward compatibility (Ref: https://github.com/rubygems/rubygems/pull/4788)
68
- deps = Bundler.definition.send(:requested_dependencies)
69
- missing = []
70
- materialized = spec_set.materialize(deps, missing)
71
- materialized.to_a + missing
72
- end
61
+ with_project_env do
62
+ if has_gemfile?
63
+ # Resolve dependencies of uninstalled gems and ensure remote sources are available.
64
+ Bundler.definition.resolve_remotely!
65
+ spec_set = Bundler.definition.resolve
66
+
67
+ if Gem::Version.new(Bundler::VERSION) >= Gem::Version.new('2.2.25')
68
+ deps = Bundler.definition.requested_dependencies
69
+ spec_set.materialize(deps).to_a
73
70
  else
74
- []
71
+ # For backward compatibility (Ref: https://github.com/rubygems/rubygems/pull/4788)
72
+ deps = Bundler.definition.send(:requested_dependencies)
73
+ missing = []
74
+ materialized = spec_set.materialize(deps, missing)
75
+
76
+ materialized.to_a + missing
75
77
  end
78
+ else
79
+ [] # Gem::Specification.latest_specs(true)
76
80
  end
77
81
  end
78
82
  end
79
83
  end
80
84
 
85
+ # @return [Boolean]
86
+ def has_gemfile?
87
+ File.exists?(File.expand_path("Gemfile", root_path))
88
+ end
89
+
81
90
  # @param [Gem::Specification]
82
91
  def metadata?(spec)
83
92
  spec.source.is_a?(Bundler::Source::Metadata)
@@ -88,6 +97,18 @@ module Yoda
88
97
  spec.source.is_a?(Bundler::Source::Path) && (File.expand_path(spec.source.path) == File.expand_path(root_path))
89
98
  end
90
99
 
100
+ def with_project_env
101
+ Dir.chdir(root_path) do
102
+ with_unbundled_env do
103
+ # Suppress bundler outputs to stdout.
104
+ Bundler.ui = Bundler::UI::Silent.new
105
+ Bundler.reset!
106
+
107
+ yield
108
+ end
109
+ end
110
+ end
111
+
91
112
  def with_unbundled_env(&block)
92
113
  if Bundler.respond_to?(:with_unbundled_env)
93
114
  Bundler.with_unbundled_env(&block)
@@ -0,0 +1,84 @@
1
+ require 'set'
2
+
3
+ module Yoda
4
+ class IdMask
5
+ # @return [Hash<Symbol>, nil]
6
+ attr_reader :pattern
7
+
8
+ # @param pattern [IdMask, Set<Symbol>, Array<Symbol>, Hash<Symbol>, nil]
9
+ # @return [IdMask]
10
+ def self.build(pattern)
11
+ if pattern.is_a?(IdMask)
12
+ pattern
13
+ elsif pattern.nil?
14
+ new(pattern)
15
+ elsif pattern.is_a?(Hash)
16
+ new(pattern.map { |k, v| [k.to_sym, v] }.to_h)
17
+ else
18
+ new(pattern.to_a.to_h { |id| [id.to_sym, nil] })
19
+ end
20
+ end
21
+
22
+ # @param pattern [Hash<Symbol>, nil]
23
+ def initialize(pattern)
24
+ fail TypeError, "pattern must be a Hash or nil" unless pattern.is_a?(Hash) || pattern.nil?
25
+ @pattern = pattern
26
+ end
27
+
28
+ # @param id [Symbol, String]
29
+ # @return [Boolean]
30
+ def cover?(id)
31
+ return true if any?
32
+ pattern.has_key?(id.to_sym)
33
+ end
34
+
35
+ # @param another [IdMasklia, Set<Symbol>, Array<Symbol>, Hash<Symbol>, nil]
36
+ # @return [IdMask]
37
+ def intersection(another)
38
+ another_mask = IdMask.build(another)
39
+ return another_mask if any?
40
+ return self if another_mask.any?
41
+
42
+ ids_intersection = covering_ids & another_mask.covering_ids
43
+
44
+ intersection_pattern = ids_intersection.map do |id|
45
+ [id, nesting_mask(id) & another_mask.nesting_mask(id)]
46
+ end.to_h
47
+
48
+ IdMask.build(intersection_pattern)
49
+ end
50
+
51
+ alias_method :&, :intersection
52
+
53
+ # @return [Boolean]
54
+ def any?
55
+ pattern.nil?
56
+ end
57
+
58
+ # @return [Set<Symbol>, nil]
59
+ def covering_ids
60
+ @covering_ids ||= begin
61
+ if any?
62
+ nil
63
+ else
64
+ Set.new(pattern.keys)
65
+ end
66
+ end
67
+ end
68
+
69
+ # @param id [String, Symbol]
70
+ # @return [IdMask]
71
+ def nesting_mask(id)
72
+ if pattern.is_a?(Hash)
73
+ IdMask.build(pattern[id.to_sym])
74
+ else
75
+ IdMask.build(nil)
76
+ end
77
+ end
78
+
79
+ # @return [Hash, nil]
80
+ def to_pattern
81
+ pattern&.map { |k, v| [k, v&.to_pattern] }&.to_h
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,45 @@
1
+ module Yoda
2
+ module Model
3
+ module Descriptions
4
+ # @abstract
5
+ class RequirePathDescription
6
+ # @return [String]
7
+ attr_reader :path
8
+
9
+ # @param path [String]
10
+ def initialize(path)
11
+ @path = path
12
+ end
13
+
14
+ # @abstract
15
+ # @return [String]
16
+ def title
17
+ path
18
+ end
19
+
20
+ # @abstract
21
+ # @return [String]
22
+ def sort_text
23
+ path
24
+ end
25
+
26
+ # @return [String]
27
+ def label
28
+ sort_text
29
+ end
30
+
31
+ # @abstract
32
+ # @return [String]
33
+ def to_markdown
34
+ path
35
+ end
36
+
37
+ # Return an LSP MarkedString content for description
38
+ # @return [String, Hash]
39
+ def markup_content
40
+ to_markdown
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -7,6 +7,7 @@ module Yoda
7
7
  require 'yoda/model/descriptions/value_description'
8
8
  require 'yoda/model/descriptions/word_description'
9
9
  require 'yoda/model/descriptions/node_description'
10
+ require 'yoda/model/descriptions/require_path_description'
10
11
  require 'yoda/model/descriptions/variable_description'
11
12
  end
12
13
  end
@@ -3,7 +3,15 @@ module Yoda
3
3
  module NodeSignatures
4
4
  class Node < Base
5
5
  def descriptions
6
- [node_type_description, *type_descriptions]
6
+ if node_info.require_paths.empty?
7
+ [node_type_description, *type_descriptions]
8
+ else
9
+ node_info.require_paths.map { |path| Descriptions::RequirePathDescription.new(path) }
10
+ end
11
+ end
12
+
13
+ def defined_files
14
+ node_info.require_paths.map { |path| [path, Parsing::Location.first_row, Parsing::Location.first_column] }
7
15
  end
8
16
  end
9
17
  end
@@ -11,6 +11,9 @@ module Yoda
11
11
  # @return [Base]
12
12
  attr_reader :value
13
13
 
14
+ # @return [Object]
15
+ attr_reader :literal
16
+
14
17
  # @param value [Base]
15
18
  # @param literal [Object]
16
19
  def initialize(value:, literal:)
@@ -17,6 +17,15 @@ module Yoda
17
17
  @column = column
18
18
  end
19
19
 
20
+ def self.first_row
21
+ 1
22
+ end
23
+
24
+ def self.first_column
25
+ 0
26
+ end
27
+
28
+
20
29
  # @param ast_location [Parser::Source::Map, Parser::Source::Range]
21
30
  # @return [Location, nil]
22
31
  def self.of_ast_location(ast_location)
@@ -0,0 +1,33 @@
1
+ module Yoda
2
+ module Services
3
+ class LoadablePathResolver
4
+ def initialize
5
+ end
6
+
7
+ # @param base_paths [Array<String>]
8
+ # @param pattern [String]
9
+ # @return [String, nil]
10
+ def find_loadable_path(base_paths, pattern)
11
+ # TODO: Support absolute path
12
+ return nil if File.absolute_path?(pattern)
13
+ return nil if pattern.start_with?("~/")
14
+ return nil if pattern.start_with?("./")
15
+ return nil if pattern.start_with?("../")
16
+
17
+ base_paths.each do |base_path|
18
+ path = File.join(base_path, pattern)
19
+
20
+ if File.extname(path).empty?
21
+ paths_with_suffix = ::Gem.suffixes.map { |suffix| path + suffix }
22
+ matched_path = paths_with_suffix.find { |path| File.file?(path) }
23
+ return matched_path if matched_path
24
+ else
25
+ return path if File.file?(path)
26
+ end
27
+ end
28
+
29
+ return nil
30
+ end
31
+ end
32
+ end
33
+ end
data/lib/yoda/services.rb CHANGED
@@ -4,6 +4,7 @@ module Yoda
4
4
  require 'yoda/services/current_node_explain'
5
5
  require 'yoda/services/comment_completion'
6
6
  require 'yoda/services/code_completion'
7
+ require 'yoda/services/loadable_path_resolver'
7
8
  require 'yoda/services/signature_discovery'
8
9
  end
9
10
  end
@@ -2,21 +2,23 @@ module Yoda
2
2
  module Store
3
3
  module Actions
4
4
  class ReadProjectFiles
5
+ # @return [Project]
6
+ attr_reader :project
7
+
5
8
  # @return [Registry]
6
9
  attr_reader :registry
7
10
 
8
- # @return [String]
9
- attr_reader :root_path
10
-
11
11
  # @param project [Project]
12
12
  # @return [ReadProjectFiles]
13
13
  def self.for_project(project)
14
- new(project.registry, project.root_path)
14
+ new(project, project.registry)
15
15
  end
16
16
 
17
- def initialize(registry, root_path)
17
+ # @param project [Project]
18
+ # @param registry [Project]
19
+ def initialize(project, registry)
20
+ @project = project
18
21
  @registry = registry
19
- @root_path = root_path
20
22
  end
21
23
 
22
24
  def run
@@ -35,7 +37,7 @@ module Yoda
35
37
 
36
38
  # @return [Array<String>]
37
39
  def project_files
38
- Dir.chdir(root_path) { Dir.glob(["{lib,app}/**/*.rb", "ext/**/*.c", ".yoda/*.rb"]).map { |name| File.expand_path(name, root_path) } }
40
+ project.project_source_paths
39
41
  end
40
42
  end
41
43
  end
@@ -20,7 +20,7 @@ module Yoda
20
20
 
21
21
  # @param address [String, Symbol]
22
22
  # @return [Object, nil]
23
- def get(address)
23
+ def get(address, **)
24
24
  JSON.load(database[build_key(address)], symbolize_names: true)
25
25
  end
26
26
 
@@ -28,7 +28,7 @@ module Yoda
28
28
 
29
29
  # @param address [String]
30
30
  # @return [any]
31
- def get(address)
31
+ def get(address, **)
32
32
  JSON.load(db[address.to_s], symbolize_names: true)
33
33
  end
34
34
 
@@ -10,7 +10,7 @@ module Yoda
10
10
  # @param dependency [Project::Dependency]
11
11
  # @return [Array<Object::Library::Core, Object::Library::Std, Object::Library::Gem>]
12
12
  def self.libraies_from_dependency(dependency)
13
- [dependency.core, dependency.std, *dependency.gems.select(&:installed?)]
13
+ [dependency.core, dependency.std, *dependency.autoload_gems.select(&:installed?)]
14
14
  end
15
15
 
16
16
  # @param libraries [Array<Library::Core, Library::Std, Library::Gem>]
@@ -1,3 +1,5 @@
1
+ require 'yoda/store/objects/library/path_resolvable'
2
+
1
3
  module Yoda
2
4
  module Store
3
5
  module Objects
@@ -42,6 +44,7 @@ module Yoda
42
44
  class Connected
43
45
  extend ConnectedDelegation
44
46
  include WithRegistry
47
+ include PathResolvable
45
48
 
46
49
  delegate_to_object :version
47
50
  delegate_to_object :id, :name, :doc_path, :to_h, :with_project_connection
@@ -64,6 +67,11 @@ module Yoda
64
67
  def registry_path
65
68
  VersionStore.for_current_version.registry_path_for_core
66
69
  end
70
+
71
+ # @return [Array<String>]
72
+ def require_paths
73
+ []
74
+ end
67
75
  end
68
76
  end
69
77
  end
@@ -1,18 +1,24 @@
1
+ require 'yoda/store/objects/library/path_resolvable'
2
+
1
3
  module Yoda
2
4
  module Store
3
5
  module Objects
4
6
  module Library
5
7
  class Gem
6
8
  include Serializable
9
+ include PathResolvable
7
10
 
8
11
  # @return [String]
9
12
  attr_reader :name, :version, :source_path, :full_gem_path, :doc_dir
10
13
 
14
+ # @return [Array<String>]
15
+ attr_reader :require_paths
16
+
11
17
  # @return [Symbol, nil]
12
18
  attr_reader :source_type
13
19
 
14
20
  class << self
15
- # @param spec [Bundler::LazySpecification]
21
+ # @param spec [Bundler::LazySpecification, Gem::Specification]
16
22
  def from_gem_spec(spec)
17
23
  if spec.respond_to?(:full_gem_path)
18
24
  # Installed
@@ -20,6 +26,7 @@ module Yoda
20
26
  name: spec.name,
21
27
  version: spec.version.version,
22
28
  source_path: spec.source.respond_to?(:path) ? spec.source.path : nil,
29
+ require_paths: spec.full_require_paths,
23
30
  full_gem_path: spec.full_gem_path,
24
31
  doc_dir: spec.doc_dir,
25
32
  source_type: source_type_of(spec.source),
@@ -30,6 +37,7 @@ module Yoda
30
37
  name: spec.name,
31
38
  version: spec.version.version,
32
39
  source_path: nil,
40
+ require_paths: [],
33
41
  full_gem_path: nil,
34
42
  doc_dir: nil,
35
43
  source_type: nil,
@@ -57,11 +65,12 @@ module Yoda
57
65
  end
58
66
  end
59
67
 
60
- def initialize(name:, version:, source_path:, full_gem_path:, doc_dir:, source_type:)
68
+ def initialize(name:, version:, source_path:, full_gem_path:, require_paths:, doc_dir:, source_type:)
61
69
  @name = name
62
70
  @version = version
63
71
  @source_path = source_path
64
72
  @full_gem_path = full_gem_path
73
+ @require_paths = require_paths
65
74
  @doc_dir = doc_dir
66
75
  @source_type = source_type&.to_sym
67
76
  end
@@ -80,6 +89,7 @@ module Yoda
80
89
  version: version,
81
90
  source_path: source_path,
82
91
  full_gem_path: full_gem_path,
92
+ require_paths: require_paths,
83
93
  doc_dir: doc_dir,
84
94
  source_type: source_type,
85
95
  }
@@ -103,9 +113,10 @@ module Yoda
103
113
  extend ConnectedDelegation
104
114
  include WithRegistry
105
115
 
106
- delegate_to_object :name, :version, :source_path, :full_gem_path, :doc_dir, :source_type
116
+ delegate_to_object :name, :version, :source_path, :full_gem_path, :doc_dir, :source_type, :require_paths
107
117
  delegate_to_object :id, :local?, :to_h, :installed?, :managed_by_rubygems?, :with_project_connection
108
118
  delegate_to_object :hash, :eql?, :==, :to_json, :derive
119
+ delegate_to_object :contain_requirable_file?, :find_requirable_file
109
120
 
110
121
  # @return [Gem]
111
122
  attr_reader :object
@@ -0,0 +1,29 @@
1
+ require 'yoda/store/objects/library/path_resolvable'
2
+
3
+ module Yoda
4
+ module Store
5
+ module Objects
6
+ module Library
7
+ module PathResolvable
8
+ # @abstract
9
+ # @return [Array<String>]
10
+ def require_paths
11
+ fail NotImplementedError
12
+ end
13
+
14
+ # @param relative_path [String]
15
+ # @return [Boolean]
16
+ def contain_requirable_file?(relative_path)
17
+ !!find_requirable_file(relative_path)
18
+ end
19
+
20
+ # @param relative_path [String]
21
+ # @return [String, nil]
22
+ def find_requirable_file(relative_path)
23
+ Services::LoadablePathResolver.new.find_loadable_path(require_paths, relative_path)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,3 +1,5 @@
1
+ require 'yoda/store/objects/library/path_resolvable'
2
+
1
3
  module Yoda
2
4
  module Store
3
5
  module Objects
@@ -42,6 +44,7 @@ module Yoda
42
44
  class Connected
43
45
  extend ConnectedDelegation
44
46
  include WithRegistry
47
+ include PathResolvable
45
48
 
46
49
  delegate_to_object :version
47
50
  delegate_to_object :id, :name, :doc_path, :to_h, :with_project_connection
@@ -64,6 +67,12 @@ module Yoda
64
67
  def registry_path
65
68
  VersionStore.for_current_version.registry_path_for_stdlib
66
69
  end
70
+
71
+ # @return [Array<String>]
72
+ def require_paths
73
+ # TODO: Calculate from registry
74
+ [File.join(VersionStore.for_current_version.ruby_source_path, "lib/")]
75
+ end
67
76
  end
68
77
  end
69
78
  end
@@ -6,6 +6,7 @@ module Yoda
6
6
  require 'yoda/store/objects/library/core'
7
7
  require 'yoda/store/objects/library/std'
8
8
  require 'yoda/store/objects/library/gem'
9
+ require 'yoda/store/objects/library/path_resolvable'
9
10
 
10
11
  class << self
11
12
  # @return [Core]
@@ -17,7 +17,7 @@ module Yoda
17
17
 
18
18
  # @param address [String, Symbol]
19
19
  # @return [Addressable, nil]
20
- def find(address)
20
+ def find(address, **)
21
21
  @registry[address.to_sym]
22
22
  end
23
23
  alias get find