solargraph-rspec 0.2.2 β†’ 0.4.0

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: b218c57b18c9c34c920dc8085633940b40980109acc0767e3819f2f460af7598
4
- data.tar.gz: 8d33d3922c38de08dde380776138fb2eddee93f72aaaee1cd7ae4dce7610ac69
3
+ metadata.gz: f674511062484768d92fcae50b6f005a941e62933e08d8d0e1bd7d90ebb6751f
4
+ data.tar.gz: 84ca708c2c86a22cc6345763c4232a550298b1f65bb958f361aeee5e217adda4
5
5
  SHA512:
6
- metadata.gz: 0d6afb3098eeaa24b1c169ba6993306b14008837ebfd267c30bfe74788cd5deecb7985d33037984f5ed698d259daf9c698dba19f4eed0e6a346f521f081a2d7a
7
- data.tar.gz: 88699cf9f89421e1a0306d37ce912c1a1fc231cd722cc4338ec757efed7ca304791b1c2e3e3271b9cb057efe91f2d3db8fa22c70739b88569a0be59c9b0de229
6
+ metadata.gz: a5cb45cfec11d259c0ffd0d45b52027c64879115b34b8d857dbacfca12dbbd2a9c31ff2d68570dc9c269b3bfd1063e8dd799715250b172ac06685a732f85d4f2
7
+ data.tar.gz: 8a036f8b0c0fa38ebdde162df6715230edcc6b54d001daaaddc13e1793313a63dbdab2e968355c9eb16eef50b169b5543d583480ac49d23a25d60515f40cbb3f
data/.rubocop.yml CHANGED
@@ -13,6 +13,9 @@ Style/StringLiteralsInInterpolation:
13
13
  Style/Documentation:
14
14
  Enabled: false
15
15
 
16
+ Style/StructInheritance:
17
+ Enabled: false
18
+
16
19
  Layout/LineLength:
17
20
  Max: 120
18
21
 
