Skip to content

Commit 4fa3e7a

Browse files
committed
Improve binding corrections
1 parent e62a315 commit 4fa3e7a

8 files changed

Lines changed: 117 additions & 70 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@
1111

1212
# rspec failure tracking
1313
.rspec_status
14+
15+
vendor
16+
.solargraph.yml

lib/solargraph/rspec/convention.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
require_relative 'correctors/described_class_corrector'
99
require_relative 'correctors/let_methods_corrector'
1010
require_relative 'correctors/subject_method_corrector'
11-
require_relative 'correctors/context_block_methods_corrector'
1211
require_relative 'correctors/dsl_methods_corrector'
1312
require_relative 'test_helpers'
1413
require_relative 'pin_factory'
@@ -52,7 +51,6 @@ module Rspec
5251

5352
# @type [Array<Class<Correctors::Base>>]
5453
CORRECTOR_CLASSES = [
55-
Correctors::ContextBlockMethodsCorrector,
5654
Correctors::ContextBlockNamespaceCorrector,
5755
Correctors::DescribedClassCorrector,
5856
Correctors::DslMethodsCorrector,

lib/solargraph/rspec/correctors/base.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ def closest_namespace_pin(namespace_pins, line)
6363
distance >= 0 ? distance : Float::INFINITY
6464
end
6565
end
66+
67+
# Overrides a pin's closure, and resets all the needed instance vars
68+
# @param pin [Solargraph::Pin::Base]
69+
# @param new_closure [Solargraph::Pin::Closure]
70+
def override_closure(pin, new_closure)
71+
pin.instance_variable_set('@closure', new_closure)
72+
pin.reset_generated!
73+
74+
pin.remove_instance_variable(:@path) if pin.instance_variables.include? :@path
75+
end
6676
end
6777
end
6878
end

lib/solargraph/rspec/correctors/context_block_methods_corrector.rb

Lines changed: 0 additions & 36 deletions
This file was deleted.

lib/solargraph/rspec/correctors/context_block_namespace_corrector.rb

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,10 @@ def correct(source_map)
2626
location: location
2727
)
2828

29-
fixed_namespace_block_pin = Solargraph::Pin::Block.new(
30-
closure: namespace_pin,
31-
location: original_block_pin.location,
32-
receiver: original_block_pin.receiver,
33-
scope: original_block_pin.scope
34-
)
35-
36-
source_map.pins[original_block_pin_index] = fixed_namespace_block_pin
29+
override_closure(original_block_pin, namespace_pin)
3730

