solargraph-rspec 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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