data/CHANGELOG.md CHANGED
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## v.0.4.0 - 2024-08-25
11
+
12
+ ### Added
13
+
14
+ - Support for 3rd party helpers from most known RSpec extension libraries.
15
+ - [rspec-mocks](https://github.com/rspec/rspec-mocks)
16
+ - [rspec-rails](https://github.com/rspec/rspec-rails)
17
+ - [webmock](https://github.com/bblimke/webmock)
18
+ - [shoulda-matchers](https://matchers.shoulda.io/)
19
+ - [rspec-sidekiq](https://github.com/wspurgin/rspec-sidekiq)
20
+ - [airborne](https://github.com/brooklynDev/airborne)
21
+ - <details><summary>πŸ“Έ</summary>
22
+ <img src="./doc/images/3rd_party_matchers.png" width="600" alt="3rd party matchers completion">
23
+ </details>
24
+
25
+ - Implement RSpec [one-liner syntax](https://rspec.info/features/3-12/rspec-core/subject/one-liner-syntax/) helpers: `is_expected`, `should` and `should_not`
26
+ - <details><summary>πŸ“Ή</summary>
27
+ <img src="./doc/images/one_liners_demo.gif" width="600" alt="One-liner syntax completion">
28
+ </details>
29
+
30
+ ## v0.3.0 - 2024-07-10
31
+
32
+ ### Added
33
+
34
+ - Added `example_methods` as a configuration option to add your own example methods. (thanks to [@mskog](https://github.com/mskog) - first code contributor πŸŽ‰)
35
+
36
+ ## v0.2.2 - 2024-06-23
37
+
10
38
  ### Fixed
11
39
 
12
40
  - Suggest keeping `spec/**/*` in the `exclude` section of `.solargraph.yml` to avoid performance issues (see [commit](https://github.com/lekemula/solargraph-rspec/commit/3f0fc39e59e99bf9430e55c52ecb88650e49315e))
data/README.md CHANGED
@@ -7,17 +7,24 @@
7
7
 
8
8
  RSpec is a testing framework of choice for many Ruby developers. But at the same time is highly dynamic and heavily relying on metaprogramming making it hard to provide accurate code completion and type inference.
9
9
 
10
- This gem aims to provide better support for RSpec in Solargraph and it supports the following features:
11
- - `describe` and `it` methods completion
12
- - memoized `let` and `let!` methods completion
13
- - implicit and explicit `subject` methods
10
+ This gem aims to provide better support for RSpec in Solargraph and it supports the following features (completion, jump to definition and type inference πŸš€):
11
+ - `describe` and `it` methods
12
+ - memoized `let` and `let!` methods
14
13
  - `described_class` with appropriate type inference
15
- - `RSpec::Matchers` methods completion
16
- - type inference πŸš€
17
- - and more to come...
14
+ - implicit and explicit `subject` methods
15
+ - one liner syntax helpers `is_expected`, `should` and `should_not` linked to the appropriate subject
16
+ - Core and 3rd party spec helpers & matchers
17
+ - [rspec-mocks](https://github.com/rspec/rspec-mocks)
18
+ - [rspec-rails](https://github.com/rspec/rspec-rails)
19
+ - [webmock](https://github.com/bblimke/webmock)
20
+ - [shoulda-matchers](https://matchers.shoulda.io/)
21
+ - [rspec-sidekiq](https://github.com/wspurgin/rspec-sidekiq)
22
+ - [airborne](https://github.com/brooklynDev/airborne)
23
+ - Custom DSL extensions support (see [Configuration](#configuration) section)
24
+ - and more to come... ⏲️
18
25
 
19
- ![solargraph-rspec-with-types](https://github.com/lekemula/solargraph-rspec/assets/9197495/077e74f8-a800-4e90-8922-fa5351adcda3)
20
- ![solargraph-rspec-with-types-vs-code](https://github.com/lekemula/solargraph-rspec/assets/9197495/6a942460-256d-46ca-82de-9869a65309ec)
26
+ ![solargraph-rspec-with-types](./doc/images/vim_demo.gif)
27
+ ![solargraph-rspec-with-types-vs-code](./doc/images/vscode_demo.gif)
21
28
 
22
29
 
23
30
  ## Installation
@@ -80,6 +87,19 @@ rspec:
80
87
  - let_it_be
81
88
  ```
82
89
 
90
+ If you have your own custom `example`-like methods like `it`, you can add them to your `.solargraph.yml` file like this:
91
+
92
+ ```yaml
93
+ # .solargraph.yml
94
+ # ...
95
+ rspec:
96
+ example_methods:
97
+ - my_it
98
+ ```
99
+
100
+ This is useful if you use gems like [rspec-given](https://github.com/rspec-given/rspec-given) which introduces its own `let` and `example` methods.
101
+
102
+
83
103
  ### Gem completions
84
104
 
85
105
  Solargraph utilizes the YARD documentation to provide code completion. If you want to have completion for gems in your project, you can generate YARD documentation for them ([Read more](https://solargraph.org/guides/yard)).
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @!override ActionController::TestCase::Behavior#request
4
+ # @return [ActionDispatch::Request]
5
+ #
6
+ # @!override ActionController::TestCase::Behavior#response
7
+ # @return [ActionDispatch::Response]
@@ -20,6 +20,11 @@ module Solargraph
20
20
  (Rspec::LET_METHODS + additional_let_methods).map(&:to_sym)
21
21
  end
22
22
 
23
+ # @return [Array<Symbol>]
24
+ def example_methods
25
+ (Rspec::EXAMPLE_METHODS + additional_example_methods).map(&:to_sym)
26
+ end
27
+
23
28
  private
24
29
 
25
30
  # @return [Hash]
@@ -32,6 +37,11 @@ module Solargraph
32
37
  (rspec_raw_data['let_methods'] || []).map(&:to_sym)
33
38
  end
34
39
 
40
+ # @return [Array<Symbol>]
41
+ def additional_example_methods
42
+ (rspec_raw_data['example_methods'] || []).map(&:to_sym)
43
+ end
44
+
35
45
  # @return [Hash]
36
46
  def raw_data
37
47
  @solargraph_config.raw_data
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'config'
4
4
  require_relative 'spec_walker'
5
+ require_relative 'annotations'
5
6
  require_relative 'correctors/context_block_namespace_corrector'
6
7
  require_relative 'correctors/example_and_hook_blocks_binding_corrector'
7
8
  require_relative 'correctors/described_class_corrector'
@@ -9,12 +10,12 @@ require_relative 'correctors/let_methods_corrector'
9
10
  require_relative 'correctors/subject_method_corrector'
10
11
  require_relative 'correctors/context_block_methods_corrector'
11
12
  require_relative 'correctors/dsl_methods_corrector'
13
+ require_relative 'test_helpers'
12
14
  require_relative 'pin_factory'
13
15
 
14
16
  module Solargraph
15
17
  module Rspec
16
18
  ROOT_NAMESPACE = 'RSpec::ExampleGroups'
17
- HELPER_MODULES = ['RSpec::Matchers'].freeze
18
19
  HOOK_METHODS = %w[before after around].freeze
19
20
  LET_METHODS = %w[let let!].freeze
20
21
  SUBJECT_METHODS = %w[subject subject!].freeze
@@ -83,7 +84,12 @@ module Solargraph
83
84
  # @return [Environ]
84
85
  def global(_yard_map)
85
86
  pins = []
86
- pins += include_helper_pins
87
+ pins += Solargraph::Rspec::TestHelpers.include_helper_pins(
88
+ root_example_group_namespace_pin: root_example_group_namespace_pin
89
+ )
90
+ pins += annotation_pins
91
+ # TODO: Include gem requires conditionally based on Gemfile definition
92
+ requires = Solargraph::Rspec::TestHelpers.gem_names
87
93
 
88
94
  if pins.any?
89
95
  Solargraph.logger.debug(
@@ -91,7 +97,9 @@ module Solargraph
91
97
  )
92
98
  end
93
99
 
94
- Environ.new(pins: pins)
100
+ Solargraph.logger.debug "[RSpec] added requires #{requires}"
101
+
102
+ Environ.new(requires: requires, pins: pins)
95
103
  rescue StandardError => e
96
104
  raise e if ENV['SOLARGRAPH_DEBUG']
97
105
 
@@ -132,7 +140,7 @@ module Solargraph
132
140
  )
133
141
  end
134
142
 
135
- Environ.new(requires: ['rspec'], pins: pins)
143
+ Environ.new(requires: [], pins: pins)
136
144
  rescue StandardError => e
137
145
  raise e if ENV['SOLARGRAPH_DEBUG']
138
146
 
@@ -144,19 +152,6 @@ module Solargraph
144
152
 
145
153
  private
146
154
 
147
- # @param helper_modules [Array<String>]
148
- # @param source_map [SourceMap]
149
- # @return [Array<Pin::Base>]
150
- def include_helper_pins(helper_modules: HELPER_MODULES)
151
- helper_modules.map do |helper_module|
152
- PinFactory.build_module_include(
153
- root_example_group_namespace_pin,
154
- helper_module,
155
- root_example_group_namespace_pin.location
156
- )
157
- end
158
- end
159
-
160
155
  # @return [Config]
161
156
  def config
162
157
  self.class.config
@@ -169,6 +164,14 @@ module Solargraph
169
164
  location: PinFactory.dummy_location('lib/rspec/core/example_group.rb')
170
165
  )
171
166
  end
167
+
168
+ # @return [Array<Pin::Base>]
169
+ def annotation_pins
170
+ ann = File.read("#{File.dirname(__FILE__)}/annotations.rb")
171
+ source = Solargraph::Source.load_string(ann, 'rspec-annotations.rb')
172
+ map = Solargraph::SourceMap.map(source)
173
+ map.pins
174
+ end
172
175
  end
173
176
  end
174
177
  end
@@ -16,6 +16,7 @@ module Solargraph
16
16
 
17
17
  subject_pin = rspec_subject_method(namespace_pin, subject_name, location_range, fake_method_ast)
18
18
  add_pin(subject_pin)
19
+ add_pins(one_liner_expectation_pins(subject_pin))
19
20
  end
20
21
 
21
22
  rspec_walker.after_walk do
@@ -23,7 +24,11 @@ module Solargraph
23
24
 
24
25
  namespace_pin = closest_namespace_pin(namespace_pins, described_class_pin.location.range.start.line)
25
26
 
26
- add_pin(implicit_subject_pin(described_class_pin, namespace_pin)) if namespace_pin
27
+ if namespace_pin
28
+ implicit_subject_pin = implicit_subject_method(described_class_pin, namespace_pin)
29
+ add_pin(implicit_subject_pin)
30
+ add_pins(one_liner_expectation_pins(implicit_subject_pin))
31
+ end
27
32
  end
28
33
  end
29
34
 
@@ -47,7 +52,7 @@ module Solargraph
47
52
  # @param described_class_pin [Pin::Method]
48
53
  # @param namespace_pin [Pin::Namespace]
49
54
  # @return [Pin::Method]
50
- def implicit_subject_pin(described_class_pin, namespace_pin)
55
+ def implicit_subject_method(described_class_pin, namespace_pin)
51
56
  described_class = described_class_pin.return_type.first.subtypes.first.name
52
57
 
53
58
  PinFactory.build_public_method(
@@ -58,6 +63,41 @@ module Solargraph
58
63
  scope: :instance
59
64
  )
60
65
  end
66
+
67
+ # @param subject_pin [Pin::Method]
68
+ # @return [Array<Pin::Method>]
69
+ def one_liner_expectation_pins(subject_pin)
70
+ [
71
+ one_liner_expectation_pin(subject_pin.closure, :is_expected, subject_pin.location),
72
+ one_liner_expectation_pin(subject_pin.closure, :should, subject_pin.location),
73
+ one_liner_expectation_pin(subject_pin.closure, :should_not, subject_pin.location)
74
+ ]
75
+ end
76
+
77
+ # @param namespace_pin [Pin::Namespace]
78
+ # @param method_name [:is_expected, :should, :should_not]
79
+ # @param location [Solargraph::Location]
80
+ # @return [Pin::Method]
81
+ def one_liner_expectation_pin(namespace_pin, method_name, location)
82
+ return_type = case method_name
83
+ when :is_expected
84
+ ['::RSpec::Expectations::ExpectationTarget']
85
+ when :should
86
+ ['::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher']
87
+ when :should_not
88
+ ['::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher']
89
+ else
90
+ raise ArgumentError, "Unknown inline expectation method: #{method_name}"
91
+ end
92
+
93
+ PinFactory.build_public_method(
94
+ namespace_pin,
95
+ method_name.to_s,
96
+ types: [return_type],
97
+ location: location,
98
+ scope: :instance
99
+ )
100
+ end
61
101
  end
62
102
  end
63
103
  end
@@ -25,9 +25,10 @@ module Solargraph
25
25
  end
26
26
 
27
27
  # @param ast [RubyVM::AbstractSyntaxTree::Node]
28
+ # @param config [Config]
28
29
  # @return [Boolean]
29
- def self.a_example_block?(block_ast)
30
- Solargraph::Rspec::EXAMPLE_METHODS.include?(method_with_block_name(block_ast))
30
+ def self.a_example_block?(block_ast, config)
31
+ config.example_methods.map(&:to_s).include?(method_with_block_name(block_ast))
31
32
  end
32
33
 
33
34
  # @param ast [RubyVM::AbstractSyntaxTree::Node]
@@ -138,7 +138,7 @@ module Solargraph
138
138
  end
139
139
 
140
140
  walker.on :ITER do |block_ast|
141
- next unless NodeTypes.a_example_block?(block_ast)
141
+ next unless NodeTypes.a_example_block?(block_ast, config)
142
142
 
143
143
  @handlers[:on_example_block].each do |handler|
144
144
  handler.call(PinFactory.build_location_range(block_ast))
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Rspec
5
+ class TestHelpers
6
+ class GemHelpers < Struct.new(:required_gems, :helper_modules, keyword_init: true)
7
+ # @!attribute [r] required_gems
8
+ # @return [Array<String>]
9
+ # @!attribute [r] helper_modules
10
+ # @return [Array<String>]
11
+ end
12
+
13
+ class << self
14
+ # @return [String]
15
+ def gem_names
16
+ GEM_HELPERS.flat_map(&:required_gems)
17
+ end
18
+
19
+ # @return [Array<String>]
20
+ def helper_module_names
21
+ GEM_HELPERS.flat_map(&:helper_modules)
22
+ end
23
+
24
+ # @param root_example_group_namespace_pin [Pin::Namespace]
25
+ # @return [Array<Pin::Reference::Include>]
26
+ def include_helper_pins(root_example_group_namespace_pin:)
27
+ Solargraph.logger.debug "[RSpec] adding helper modules #{helper_module_names}"
28
+ helper_module_names.map do |helper_module|
29
+ PinFactory.build_module_include(
30
+ root_example_group_namespace_pin,
31
+ helper_module,
32
+ root_example_group_namespace_pin.location
33
+ )
34
+ end
35
+ end
36
+ end
37
+
38
+ GEM_HELPERS = [
39
+ GemHelpers.new(
40
+ required_gems: %w[rspec],
41
+ helper_modules: %w[RSpec::Matchers]
42
+ ),
43
+ # https://github.com/rspec/rspec-mocks
44
+ GemHelpers.new(
45
+ required_gems: %w[rspec-mocks],
46
+ helper_modules: %w[RSpec::Mocks::ExampleMethods]
47
+ ),
48
+ # @see https://github.com/rspec/rspec-rails#what-tests-should-i-write
49
+ # @see https://github.com/rspec/rspec-rails#helpful-rails-matchers
50
+ GemHelpers.new(
51
+ required_gems: %w[rspec-rails actionmailer activesupport activerecord],
52
+ helper_modules: [
53
+ 'RSpec::Rails::Matchers',
54
+ 'ActionController::TestCase::Behavior',
55
+ 'ActionMailer::TestCase::Behavior',
56
+ 'ActiveSupport::Testing::Assertions',
57
+ 'ActiveSupport::Testing::TimeHelpers',
58
+ 'ActiveSupport::Testing::FileFixtures',
59
+ 'ActiveRecord::TestFixtures',
60
+ 'ActionDispatch::Integration::Runner',
61
+ 'ActionDispatch::Routing::UrlFor',
62
+ 'ActionController::TemplateAssertions'
63
+ ]
64
+ ),
65
+ # @see https://matchers.shoulda.io/docs/v6.2.0/#matchers
66
+ GemHelpers.new(
67
+ required_gems: %w[shoulda-matchers],
68
+ helper_modules: [
69
+ 'Shoulda::Matchers::ActiveModel',
70
+ 'Shoulda::Matchers::ActiveRecord',
71
+ 'Shoulda::Matchers::ActionController',
72
+ 'Shoulda::Matchers::Routing'
73
+ ]
74
+ ),
75
+ # @see https://github.com/wspurgin/rspec-sidekiq#matchers
76
+ GemHelpers.new(
77
+ required_gems: %w[rspec-sidekiq],
78
+ helper_modules: %w[RSpec::Sidekiq::Matchers]
79
+ ),
80
+ # @see https://github.com/bblimke/webmock#examples
81
+ GemHelpers.new(
82
+ required_gems: %w[webmock],
83
+ helper_modules: %w[WebMock::API WebMock::Matchers]
84
+ ),
85
+ # @see https://github.com/brooklynDev/airborne
86
+ GemHelpers.new(
87
+ required_gems: %w[airborne],
88
+ helper_modules: %w[Airborne]
89
+ )
90
+ ].freeze
91
+ end
92
+ end
93
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Solargraph
4
4
  module Rspec
5
- VERSION = '0.2.2'
5
+ VERSION = '0.4.0'
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.2
4
+ version: 0.4.0
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-06-23 00:00:00.000000000 Z
11
+ date: 2024-08-25 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'
20
17
  - - ">="
21
18
  - !ruby/object:Gem::Version
22
19
  version: 0.49.0
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '0.49'
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'
30
27
  - - ">="
31
28
  - !ruby/object:Gem::Version
32
29
  version: 0.49.0
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.49'
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:
@@ -46,7 +46,12 @@ files:
46
46
  - README.md
47
47
  - Rakefile
48
48
  - codecov.yml
49
+ - doc/images/3rd_party_matchers.png
50
+ - doc/images/one_liners_demo.gif
51
+ - doc/images/vim_demo.gif
52
+ - doc/images/vscode_demo.gif
49
53
  - lib/solargraph-rspec.rb
54
+ - lib/solargraph/rspec/annotations.rb
50
55
  - lib/solargraph/rspec/config.rb
51
56
  - lib/solargraph/rspec/convention.rb
52
57
  - lib/solargraph/rspec/correctors/base.rb
@@ -63,6 +68,7 @@ files:
63
68
  - lib/solargraph/rspec/spec_walker/full_constant_name.rb
64
69
  - lib/solargraph/rspec/spec_walker/node_types.rb
65
70
  - lib/solargraph/rspec/spec_walker/rspec_context_namespace.rb
71
+ - lib/solargraph/rspec/test_helpers.rb
66
72
  - lib/solargraph/rspec/version.rb
67
73
  - lib/solargraph/rspec/walker.rb
68
74
  - lib/solargraph_rspec.rb
@@ -89,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
95
  - !ruby/object:Gem::Version
90
96
  version: '0'
91
97
  requirements: []
92
- rubygems_version: 3.4.10
98
+ rubygems_version: 3.0.9
93
99
  signing_key:
94
100
  specification_version: 4
95
101
  summary: Solargraph plugin supporting RSpec code completion