rubocop-rspec_parity 1.3.2 → 1.3.4

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: fe061c7b11557dedba1714eeb2df39a1030bf990a509501dda39781277557aca
4
- data.tar.gz: aff7a164338bc4f5b23a9aacf1a3b04c91e040f18bccd7cbdbdc0e931b6bb8b5
3
+ metadata.gz: b634068a8fe93d9576c210988a5ebab48f22f25058cf7c50e21710de1b7fb775
4
+ data.tar.gz: 9ac6bd2fc8503e43013e25e03413cb32dd8eb3d6ee44480f1a243f41e006781f
5
5
  SHA512:
6
- metadata.gz: b1989fb64fc261fb90ce9a3f0a8493715cf7f36015679424dd1a5e746f8cb47682901222c8f1ca078ccc310441a03b8c7671b77e331ae659933d863cfab55449
7
- data.tar.gz: 8e173ee1fd7e2aa65e29efe31ed30d5c05fac453579d79bcf3e53c8a7ad9617de435be3cd7b86ae4d5e3cc46815c913bffa939ac36ff3321944b5d2796443267
6
+ metadata.gz: ab0f3101fd7603ec83438f91772b6991446c9fbb2102cc32ebb948a02df1cfe8a6217e71b2629ba695135b717322d9ba6bd686bfe1a9f58fbe292ea1b70357ba
7
+ data.tar.gz: d30491decd3a61710bf1c873bbd268aad7d5a40e6d209b46676bf469871c54087e13a6111a47ad83437d5becb6416e5075cec6ca6a0e00a7b7657c873bb44ce2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.3.4] - 2026-02-23
4
+
5
+ Added: `PublicMethodHasSpec` now treats methods inside `class_methods do` blocks (ActiveSupport::Concern) as class methods, expecting `.method_name` in specs
6
+
7
+ ## [1.3.3] - 2026-02-20
8
+
9
+ Fixed: `PublicMethodHasSpec` offense message now shows correct method prefix (`#` for instance methods, `.` for class methods) and includes configured `DescribeAliases` in the expected describes
10
+ Fixed: `PublicMethodHasSpec` no longer reports methods in inner classes (class nested inside another class) as needing specs
11
+
3
12
  ## [1.3.2] - 2026-02-20
4
13
 
5
14
  Fixed: `PublicMethodHasSpec` now recognizes specs that use module wrapping (e.g., `module Foo; RSpec.describe Bar`) instead of fully qualified class names
@@ -16,7 +16,7 @@ module RuboCop
16
16
  include SpecFileFinder
17
17
 
18
18
  MSG = "Missing spec for public method `%<method_name>s`. " \
19
- "Expected describe '#%<method_name>s' or describe '.%<method_name>s' in %<spec_path>s"
19
+ "Expected %<expected>s in %<spec_path>s"
20
20
 
21
21
  COVERED_DIRECTORIES = %w[models controllers services jobs mailers helpers].freeze
22
22
  EXCLUDED_METHODS = %w[initialize].freeze
@@ -32,13 +32,15 @@ module RuboCop
32
32
 
33
33
  def on_def(node)
34
34
  return unless checkable_method?(node) && public_method?(node)
35
+ return if inside_inner_class?(node)
35
36
 
36
- check_method_has_spec(node, instance_method: !inside_eigenclass?(node))
37
+ check_method_has_spec(node, instance_method: !inside_eigenclass?(node) && !inside_class_methods_block?(node))
37
38
  end
38
39
 
39
40
  def on_defs(node)
40
41
  return unless checkable_method?(node) && public_class_method?(node)
41
42
  return if EXCLUDED_HOOK_METHODS.include?(node.method_name.to_s)
43
+ return if inside_inner_class?(node)
42
44
 
43
45
  check_method_has_spec(node, instance_method: false)
44
46
  end
@@ -75,6 +77,36 @@ module RuboCop
75
77
  node.each_ancestor.any? { |a| a.sclass_type? && a.children.first&.self_type? }
76
78
  end
77
79
 
80
+ def inside_class_methods_block?(node)
81
+ node.each_ancestor(:block).any? do |block_node|
82
+ block_node.send_node.method_name == :class_methods
83
+ end
84
+ end
85
+
86
+ def inside_inner_class?(node)
87
+ enclosing = find_class_or_module(node)
88
+ return false unless enclosing
89
+
90
+ enclosing.each_ancestor.any? { |a| a.class_type? && class_has_methods?(a) }
91
+ end
92
+
93
+ def class_has_methods?(class_node)
94
+ return false unless class_node.body
95
+
96
+ children = class_node.body.begin_type? ? class_node.body.children : [class_node.body]
97
+ children.any? { |child| child.def_type? || child.defs_type? || eigenclass_with_methods?(child) }
98
+ end
99
+
100
+ def eigenclass_with_methods?(node)
101
+ return false unless node.sclass_type? && node.children.first&.self_type?
102
+
103
+ body = node.body
104
+ return false unless body
105
+
106
+ body_children = body.begin_type? ? body.children : [body]
107
+ body_children.any?(&:def_type?)
108
+ end
109
+
78
110
  def should_check_file?
79
111
  path = processed_source.file_path
80
112
  return false if path.nil? || !path.include?("/app/") || path.end_with?("_spec.rb")
@@ -101,7 +133,13 @@ module RuboCop
101
133
  end
102
134
 
103
135
  def find_enclosing_scope(node)
104
- node.each_ancestor.find { |n| n.class_type? || n.module_type? || n.sclass_type? }
136
+ node.each_ancestor.find do |n|
137
+ n.class_type? || n.module_type? || n.sclass_type? || class_methods_block?(n)
138
+ end
139
+ end
140
+
141
+ def class_methods_block?(node)
142
+ node.block_type? && node.send_node.method_name == :class_methods
105
143
  end
106
144
 
107
145
  def find_class_or_module(node)
@@ -175,7 +213,7 @@ module RuboCop
175
213
  return
176
214
  end
177
215
 
178
- add_method_offense(node, method_name, spec_paths.first)
216
+ add_method_offense(node, method_name, spec_paths.first, instance_method: instance_method)
179
217
  end
180
218
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
181
219
 
@@ -191,13 +229,23 @@ module RuboCop
191
229
  end
192
230
  end
193
231
 
194
- def add_method_offense(node, method_name, spec_path)
232
+ def add_method_offense(node, method_name, spec_path, instance_method:)
233
+ prefix = instance_method ? "#" : "."
234
+ expected = expected_describes(prefix, method_name)
195
235
  add_offense(
196
236
  node.loc.keyword.join(node.loc.name),
197
- message: format(MSG, method_name: method_name, spec_path: relative_spec_path(spec_path))
237
+ message: format(MSG, method_name: method_name, expected: expected, spec_path: relative_spec_path(spec_path))
198
238
  )
199
239
  end
200
240
 
241
+ def expected_describes(prefix, method_name)
242
+ describes = ["describe '#{prefix}#{method_name}'"]
243
+ describe_aliases_for("#{prefix}#{method_name}").each do |alias_desc|
244
+ describes << "describe '#{alias_desc}'"
245
+ end
246
+ describes.join(" or ")
247
+ end
248
+
201
249
  def method_tested_in_spec?(spec_path, method_name, instance_method)
202
250
  spec_content = File.read(spec_path)
203
251
  prefix = instance_method ? "#" : "."
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module RSpecParity
5
- VERSION = "1.3.2"
5
+ VERSION = "1.3.4"
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: 1.3.2
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Povilas Jurcys