rubocop-rspec_parity 2.0.0 → 2.0.1

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: 2bda6248c84f44ce1e039baac11b9e6b3075c3feb13bb4e06a9e804ff26436a6
4
- data.tar.gz: ebc0e696c427bd033637609d7f1ad4aaa66c603a9ca1ed82adb09d2857c99161
3
+ metadata.gz: c258389ca56666df76d2865c8fee4ecca3dec132d02b7295d6e245747dbc4896
4
+ data.tar.gz: 02612dbd491de04d9819742f61bcdb47933837a6b3211d9888765e9eea94ef36
5
5
  SHA512:
6
- metadata.gz: 102aceedd06b6db82be97c0a45d95a57e22cb1b1ab7427875c6137f98dcfcc87b862cd2cc26dfc14d8f5604a24702166db12b6f94c1835f7e0395fd98082d556
7
- data.tar.gz: ca83d65bb73322941c49160de66943b2e1c6c93f35db372ef8cb559e5ea2cf3bdf1d3cc31151e654c8d19b620ceb1f4ee2f6dbf5ef8a8213277bd243c7104111
6
+ metadata.gz: 6fb8521af37136c1449fc5292fcc7658966f42f538197081d5a9ff53985dc4901c70e5e17c7a93c3204c8be0dc179c10c909ec2499ced966251d7ffc124e14e9
7
+ data.tar.gz: d18fc9c48f6063187c20472ada669bbf374192687dce5ae7e91d5bfceb2dc7b282340e623e72165363ad398d4e8cb43251dc8ef7820306cab73279ef71c92c41
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.0.1] - 2026-06-18
4
+
5
+ Fixed: `PublicMethodHasSpec` relaxed validation for single-public-method classes (e.g. service objects) no longer passes when the spec's only method-style `describe`/`context` covers a different method — if a method describe is present it must describe the actual public method.
6
+
3
7
  ## [2.0.0] - 2026-06-18
4
8
 
5
9
  Added: `SufficientContexts` now pinpoints which branch is untested — its message names one uncovered branch and the `# rspec_parity:covers <branch>` annotation to add, and the bundled `rspec-parity-cover` executable lists all of a method's gaps as paste-ready context stubs. Annotations are opt-in (new `CoversAnnotations` config key, default `true`).
data/README.md CHANGED
@@ -249,7 +249,24 @@ context 'when staff' do # rspec_parity:covers user.staff?
249
249
  end
250
250
  ```
251
251
 
252
- Re-run and the message advances to the next uncovered branch. Annotations are opt-in and only ever raise coverage — they never create a new violation, and each one covers exactly one branch. A mistyped label is reported with a did-you-mean suggestion.
252
+ Re-run and the message advances to the next uncovered branch. Annotations are opt-in and only ever raise coverage — they never create a new violation. A mistyped label is reported with a did-you-mean suggestion.
253
+
254
+ Each annotation covers exactly one branch, and the normal expectation is one annotation per context — one context, one scenario, one branch. In rare cases a single context genuinely exercises several branches at once; you can then list more than one branch on it, either as separate comments or with a `;`-separated list:
255
+
256
+ ```ruby
257
+ context 'when fully privileged' do
258
+ # rspec_parity:covers user.admin?
259
+ # rspec_parity:covers user.staff?
260
+ it { is_expected.to be_allowed }
261
+ end
262
+
263
+ # or, equivalently, on one line:
264
+ context 'when fully privileged' do # rspec_parity:covers user.admin?; user.staff?
265
+ it { is_expected.to be_allowed }
266
+ end
267
+ ```
268
+
269
+ Reach for this only when the branches really are covered together — multiple annotations on a context that only tests one path inflate coverage and defeat the point of the check.
253
270
 
254
271
  Long conditions can push the comment past `Layout/LineLength`; exempt these comments rather than editing the label:
255
272
 
@@ -219,8 +219,9 @@ module RuboCop
219
219
 
220
220
  # Check if relaxed validation applies
221
221
  if matches_skip_path? && count_public_methods(node) == 1
222
- # For single-method classes in configured paths, just check for examples
223
- return if spec_paths.any? { |spec_path| spec_has_examples?(spec_path, class_name) }
222
+ # For single-method classes in configured paths, the method describe is optional —
223
+ # but if one is present, it must describe the actual public method, not a private/random one.
224
+ return if relaxed_spec_valid?(spec_paths, class_name, method_name, instance_method, flexible_prefix)
224
225
  elsif spec_paths.any? do |sp|
225
226
  spec_covers_method?(sp, method_name, instance_method, flexible_prefix: flexible_prefix)
226
227
  end
@@ -233,6 +234,25 @@ module RuboCop
233
234
  end
234
235
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
235
236
 
237
+ # Relaxed validation for single-public-method classes in skip paths.
238
+ # Passes when the spec describes the class with examples AND either has no
239
+ # method-style describe/context block at all, or has one that covers the public method.
240
+ def relaxed_spec_valid?(spec_paths, class_name, method_name, instance_method, flexible_prefix)
241
+ return false unless spec_paths.any? { |sp| spec_has_examples?(sp, class_name) }
242
+ return true unless spec_paths.any? { |sp| spec_has_method_describe?(sp) }
243
+
244
+ spec_paths.any? do |sp|
245
+ spec_covers_method?(sp, method_name, instance_method, flexible_prefix: flexible_prefix)
246
+ end
247
+ end
248
+
249
+ # Detects a method-style block, e.g. describe '#foo' / context '.bar'
250
+ # (the char right after the quote is a `#` or `.` prefix), as opposed to a
251
+ # plain descriptive string or a class constant.
252
+ def spec_has_method_describe?(spec_path)
253
+ File.read(spec_path).match?(/(?:describe|context)\s+['"][#.][^'"]+['"]/)
254
+ end
255
+
236
256
  def spec_covers_method?(spec_path, method_name, instance_method, flexible_prefix: false)
237
257
  return true if method_tested_in_spec?(spec_path, method_name, instance_method)
238
258
  return true if flexible_prefix && method_tested_in_spec?(spec_path, method_name, !instance_method)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module RSpecParity
5
- VERSION = "2.0.0"
5
+ VERSION = "2.0.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec_parity
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Povilas Jurcys