solargraph-rspec 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f73a95cc73aa3ce52cff1e5e4e8e06509f3a59ccf6a3371b9087fad38e135b0
4
- data.tar.gz: 221342fb0163f67fce1648aa4b14310b31907aacc9637def0b61e690b8ff750e
3
+ metadata.gz: b218c57b18c9c34c920dc8085633940b40980109acc0767e3819f2f460af7598
4
+ data.tar.gz: 8d33d3922c38de08dde380776138fb2eddee93f72aaaee1cd7ae4dce7610ac69
5
5
  SHA512:
6
- metadata.gz: 47f84a714dc459f67e354b68ff1c037e0ee9170a364db3fb4aa8e7a04cef1ce81952fade0a109a41de91f57b0b18201d3d8ab95b901f94de679357688bc9e41f
7
- data.tar.gz: a5bff062303a4fd717315083944c19dbe1c21a94ee795e9f29d5e2971d574038bb75677c596645dacd5861f5f624a7a36a93347c48e443a549ab7decc387dae3
6
+ metadata.gz: 0d6afb3098eeaa24b1c169ba6993306b14008837ebfd267c30bfe74788cd5deecb7985d33037984f5ed698d259daf9c698dba19f4eed0e6a346f521f081a2d7a
7
+ data.tar.gz: 88699cf9f89421e1a0306d37ce912c1a1fc231cd722cc4338ec757efed7ca304791b1c2e3e3271b9cb057efe91f2d3db8fa22c70739b88569a0be59c9b0de229
data/CHANGELOG.md CHANGED
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Fixed
11
+
12
+ - Suggest keeping `spec/**/*` in the `exclude` section of `.solargraph.yml` to avoid performance issues (see [commit](https://github.com/lekemula/solargraph-rspec/commit/3f0fc39e59e99bf9430e55c52ecb88650e49315e))
13
+ - Fix `let` definitions when do/end keywords overlap with body definition
14
+ ```ruby
15
+ let(:todo) do # "do" keyword overlap
16
+ {
17
+ 'todo' => 'end' # "end" keyword overlap
18
+ }
19
+ end
20
+ ```
21
+ - Error handling in SpecWalker::FakeLetMethod
22
+
23
+ ## [0.2.1] - 2024-06-09
24
+
25
+ ### Added
26
+
27
+ - Documentation for `RSpec::ExampleGroups` DSL methods like `it`, `fit`, `example` etc.
28
+
29
+ ### Fixed
30
+
31
+ - Fix nameless `subject` method completion inside nested `context` blocks
32
+ - (Hack-ish) Fix `described_class` type collision when `RSpec.describe SomeClassWithoutNamespace`
33
+
10
34
  ## [0.2.0] - 2024-05-20
11
35
 
12
36
  ### Added
data/README.md CHANGED
@@ -34,14 +34,19 @@ Or add it to your Gemfile:
34
34
 
35
35
  ```ruby
36
36
  group :development do
37
- gem 'solargraph'
38
- gem 'solargraph-rspec'
37
+ gem 'solargraph', require: false
38
+ gem 'solargraph-rspec', require: false
39
39
  end
40
40
  ```
41
41
 
42
42
  If you add them to your Gemfile, you'll have to tell your IDE plugin to use bundler to load the right version of solargraph.
43
43
 
44
- Add `solargraph-rspec` to your `.solargraph.yml` and remove the `spec` directory from the `exclude` list.
44
+ Add `solargraph-rspec` to your `.solargraph.yml` as a plugin.
45
+
46
+ > [!CAUTION]
47
+ > To avoid **performance issues**, please keep the `spec/**/*` directory in **exclude** list in the Solargraph configuration.
48
+ > That does not actually *exclude* the specs, but rather avoids pre-indexing the specs when Solargraph boots up, and only parses
49
+ > the specs on demand when opened in the editor, which is what we usually want.
45
50
 
46
51
  (if you don't have a `.solargraph.yml` in your project root, you can run `solargraph config` to add one)
47
52
 
@@ -50,7 +55,7 @@ Add `solargraph-rspec` to your `.solargraph.yml` and remove the `spec` directory
50
55
  include:
51
56
  - "**/*.rb"
52
57
  exclude:
53
- -- spec/**/*
58
+ +- spec/**/*
54
59
  - test/**/*
55
60
  - vendor/**/*
56
61
  - ".bundle/**/*"
data/codecov.yml ADDED
@@ -0,0 +1,13 @@
1
+ # https://docs.codecov.com/docs/common-recipe-list
2
+ coverage:
3
+ status:
4
+ project: #add everything under here, more options at https://docs.codecov.com/docs/commit-status
5
+ default:
6
+ # basic
7
+ target: auto #default
8
+ threshold: 1%
9
+ base: auto
10
+ informational: true
11
+ patch:
12
+ default:
13
+ informational: true
@@ -8,7 +8,6 @@ require_relative 'correctors/described_class_corrector'
8
8
  require_relative 'correctors/let_methods_corrector'
9
9
  require_relative 'correctors/subject_method_corrector'
10
10
  require_relative 'correctors/context_block_methods_corrector'
11
- require_relative 'correctors/implicit_subject_method_corrector'
12
11
  require_relative 'correctors/dsl_methods_corrector'
13
12
  require_relative 'pin_factory'
14
13
 
@@ -50,6 +49,17 @@ module Solargraph
50
49
  include_context
51
50
  ].freeze
52
51
 
52
+ # @type [Array<Class<Correctors::Base>>]
53
+ CORRECTOR_CLASSES = [
54
+ Correctors::ContextBlockMethodsCorrector,
55
+ Correctors::ContextBlockNamespaceCorrector,
56
+ Correctors::DescribedClassCorrector,
57
+ Correctors::DslMethodsCorrector,
58
+ Correctors::ExampleAndHookBlocksBindingCorrector,
59
+ Correctors::LetMethodsCorrector,
60
+ Correctors::SubjectMethodCorrector
61
+ ].freeze
62
+
53
63
  # Provides completion for RSpec DSL and helper methods.
54
64
  # - `describe` and `context` blocks
55
65
  # - `let` and `let!` methods
@@ -105,86 +115,17 @@ module Solargraph
105
115
 
106
116
  rspec_walker = SpecWalker.new(source_map: source_map, config: config)
107
117
 
108
- Correctors::ContextBlockNamespaceCorrector.new(
109
- namespace_pins: namespace_pins,
110
- rspec_walker: rspec_walker
111
- ).correct(source_map) do |pins_to_add|
112
- pins += pins_to_add
113
- end
114
-
115
- Correctors::ExampleAndHookBlocksBindingCorrector.new(
116
- namespace_pins: namespace_pins,
117
- rspec_walker: rspec_walker
118
- ).correct(source_map) do |pins_to_add|
119
- pins += pins_to_add
120
- end
121
-
122
- # @type [Pin::Method, nil]
123
- described_class_pin = nil
124
- Correctors::DescribedClassCorrector.new(
125
- namespace_pins: namespace_pins,
126
- rspec_walker: rspec_walker
127
- ).correct(
128
- source_map
129
- ) do |pins_to_add|
130
- described_class_pin = pins_to_add.first
131
- pins += pins_to_add
132
- end
133
-
134
- Correctors::LetMethodsCorrector.new(
135
- namespace_pins: namespace_pins,
136
- rspec_walker: rspec_walker
137
- ).correct(
138
- source_map
139
- ) do |pins_to_add|
140
- pins += pins_to_add
141
- end
142
-
143
- # @type [Pin::Method, nil]
144
- subject_pin = nil
145
- Correctors::SubjectMethodCorrector.new(
146
- namespace_pins: namespace_pins,
147
- rspec_walker: rspec_walker
148
- ).correct(
149
- source_map
150
- ) do |pins_to_add|
151
- subject_pin = pins_to_add.first
152
- pins += pins_to_add
153
- end
154
-
155
- Correctors::ContextBlockMethodsCorrector.new(
156
- namespace_pins: namespace_pins,
157
- rspec_walker: rspec_walker
158
- ).correct(source_map) do |pins_to_add|
159
- pins += pins_to_add
160
- end
161
-
162
- Correctors::DslMethodsCorrector.new(
163
- namespace_pins: namespace_pins,
164
- rspec_walker: rspec_walker,
165
- config: config
166
- ).correct(
167
- source_map
168
- ) do |pins_to_add|
169
- pins += pins_to_add
118
+ CORRECTOR_CLASSES.each do |corrector_class|
119
+ corrector_class.new(
120
+ namespace_pins: namespace_pins,
121
+ rspec_walker: rspec_walker,
122
+ added_pins: pins
123
+ ).correct(source_map)
170
124
  end
171
125
 
172
126
  rspec_walker.walk!
173
127
  pins += namespace_pins
174
128
 
175
- # Implicit subject
176
- if !subject_pin && described_class_pin
177
- Correctors::ImplicitSubjectMethodCorrector.new(
178
- namespace_pins: namespace_pins,
179
- described_class_pin: described_class_pin
180
- ).correct(
181
- source_map
182
- ) do |pins_to_add|
183
- subject_pin = pins_to_add.first
184
- pins += pins_to_add
185
- end
186
- end
187
-
188
129
  if pins.any?
189
130
  Solargraph.logger.debug(
190
131
  "[RSpec] added #{pins.map(&:inspect)} to #{source_map.filename}"
@@ -9,13 +9,22 @@ module Solargraph
9
9
  # @return [Array<Solargraph::Pin::Namespace>]
10
10
  attr_reader :namespace_pins
11
11
 
12
+ # @return [Solargraph::Rspec::SpecWalker]
13
+ attr_reader :rspec_walker
14
+
15
+ # @return [Array<Solargraph::Pin::Base]
16
+ attr_reader :added_pins
17
+
12
18
  # @param namespace_pins [Array<Solargraph::Pin::Base>]
13
- def initialize(namespace_pins:)
19
+ # @param rspec_walker [Solargraph::Rspec::SpecWalker]
20
+ # @param added_pins [Array<Solargraph::Pin::Base>]
21
+ def initialize(namespace_pins:, rspec_walker:, added_pins: [])
14
22
  @namespace_pins = namespace_pins
23
+ @rspec_walker = rspec_walker
24
+ @added_pins = added_pins
15
25
  end
16
26
 
17
27
  # @param _source_map [Solargraph::SourceMap]
18
- # @yield [Array<Solargraph::Pin::Base>] Pins to be added to the source map
19
28
  # @return [void]
20
29
  def correct(_source_map)
21
30
  raise NotImplementedError
@@ -23,6 +32,20 @@ module Solargraph
23
32
 
24
33
  private
25
34
 
35
+ # @param pin [Solargraph::Pin::Base, nil]
36
+ # @return [void]
37
+ def add_pin(pin)
38
+ return unless pin
39
+
40
+ added_pins.push(pin)
41
+ end
42
+
43
+ # @param pins [Array<Solargraph::Pin::Base>]
44
+ # @return [void]
45
+ def add_pins(*pins)
46
+ added_pins.concat(pins.flatten.compact)
47
+ end
48
+
26
49
  # @return [Solargraph::Pin::Namespace]
27
50
  def root_example_group_namespace_pin
28
51
  Solargraph::Pin::Namespace.new(
@@ -6,7 +6,7 @@ module Solargraph
6
6
  module Rspec
7
7
  module Correctors
8
8
  # A corrector that corrects pure ruby method blocks namespace defined inside describe/context blocks.
9
- class ContextBlockMethodsCorrector < WalkerBase
9
+ class ContextBlockMethodsCorrector < Base
10
10
  # @param source_map [Solargraph::SourceMap]
11
11
  def correct(source_map)
12
12
  rspec_walker.after_walk do
@@ -28,8 +28,6 @@ module Solargraph
28
28
  comments: pin.comments
29
29
  )
30
30
  end
31
-
32
- yield [] if block_given?
33
31
  end
34
32
  end
35
33
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'walker_base'
3
+ require_relative 'base'
4
4
 
5
5
  module Solargraph
6
6
  module Rspec
7
7
  module Correctors
8
- # A corrector of RSpec parsed pins by Solargraph
9
- class ContextBlockNamespaceCorrector < WalkerBase
8
+ # RSpec generates a namespace class for each context block. This corrector add the pins for those namespaces.
9
+ class ContextBlockNamespaceCorrector < Base
10
10
  # @param source_map [Solargraph::SourceMap]
11
11
  def correct(source_map)
12
12
  # @param location_range [Solargraph::Range]
@@ -52,12 +52,8 @@ module Solargraph
52
52
  )
53
53
 
54
54
  namespace_pins << namespace_pin
55
- if block_given?
56
- yield [
57
- namespace_include_pin,
58
- namespace_extend_pin
59
- ]
60
- end
55
+
56
+ add_pins(namespace_extend_pin, namespace_include_pin)
61
57
  end
62
58
  end
63
59
  end
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'walker_base'
3
+ require_relative 'base'
4
4
 
5
5
  module Solargraph
6
6
  module Rspec
7
7
  module Correctors
8
- class DescribedClassCorrector < WalkerBase
8
+ # Defines `described_class` method in the example group block
9
+ class DescribedClassCorrector < Base
9
10
  # @param source_map [Solargraph::SourceMap]
10
11
  # @return [void]
11
12
  def correct(_source_map)
@@ -14,7 +15,7 @@ module Solargraph
14
15
  next unless namespace_pin
15
16
 
16
17
  described_class_pin = rspec_described_class_method(namespace_pin, location_range, described_class_name)
17
- yield [described_class_pin].compact if block_given?
18
+ add_pin(described_class_pin)
18
19
  end
19
20
  end
20
21
 
@@ -1,44 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'walker_base'
3
+ require_relative 'base'
4
+ require 'yard'
4
5
 
5
6
  module Solargraph
6
7
  module Rspec
7
8
  module Correctors
8
- class DslMethodsCorrector < WalkerBase
9
- # @param namespace_pins [Array<Solargraph::Pin::Base>]
10
- # @param rspec_walker [Solargraph::Rspec::SpecWalker]
11
- # @param config [Solargraph::Rspec::Config]
12
- def initialize(namespace_pins:, rspec_walker:, config:)
13
- super(namespace_pins: namespace_pins, rspec_walker: rspec_walker)
14
- @config = config
9
+ # Includes DSL method helpers in the example group block for completion (ie. it, before, let, subject, etc.)
10
+ class DslMethodsCorrector < Base
11
+ # @return [Array<YARD::CodeObjects::Base>]
12
+ def self.rspec_yardoc_tags
13
+ @rspec_yardoc_tags ||= begin
14
+ spec = Gem::Specification.find_by_name('rspec-core')
15
+ require_paths = spec.require_paths.map { |path| File.join(spec.full_gem_path, path) }
16
+ Solargraph.logger.debug "[RSpec] Loading YARD registry for rspec-core from #{require_paths}"
17
+ YARD::Registry.load(require_paths, true)
18
+ YARD::Registry.all
19
+ end
15
20
  end
16
21
 
17
22
  # @param source_map [Solargraph::SourceMap]
18
23
  # @return [void]
19
24
  def correct(_source_map)
20
25
  rspec_walker.after_walk do
21
- if block_given?
22
- yield namespace_pins.flat_map { |namespace_pin| add_context_dsl_methods(namespace_pin) }
23
- yield namespace_pins.flat_map { |namespace_pin| add_methods_with_example_binding(namespace_pin) }
26
+ namespace_pins.each do |namespace_pin|
27
+ add_pins(context_dsl_methods(namespace_pin))
28
+ add_pins(methods_with_example_binding(namespace_pin))
24
29
  end
25
30
  end
26
31
  end
27
32
 
28
33
  private
29
34
 
30
- # @return [Solargraph::Rspec::Config]
31
- attr_reader :config
32
-
33
35
  # RSpec executes example and hook blocks (eg. it, before, after)in the context of the example group.
34
- # @yieldsef changes the binding of the block to correct class.
36
+ # Tag @yieldsef changes the binding of the block to correct class.
35
37
  # @return [Array<Solargraph::Pin::Method>]
36
- def add_methods_with_example_binding(namespace_pin)
38
+ def methods_with_example_binding(namespace_pin)
37
39
  rspec_context_block_methods.map do |method|
40
+ # TODO: Add location from YARD registry and documentation for other methods not just example group methods.
38
41
  PinFactory.build_public_method(
39
42
  namespace_pin,
40
43
  method.to_s,
41
- comments: ["@yieldself [#{namespace_pin.path}]"], # Fixes the binding of the block to the correct class
44
+ comments: [example_group_documentation(method), "@yieldself [#{namespace_pin.path}]"],
42
45
  scope: :class
43
46
  )
44
47
  end
@@ -48,7 +51,7 @@ module Solargraph
48
51
  # Fix this once Solargraph supports extending class methods.
49
52
  # @param namespace_pin [Solargraph::Pin::Base]
50
53
  # @return [Array<Solargraph::Pin::Base>]
51
- def add_context_dsl_methods(namespace_pin)
54
+ def context_dsl_methods(namespace_pin)
52
55
  Rspec::CONTEXT_METHODS.map do |method|
53
56
  PinFactory.build_public_method(
54
57
  namespace_pin,
@@ -58,10 +61,36 @@ module Solargraph
58
61
  end
59
62
  end
60
63
 
64
+ # @param method [String]
65
+ # @return [String]
66
+ def example_group_documentation(method)
67
+ return unless Rspec::EXAMPLE_METHODS.include?(method)
68
+
69
+ yardoc = rspec_yardoc_tags_at("RSpec::Core::ExampleGroup.#{method}")
70
+
71
+ unless yardoc
72
+ Solargraph.logger.warn "[RSpec] YARD documentation not found for RSpec::Core::ExampleGroup.#{method}"
73
+ return
74
+ end
75
+
76
+ yardoc.docstring.all
77
+ end
78
+
79
+ # @param method [String]
80
+ # @return [YARD::CodeObjects::MethodObject, nil]
81
+ def rspec_yardoc_tags_at(method_path)
82
+ self.class.rspec_yardoc_tags.find { |tag| tag.path == method_path }
83
+ end
84
+
61
85
  # @return [Array<String>]
62
86
  def rspec_context_block_methods
63
87
  config.let_methods + Rspec::HOOK_METHODS + Rspec::EXAMPLE_METHODS
64
88
  end
89
+
90
+ # @return [Solargraph::Rspec::Config]
91
+ def config
92
+ Solargraph::Rspec::Convention.config
93
+ end
65
94
  end
66
95
  end
67
96
  end
@@ -1,44 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'walker_base'
3
+ require_relative 'base'
4
4
 
5
5
  module Solargraph
6
6
  module Rspec
7
7
  module Correctors
8
- # Sets the correct namespace binding for example group blocks (it, example, etc.) and
9
- # hook blocks (before, after, around)
10
- class ExampleAndHookBlocksBindingCorrector < WalkerBase
8
+ # RSpec executes example and hook blocks in the context of the example group (ie. describe blocks).
9
+ # This correctors sets the right bindings to those blocks.
10
+ class ExampleAndHookBlocksBindingCorrector < Base
11
11
  # @param source_map [Solargraph::SourceMap]
12
12
  # @return [void]
13
13
  def correct(source_map)
14
14
  rspec_walker.on_example_block do |location_range|
15
15
  bind_closest_namespace(location_range, source_map)
16
-
17
- yield [] if block_given?
18
16
  end
19
17
 
20
18
  rspec_walker.on_hook_block do |location_range|
21
19
  bind_closest_namespace(location_range, source_map)
22
-
23
- yield [] if block_given?
24
20
  end
25
21
 
26
22
  rspec_walker.on_let_method do |_method_name, location_range|
27
23
  bind_closest_namespace(location_range, source_map)
28
-
29
- yield [] if block_given?
30
24
  end
31
25
 
32
26
  rspec_walker.on_blocks_in_examples do |location_range|
33
27
  bind_closest_namespace(location_range, source_map)
34
-
35
- yield [] if block_given?
36
28
  end
37
29
 
38
30
  rspec_walker.on_subject do |_method_name, location_range|
39
31
  bind_closest_namespace(location_range, source_map)
40
-
41
- yield [] if block_given?
42
32
  end
43
33
  end
44
34
 
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'walker_base'
3
+ require_relative 'base'
4
4
 
5
5
  module Solargraph
6
6
  module Rspec
7
7
  module Correctors
8
8
  # Defines let-like methods in the example group block
9
- class LetMethodsCorrector < WalkerBase
9
+ class LetMethodsCorrector < Base
10
10
  # @param source_map [Solargraph::SourceMap]
11
11
  # @return [void]
12
12
  def correct(_source_map)
@@ -15,7 +15,7 @@ module Solargraph
15
15
  next unless namespace_pin
16
16
 
17
17
  pin = rspec_let_method(namespace_pin, let_name, location_range, fake_method_ast)
18
- yield [pin] if block_given?
18
+ add_pin(pin)
19
19
  end
20
20
  end
21
21
 
@@ -11,14 +11,52 @@ module Solargraph
11
11
  # @return [void]
12
12
  def correct(_source_map)
13
13
  rspec_walker.on_subject do |subject_name, location_range, fake_method_ast|
14
- next unless subject_name
15
-
16
14
  namespace_pin = closest_namespace_pin(namespace_pins, location_range.start.line)
17
15
  next unless namespace_pin
18
16
 
19
- subject_pin = rspec_let_method(namespace_pin, subject_name, location_range, fake_method_ast)
20
- yield [subject_pin].compact if block_given?
17
+ subject_pin = rspec_subject_method(namespace_pin, subject_name, location_range, fake_method_ast)
18
+ add_pin(subject_pin)
21
19
  end
20
+
21
+ rspec_walker.after_walk do
22
+ next unless described_class_pin
23
+
24
+ namespace_pin = closest_namespace_pin(namespace_pins, described_class_pin.location.range.start.line)
25
+
26
+ add_pin(implicit_subject_pin(described_class_pin, namespace_pin)) if namespace_pin
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ # @return [Pin::Method, nil]
33
+ def described_class_pin
34
+ @described_class_pin ||= added_pins.find { |pin| pin.is_a?(Pin::Method) && pin.name == 'described_class' }
35
+ end
36
+
37
+ # @param namespace_pin [Pin::Namespace]
38
+ # @param subject_name [String, nil]
39
+ # @param location_range [Solargraph::Range]
40
+ # @param fake_method_ast [Parser::AST::Node]
41
+ # @return [Pin::Method]
42
+ def rspec_subject_method(namespace_pin, subject_name, location_range, fake_method_ast)
43
+ method_name = subject_name || 'subject'
44
+ rspec_let_method(namespace_pin, method_name, location_range, fake_method_ast)
45
+ end
46
+
47
+ # @param described_class_pin [Pin::Method]
48
+ # @param namespace_pin [Pin::Namespace]
49
+ # @return [Pin::Method]
50
+ def implicit_subject_pin(described_class_pin, namespace_pin)
51
+ described_class = described_class_pin.return_type.first.subtypes.first.name
52
+
53
+ PinFactory.build_public_method(
54
+ namespace_pin,
55
+ 'subject',
56
+ types: ["::#{described_class}"],
57
+ location: described_class_pin.location,
58
+ scope: :instance
59
+ )
22
60
  end
23
61
  end
24
62
  end
@@ -4,18 +4,18 @@ module Solargraph
4
4
  module Rspec
5
5
  class SpecWalker
6
6
  class FakeLetMethod
7
- MATCH_BODY = Regexp.union(
8
- /do(.*)end/m,
9
- /{(.*)}/m
10
- )
7
+ MATCH_DO_END = /.*? do(.*)end/m.freeze
8
+ MATCH_CURLY = /{(.*)}/m.freeze
11
9
 
12
10
  # @param block_ast [RubyVM::AbstractSyntaxTree::Node]
13
- # @return [RubyVM::AbstractSyntaxTree::Node]
11
+ # @return [RubyVM::AbstractSyntaxTree::Node, nil]
14
12
  def self.transform_block(block_ast, code, method_name = nil)
15
13
  method_name ||= NodeTypes.let_method_name(block_ast)
16
14
  block_body = block_ast.children[1]
17
- matches = code.lines[block_body.first_lineno - 1..block_body.last_lineno - 1].join.match(MATCH_BODY)
18
- method_body = (matches[1] || matches[2]).strip
15
+ let_definition_code = code.lines[block_body.first_lineno - 1..block_body.last_lineno - 1].join
16
+ match_do_end = let_definition_code.match(MATCH_DO_END)&.captures&.first || ''
17
+ match_curly = let_definition_code.match(MATCH_CURLY)&.captures&.first || ''
18
+ method_body = [match_do_end, match_curly].max_by(&:length).strip
19
19
 
20
20
  ast = RubyVM::AbstractSyntaxTree.parse <<~RUBY
21
21
  def #{method_name}
@@ -24,8 +24,11 @@ module Solargraph
24
24
  RUBY
25
25
 
26
26
  ast.children[2]
27
- rescue SyntaxError
28
- raise "Failed to build fake let method: #{block_ast.inspect}, message: #{e.message}"
27
+ rescue SyntaxError => e
28
+ Solargraph.logger.warn "[RSpec] Failed to build fake let method: #{e.message}, \
29
+ \n\nlet_definition_code: \n```\n#{let_definition_code}\n```, \
30
+ \n\nmethod_body: \n```\n#{method_body}\n```, \
31
+ \nast: #{block_ast.inspect}"
29
32
  ensure
30
33
  nil
31
34
  end
@@ -201,6 +201,10 @@ module Solargraph
201
201
  block_name = RspecContextNamespace.from_block_ast(block_ast)
202
202
  next unless block_name
203
203
 
204
+ # @HACK: When we describe `SomeClass` without a namespace, Solargraph confuses described_class with the
205
+ # `RSpec::ExampleGroups::SomeClass` constant. To avoid this, we append the root namespace with "Test"
206
+ block_name = "Test#{block_name}" if parent_namespace == Rspec::ROOT_NAMESPACE
207
+
204
208
  parent_namespace = namespace_name = "#{parent_namespace}::#{block_name}"
205
209
  block&.call(namespace_name, block_ast)
206
210
  next parent_namespace
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Solargraph
4
4
  module Rspec
5
- VERSION = '0.2.0'
5
+ VERSION = '0.2.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,35 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lekë Mula
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-20 00:00:00.000000000 Z
11
+ date: 2024-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: solargraph
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 0.49.0
20
17
  - - "~>"
21
18
  - !ruby/object:Gem::Version
22
19
  version: '0.49'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.49.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 0.49.0
30
27
  - - "~>"
31
28
  - !ruby/object:Gem::Version
32
29
  version: '0.49'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.49.0
33
33
  description: RSpec is a testing tool of choice for many Ruby developers. This plugin
34
34
  provides code completion and other features for RSpec files in Solargraph.
35
35
  email:
@@ -45,6 +45,7 @@ files:
45
45
  - LICENSE.txt
46
46
  - README.md
47
47
  - Rakefile
48
+ - codecov.yml
48
49
  - lib/solargraph-rspec.rb
49
50
  - lib/solargraph/rspec/config.rb
50
51
  - lib/solargraph/rspec/convention.rb
@@ -54,10 +55,8 @@ files:
54
55
  - lib/solargraph/rspec/correctors/described_class_corrector.rb
55
56
  - lib/solargraph/rspec/correctors/dsl_methods_corrector.rb
56
57
  - lib/solargraph/rspec/correctors/example_and_hook_blocks_binding_corrector.rb
57
- - lib/solargraph/rspec/correctors/implicit_subject_method_corrector.rb
58
58
  - lib/solargraph/rspec/correctors/let_methods_corrector.rb
59
59
  - lib/solargraph/rspec/correctors/subject_method_corrector.rb
60
- - lib/solargraph/rspec/correctors/walker_base.rb
61
60
  - lib/solargraph/rspec/pin_factory.rb
62
61
  - lib/solargraph/rspec/spec_walker.rb
63
62
  - lib/solargraph/rspec/spec_walker/fake_let_method.rb
@@ -90,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
89
  - !ruby/object:Gem::Version
91
90
  version: '0'
92
91
  requirements: []
93
- rubygems_version: 3.0.9
92
+ rubygems_version: 3.4.10
94
93
  signing_key:
95
94
  specification_version: 4
96
95
  summary: Solargraph plugin supporting RSpec code completion
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'let_methods_corrector'
4
-
5
- module Solargraph
6
- module Rspec
7
- module Correctors
8
- # Defines let-like methods in the example group block
9
- class ImplicitSubjectMethodCorrector < Base
10
- # @return [Pin::Method]
11
- attr_reader :described_class_pin
12
-
13
- # @param namespace_pins [Array<Pin::Namespace>]
14
- # @param described_class_pin [Pin::Method]
15
- def initialize(namespace_pins:, described_class_pin:)
16
- super(namespace_pins: namespace_pins)
17
-
18
- @described_class_pin = described_class_pin
19
- end
20
-
21
- # @param source_map [Solargraph::SourceMap]
22
- # @return [void]
23
- def correct(_source_map)
24
- namespace_pin = closest_namespace_pin(namespace_pins, described_class_pin.location.range.start.line)
25
-
26
- yield [implicit_subject_pin(described_class_pin, namespace_pin)] if block_given? && namespace_pin
27
- end
28
-
29
- private
30
-
31
- # @param described_class_pin [Pin::Method]
32
- # @param namespace_pin [Pin::Namespace]
33
- # @return [Pin::Method]
34
- def implicit_subject_pin(described_class_pin, namespace_pin)
35
- described_class = described_class_pin.return_type.first.subtypes.first.name
36
-
37
- PinFactory.build_public_method(
38
- namespace_pin,
39
- 'subject',
40
- types: ["::#{described_class}"],
41
- location: described_class_pin.location,
42
- scope: :instance
43
- )
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base'
4
-
5
- # A corrector that walks through RSpec AST nodes and corrects them
6
- module Solargraph
7
- module Rspec
8
- module Correctors
9
- # A corrector of RSpec parsed pins by Solargraph
10
- # @abstract
11
- class WalkerBase < Base
12
- # @return [Array<Solargraph::Pin::Namespace>]
13
- attr_reader :namespace_pins
14
-
15
- # @return [Solargraph::Rspec::SpecWalker]
16
- attr_reader :rspec_walker
17
-
18
- # @param namespace_pins [Array<Solargraph::Pin::Base>]
19
- # @param rspec_walker [Solargraph::Rspec::SpecWalker]
20
- def initialize(namespace_pins:, rspec_walker:)
21
- super(namespace_pins: namespace_pins)
22
- @rspec_walker = rspec_walker
23
- end
24
- end
25
- end
26
- end
27
- end