diff --git a/.gitignore b/.gitignore index bcc8d5f..58ce68c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ # rspec failure tracking .rspec_status + +vendor +.solargraph.yml \ No newline at end of file diff --git a/lib/solargraph/rspec/convention.rb b/lib/solargraph/rspec/convention.rb index 7fb8c38..34eba27 100644 --- a/lib/solargraph/rspec/convention.rb +++ b/lib/solargraph/rspec/convention.rb @@ -8,7 +8,6 @@ require_relative 'correctors/described_class_corrector' require_relative 'correctors/let_methods_corrector' require_relative 'correctors/subject_method_corrector' -require_relative 'correctors/context_block_methods_corrector' require_relative 'correctors/dsl_methods_corrector' require_relative 'test_helpers' require_relative 'pin_factory' @@ -52,7 +51,6 @@ module Rspec # @type [Array>] CORRECTOR_CLASSES = [ - Correctors::ContextBlockMethodsCorrector, Correctors::ContextBlockNamespaceCorrector, Correctors::DescribedClassCorrector, Correctors::DslMethodsCorrector, diff --git a/lib/solargraph/rspec/correctors/base.rb b/lib/solargraph/rspec/correctors/base.rb index 62e0207..2d87fd9 100644 --- a/lib/solargraph/rspec/correctors/base.rb +++ b/lib/solargraph/rspec/correctors/base.rb @@ -63,6 +63,16 @@ def closest_namespace_pin(namespace_pins, line) distance >= 0 ? distance : Float::INFINITY end end + + # Overrides a pin's closure, and resets all the needed instance vars + # @param pin [Solargraph::Pin::Base] + # @param new_closure [Solargraph::Pin::Closure] + def override_closure(pin, new_closure) + pin.instance_variable_set('@closure', new_closure) + pin.reset_generated! + + pin.remove_instance_variable(:@path) if pin.instance_variables.include? :@path + end end end end diff --git a/lib/solargraph/rspec/correctors/context_block_methods_corrector.rb b/lib/solargraph/rspec/correctors/context_block_methods_corrector.rb deleted file mode 100644 index fedfa51..0000000 --- a/lib/solargraph/rspec/correctors/context_block_methods_corrector.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require_relative 'base' - -module Solargraph - module Rspec - module Correctors - # A corrector that corrects pure ruby method blocks namespace defined inside describe/context blocks. - class ContextBlockMethodsCorrector < Base - # @param source_map [Solargraph::SourceMap] - def correct(source_map) - rspec_walker.after_walk do - source_map.pins.each_with_index do |pin, index| - next unless pin.is_a?(Solargraph::Pin::Method) - - namespace_pin = closest_namespace_pin(namespace_pins, pin.location.range.start.line) - next unless namespace_pin - - source_map.pins[index] = Solargraph::Pin::Method.new( - visibility: pin.visibility, - parameters: pin.parameters, - closure: namespace_pin, - node: pin.node, - signatures: pin.signatures, - location: pin.location, - name: pin.name, - scope: pin.scope, - comments: pin.comments - ) - end - end - end - end - end - end -end diff --git a/lib/solargraph/rspec/correctors/context_block_namespace_corrector.rb b/lib/solargraph/rspec/correctors/context_block_namespace_corrector.rb index 4a6a093..1561fb9 100644 --- a/lib/solargraph/rspec/correctors/context_block_namespace_corrector.rb +++ b/lib/solargraph/rspec/correctors/context_block_namespace_corrector.rb @@ -12,7 +12,6 @@ def correct(source_map) # @param location_range [Solargraph::Range] rspec_walker.on_each_context_block do |namespace_name, location_range| original_block_pin = source_map.locate_block_pin(location_range.start.line, location_range.start.column) - original_block_pin_index = source_map.pins.index(original_block_pin) location = PinFactory.build_location(location_range, source_map.filename) # Define a dynamic module for the example group block @@ -26,17 +25,10 @@ def correct(source_map) location: location ) - fixed_namespace_block_pin = Solargraph::Pin::Block.new( - closure: namespace_pin, - location: original_block_pin.location, - receiver: original_block_pin.receiver, - scope: original_block_pin.scope - ) - - source_map.pins[original_block_pin_index] = fixed_namespace_block_pin + override_closure(original_block_pin, namespace_pin) # Include DSL methods in the example group block - # TOOD: This does not work on solagraph! Class methods are not included from parent class. + # TODO: This does not work on solagraph! Class methods are not included from parent class. namespace_extend_pin = PinFactory.build_module_extend( namespace_pin, root_example_group_namespace_pin.name, diff --git a/lib/solargraph/rspec/correctors/example_and_hook_blocks_binding_corrector.rb b/lib/solargraph/rspec/correctors/example_and_hook_blocks_binding_corrector.rb index 63f9868..b8fb040 100644 --- a/lib/solargraph/rspec/correctors/example_and_hook_blocks_binding_corrector.rb +++ b/lib/solargraph/rspec/correctors/example_and_hook_blocks_binding_corrector.rb @@ -43,15 +43,8 @@ def bind_closest_namespace(location_range, source_map) original_block_pin = source_map.locate_block_pin(location_range.start.line, location_range.start.column) - original_block_pin_index = source_map.pins.index(original_block_pin) - fixed_namespace_block_pin = Solargraph::Pin::Block.new( - closure: example_run_method(namespace_pin), - location: original_block_pin.location, - receiver: original_block_pin.receiver, - scope: original_block_pin.scope - ) - source_map.pins[original_block_pin_index] = fixed_namespace_block_pin + override_closure(original_block_pin, example_run_method(namespace_pin)) end # @param namespace_pin [Solargraph::Pin::Namespace] diff --git a/spec/solargraph/rspec/convention_spec.rb b/spec/solargraph/rspec/convention_spec.rb index c81090c..1391374 100644 --- a/spec/solargraph/rspec/convention_spec.rb +++ b/spec/solargraph/rspec/convention_spec.rb @@ -481,7 +481,8 @@ def load_and_assert_type(let_declaration, let_name, expected_type) end it 'infers type for some_object' do - load_and_assert_type(<<~RUBY, 'some_object', 'MyClass') + pending('https://github.com/castwide/solargraph/pull/1008') + load_and_assert_type(<<~RUBY, 'some_object', 'RSpec::ExampleGroups::TestSomeNamespaceTransaction::MyClass') class MyClass; end let(:some_object) { MyClass.new } RUBY @@ -598,6 +599,85 @@ class MyClass; end 'Class' ) end + + describe 'on variables' do + it 'should parse result of a method defined in an example' do + load_string filename, <<~RUBY + RSpec.describe SomeNamespace::Transaction, type: :model do + it 'some example' do + # @return [Numeric] + def example_method + end + + result = example_method + end + end + RUBY + + var_pin = expect_local_variable_type('result', 'Numeric') + # This is mostly important of includes outside an include pin (ie. https://github.com/lekemula/solargraph-rspec/pull/13) + expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction') + end + + it 'should parse result of a method defined in a context' do + load_string filename, <<~RUBY + RSpec.describe SomeNamespace::Transaction, type: :model do + # @return [String] + def example_method + end + + it 'some example' do + result = example_method + end + end + RUBY + + var_pin = expect_local_variable_type('result', 'String') + expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction') + end + + it 'should parse result of a module method included in an example' do + load_string filename, <<~RUBY + module SomeModule + # @return [String] + def example_method + end + end + + RSpec.describe SomeNamespace::Transaction, type: :model do + it 'some example' do + include SomeModule + + result = example_method + end + end + RUBY + + var_pin = expect_local_variable_type('result', 'String') + expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction') + end + + it 'should parse result of a module method included in a context' do + load_string filename, <<~RUBY + module SomeModule + # @return [Numeric] + def example_method + end + end + + RSpec.describe SomeNamespace::Transaction, type: :model do + include SomeModule + + it 'some example' do + result = example_method + end + end + RUBY + + var_pin = expect_local_variable_type('result', 'Numeric') + expect(var_pin.namespace).to eql('RSpec::ExampleGroups::TestSomeNamespaceTransaction') + end + end end describe 'configurations' do diff --git a/spec/support/solargraph_helpers.rb b/spec/support/solargraph_helpers.rb index 097d485..c167762 100644 --- a/spec/support/solargraph_helpers.rb +++ b/spec/support/solargraph_helpers.rb @@ -59,7 +59,9 @@ def find_pins(path, map = api_map) map.pins.select { |p| p.path == path } end + # @return [Array] def completion_pins_at(filename, position, map = api_map) + # @type [Solargraph::SourceMap::Clip] clip = map.clip_at(filename, position) cursor = clip.send(:cursor) word = cursor.chain.links.first.word @@ -74,4 +76,20 @@ def completion_pins_at(filename, position, map = api_map) def completion_at(filename, position, map = api_map) completion_pins_at(filename, position, map).map(&:name) end + + # Expect that a local can be inferred with +expected_type+ + # + # @param var_name [String] + # @param expected_type [String] + # @param file [String] The filename (defaults to filename defined in test) + # @param map [Solargraph::ApiMap] The Api Map (defaults to the one defined in a test) + # + # @return [Solargraph::Pin::BaseVariable] The variable pin + def expect_local_variable_type(var_name, expected_type, file = filename, map = api_map) + var_pin = map.source_map(file).locals.find { |p| p.name == var_name } + expect(var_pin).not_to be_nil + expect(var_pin.probe(map).to_s).to eql(expected_type) + + var_pin + end end