3831
# Include DSL methods in the example group block
39-
# TOOD: This does not work on solagraph! Class methods are not included from parent class.
32+
# TODO: This does not work on solagraph! Class methods are not included from parent class.
4033
namespace_extend_pin = PinFactory.build_module_extend(
4134
namespace_pin,
4235
root_example_group_namespace_pin.name,

lib/solargraph/rspec/correctors/example_and_hook_blocks_binding_corrector.rb

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ class ExampleAndHookBlocksBindingCorrector < Base
1111
# @param source_map [Solargraph::SourceMap]
1212
# @return [void]
1313
def correct(source_map)
14-
# @type [Hash{Solargraph::Pin::Block => Solargraph::Pin::Block}]
15-
@corrected_blocks = {}
16-
1714
rspec_walker.on_example_block do |location_range|
1815
bind_closest_namespace(location_range, source_map)
1916
end
@@ -33,17 +30,6 @@ def correct(source_map)
3330
rspec_walker.on_subject do |_method_name, location_range|
3431
bind_closest_namespace(location_range, source_map)
3532
end
36-
37-
rspec_walker.after_walk do
38-
source_map.locals.each do |p|
39-
next unless p.is_a? Solargraph::Pin::BaseVariable
40-
41-
fixed_block = @corrected_blocks[p.closure]
42-
43-
# This might not be be best best practice, but imo its much simpler to keep up with updates and such
44-
p.instance_variable_set('@closure', fixed_block) unless fixed_block.nil?
45-
end
46-
end
4733
end
4834

4935
private
@@ -57,15 +43,8 @@ def bind_closest_namespace(location_range, source_map)
5743

5844
original_block_pin = source_map.locate_block_pin(location_range.start.line,
5945
location_range.start.column)
60-
original_block_pin_index = source_map.pins.index(original_block_pin)
61-
fixed_namespace_block_pin = Solargraph::Pin::Block.new(
62-
closure: example_run_method(namespace_pin),
63-
location: original_block_pin.location,
64-
receiver: original_block_pin.receiver,
65-
scope: original_block_pin.scope
66-
)
6746

68-
source_map.pins[original_block_pin_index] = fixed_namespace_block_pin
47+
override_closure(original_block_pin, example_run_method(namespace_pin))
6948
end
7049

7150
# @param namespace_pin [Solargraph::Pin::Namespace]

spec/solargraph/rspec/convention_spec.rb

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,8 @@ def load_and_assert_type(let_declaration, let_name, expected_type)
481481
end
482482

483483
it 'infers type for some_object' do
484-
load_and_assert_type(<<~RUBY, 'some_object', 'MyClass')
484+
pending('https://github.com/castwide/solargraph/pull/1008')
485+
load_and_assert_type(<<~RUBY, 'some_object', 'RSpec::ExampleGroups::TestSomeNamespaceTransaction::MyClass')
485486
class MyClass; end
486487
let(:some_object) { MyClass.new }
487488
RUBY
@@ -598,6 +599,87 @@ class MyClass; end
598599
'Class'
599600
)
600601
end
602+
603+
context 'on variables' do
604+
context 'in an example' do
605+
it 'should parse result of a method defined in an example' do
606+
load_string filename, <<~RUBY
607+
RSpec.describe SomeNamespace::Transaction, type: :model do
608+
it 'some example' do
609+
# @return [Numeric]
610+
def example_method
611+
end
612+
613+
result = example_method
614+
end
615+
end
616+
RUBY
617+
618+
var_pin = expect_local_type('result', 'Numeric')
619+
# This is mostly important of includes outside an include pin (ie. https://github.com/lekemula/solargraph-rspec/pull/13)
620+
expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction')
621+
end
622+
623+
it 'should parse result of a method defined in a context' do
624+
load_string filename, <<~RUBY
625+
RSpec.describe SomeNamespace::Transaction, type: :model do
626+
# @return [String]
627+
def example_method
628+
end
629+
630+
it 'some example' do
631+
result = example_method
632+
end
633+
end
634+
RUBY
635+
636+
var_pin = expect_local_type('result', 'String')
637+
expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction')
638+
end
639+
640+
it 'should parse result of a module method included in an example' do
641+
load_string filename, <<~RUBY
642+
module SomeModule
643+
# @return [String]
644+
def example_method
645+
end
646+
end
647+
648+
RSpec.describe SomeNamespace::Transaction, type: :model do
649+
it 'some example' do
650+
include SomeModule
651+
652+
result = example_method
653+
end
654+
end
655+
RUBY
656+
657+
var_pin = expect_local_type('result', 'String')
658+
expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction')
659+
end
660+
661+
it 'should parse result of a module method included in a context' do
662+
load_string filename, <<~RUBY
663+
module SomeModule
664+
# @return [Numeric]
665+
def example_method
666+
end
667+
end
668+
669+
RSpec.describe SomeNamespace::Transaction, type: :model do
670+
include SomeModule
671+
672+
it 'some example' do
673+
result = example_method
674+
end
675+
end
676+
RUBY
677+
678+
var_pin = expect_local_type('result', 'Numeric')
679+
expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction')
680+
end
681+
end
682+
end
601683
end
602684

603685
describe 'configurations' do

spec/support/solargraph_helpers.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ def find_pins(path, map = api_map)
5959
map.pins.select { |p| p.path == path }
6060
end
6161

62+
# @return [Array<Solargraph::Pin::Base>]
6263
def completion_pins_at(filename, position, map = api_map)
64+
# @type [Solargraph::SourceMap::Clip]
6365
clip = map.clip_at(filename, position)
6466
cursor = clip.send(:cursor)
6567
word = cursor.chain.links.first.word
@@ -74,4 +76,20 @@ def completion_pins_at(filename, position, map = api_map)
7476
def completion_at(filename, position, map = api_map)
7577
completion_pins_at(filename, position, map).map(&:name)
7678
end
79+
80+
# Expect that a local can be inferred with +expected_type+
81+
#
82+
# @param var_name [String]
83+
# @param expected_type [String]
84+
# @param file [String] The filename (defaults to filename defined in test)
85+
# @param map [Solargraph::ApiMap] The Api Map (defaults to the one defined in a test)
86+
#
87+
# @return [Solargraph::Pin::BaseVariable] The variable pin
88+
def expect_local_type(var_name, expected_type, file = filename, map = api_map)
89+
var_pin = map.source_map(file).locals.find { |p| p.name == var_name }
90+
expect(var_pin).not_to be_nil
91+
expect(var_pin.probe(map).to_s).to eql(expected_type)
92+
93+
var_pin
94+
end
7795
end

0 commit comments

Comments
 (0)