Skip to content

Commit f8d2d40

Browse files
committed
Use filename for correct require_relative path completion
1 parent 93a4e1e commit f8d2d40

7 files changed

Lines changed: 35 additions & 28 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Now you can get completion candidates.
3232
```ruby
3333
array = [1, 2, 3]
3434
class String; def upupup; end; end
35-
result = ReplCompletion.analyze('array.map do str = _1.chr; str.up', binding)
35+
result = ReplCompletion.analyze('array.map do str = _1.chr; str.up', binding: binding)
3636
result.completion_candidates #=> ["case", "case!", "to", "upup"]
3737
result.doc_namespace('case') #=> "String#upcase"
3838
```
@@ -54,7 +54,7 @@ ReplCompletion.rbs_load_started?
5454
ReplCompletion.rbs_loaded?
5555
ReplCompletion.rbs_load_error
5656
ReplCompletion.last_completion_error
57-
ReplCompletion.analyze(code_to_complete, binding)
57+
ReplCompletion.analyze(code_to_complete, binding: binding)
5858
```
5959

6060
## License

lib/repl_completion.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ def preload_rbs
2828
Types.preload_rbs_builder
2929
end
3030

31-
def analyze(code, binding)
31+
def analyze(code, binding:, filename: nil)
3232
verbose, $VERBOSE = $VERBOSE, nil
3333
result = analyze_code(code, binding)
34-
Result.new(result, binding) if result
34+
Result.new(result, binding, filename) if result
3535
rescue Exception => e
3636
handle_exception(e)
3737
nil

lib/repl_completion/require_paths.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ def require_completions(target_path)
1919
end
2020
end
2121

22-
def require_relative_completions(target_path, binding)
23-
current_filepath = binding.source_location[0]
22+
def require_relative_completions(target_path, source_file)
23+
source_dir = source_file ? File.dirname(source_file) : Dir.pwd
2424
*dir, target = target_path.split('/', -1)
2525
target ||= ''
26-
base_dir = File.absolute_path(File.join(File.dirname(current_filepath), *dir))
26+
base_dir = File.absolute_path(File.join(source_dir, *dir))
2727
paths = with_cache [:requireable_paths, base_dir] do
2828
requireable_paths(base_dir)
2929
end

lib/repl_completion/result.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ def defined? do
2626
yield
2727
]
2828

29-
def initialize(analyze_result, binding)
29+
def initialize(analyze_result, binding, source_file)
3030
@analyze_result = analyze_result
3131
@binding = binding
32+
@source_file = source_file
3233
end
3334

3435
def completion_candidates
@@ -37,7 +38,7 @@ def completion_candidates
3738
in [:require, name]
3839
RequirePaths.require_completions(name)
3940
in [:require_relative, name]
40-
RequirePaths.require_relative_completions(name, @binding)
41+
RequirePaths.require_relative_completions(name, @source_file)
4142
in [:call_or_const, name, type, self_call]
4243
((self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS) | type.constants
4344
in [:const, name, type, scope]

sig/repl_completion.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module ReplCompletion
66
def doc_namespace: (String) -> String?
77
end
88

9-
def self.analyze: (String, Binding) -> Result?
9+
def self.analyze: (String, binding: Binding, ?filename: String?) -> Result?
1010

1111
def self.rbs_load_error: () -> Exception?
1212
def self.last_completion_error: () -> Exception?

test/repl_completion/test_repl_completion.rb

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,27 @@ def empty_binding
1515

1616
TARGET_REGEXP = /(@@|@|\$)?[a-zA-Z_]*[!?=]?$/
1717

18-
def assert_completion(code, binding: empty_binding, include: nil, exclude: nil)
18+
def assert_completion(code, binding: empty_binding, filename: nil, include: nil, exclude: nil)
1919
raise ArgumentError if include.nil? && exclude.nil?
20-
candidates = ReplCompletion.analyze(code, binding).completion_candidates
20+
candidates = ReplCompletion.analyze(code, binding: binding, filename: filename).completion_candidates
2121
assert ([*include] - candidates).empty?, "Expected #{candidates} to include #{include}" if include
2222
assert (candidates & [*exclude]).empty?, "Expected #{candidates} not to include #{exclude}" if exclude
2323
end
2424

2525
def assert_doc_namespace(code, namespace, binding: empty_binding)
26-
assert_equal namespace, ReplCompletion.analyze(code, binding).doc_namespace('')
26+
assert_equal namespace, ReplCompletion.analyze(code, binding: binding).doc_namespace('')
2727
end
2828

2929
def test_require
3030
assert_completion("require '", include: 'set')
3131
assert_completion("require 's", include: 'et')
32-
assert_completion("require_relative 'test_", include: 'repl_completion')
32+
assert_completion("require_relative 'test_", filename: __FILE__, include: 'repl_completion')
33+
assert_completion("require_relative '../repl_", filename: __FILE__, include: 'completion/test_repl_completion')
34+
Dir.chdir File.join(__dir__, '..') do
35+
assert_completion("require_relative 'repl_", filename: nil, include: 'completion/test_repl_completion')
36+
assert_completion("require_relative 'repl_", filename: '(irb)', include: 'completion/test_repl_completion')
37+
end
38+
3339
# Incomplete double quote string is InterpolatedStringNode
3440
assert_completion('require "', include: 'set')
3541
assert_completion('require "s', include: 'et')
@@ -155,12 +161,12 @@ def test_deprecated_const_without_warning
155161
end
156162

157163
def test_sig_dir
158-
assert_doc_namespace('ReplCompletion.analyze(code, binding).completion_candidates.__id__', 'Array#__id__')
159-
assert_doc_namespace('ReplCompletion.analyze(code, binding).doc_namespace.__id__', 'String#__id__')
164+
assert_doc_namespace('ReplCompletion.analyze(code, binding: binding).completion_candidates.__id__', 'Array#__id__')
165+
assert_doc_namespace('ReplCompletion.analyze(code, binding: binding).doc_namespace.__id__', 'String#__id__')
160166
end
161167

162168
def test_none
163-
result = ReplCompletion.analyze('()', binding)
169+
result = ReplCompletion.analyze('()', binding: binding)
164170
assert_nil result
165171
end
166172

@@ -187,15 +193,15 @@ def with_failing_method(klass, method_name, message)
187193

188194
def test_analyze_error
189195
with_failing_method(ReplCompletion.singleton_class, :analyze_code, 'error_in_analyze_code') do
190-
assert_nil ReplCompletion.analyze '1.', binding
196+
assert_nil ReplCompletion.analyze('1.', binding: binding)
191197
end
192198
assert_equal 'error_in_analyze_code', ReplCompletion.last_completion_error&.message
193199
ensure
194200
ReplCompletion.instance_variable_set(:@last_completion_error, nil)
195201
end
196202

197203
def test_completion_candidates_error
198-
result = ReplCompletion.analyze '1.', binding
204+
result = ReplCompletion.analyze '1.', binding: binding
199205
with_failing_method(ReplCompletion::Types::InstanceType, :methods, 'error_in_methods') do
200206
assert_equal [], result.completion_candidates
201207
end
@@ -205,7 +211,7 @@ def test_completion_candidates_error
205211
end
206212

207213
def test_doc_namespace_error
208-
result = ReplCompletion.analyze '1.', binding
214+
result = ReplCompletion.analyze '1.', binding: binding
209215
with_failing_method(ReplCompletion::Result, :method_doc, 'error_in_method_doc') do
210216
assert_nil result.doc_namespace('abs')
211217
end

test/repl_completion/test_require_paths.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ def test_require_paths
1212
end
1313

1414
def test_require_relative_paths
15-
assert_include ReplCompletion::RequirePaths.require_relative_completions('test_re', binding), 'test_require_paths'
16-
assert_include ReplCompletion::RequirePaths.require_relative_completions('../repl_', binding), '../repl_completion/test_require_paths'
17-
root_path_binding = eval('binding', binding, File.join(__dir__, '../../Gemfile'), 1)
18-
assert_not_include ReplCompletion::RequirePaths.require_relative_completions('li', binding), 'lib/repl_completion'
19-
assert_include ReplCompletion::RequirePaths.require_relative_completions('li', root_path_binding), 'lib/repl_completion'
15+
assert_include ReplCompletion::RequirePaths.require_relative_completions('test_re', __FILE__), 'test_require_paths'
16+
assert_include ReplCompletion::RequirePaths.require_relative_completions('../repl_', __FILE__), '../repl_completion/test_require_paths'
17+
project_root = File.expand_path('../../Gemfile', __dir__)
18+
assert_not_include ReplCompletion::RequirePaths.require_relative_completions('li', __FILE__), 'lib/repl_completion'
19+
assert_include ReplCompletion::RequirePaths.require_relative_completions('li', project_root), 'lib/repl_completion'
2020
# Incrementally complete deep path
21-
assert_include ReplCompletion::RequirePaths.require_relative_completions('li', root_path_binding), 'lib/repl_completion/'
22-
assert_not_include ReplCompletion::RequirePaths.require_relative_completions('li', root_path_binding), 'lib/repl_completion/version'
23-
assert_include ReplCompletion::RequirePaths.require_relative_completions('lib/', root_path_binding), 'lib/repl_completion/version'
21+
assert_include ReplCompletion::RequirePaths.require_relative_completions('li', project_root), 'lib/repl_completion/'
22+
assert_not_include ReplCompletion::RequirePaths.require_relative_completions('li', project_root), 'lib/repl_completion/version'
23+
assert_include ReplCompletion::RequirePaths.require_relative_completions('lib/', project_root), 'lib/repl_completion/version'
2424
end
2525
end
2626
end

0 commit comments

Comments
 (0)