rubocop-thoughtbot 0.1.0 → 0.1.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: 56b7014c878946a04e2619ecb8a50cd7e2cd60199c4c4e3ea4fd362ca601b3e0
4
- data.tar.gz: 964048a771865a0092dd7461cfe3205bc8365818c62fd10302065fee2665f4c8
3
+ metadata.gz: c605025e3fecafd33bad54f248518f13564c99fb048c788fb3a08c73d9f1eb88
4
+ data.tar.gz: 6f5410b06ae7db53ec37016e0e09ba41edc71b4f410c258152c03bd976d946e4
5
5
  SHA512:
6
- metadata.gz: ce3ee7c537f213881a88c69798f2ffd282a7a124446b96034b2715b09b8491246399fc8a584ff0810e065f7928213ccb1a530441784922c1dcdfe9df865d6737
7
- data.tar.gz: ff3e7287274ab79cc20953993a44bd3edd2c456b7b529156b7b2ac26a54b22ab152a00dc2b41757901200a003507f91be650b27c4c9f271ba759fd194fd54b34
6
+ metadata.gz: f0d338a84df29c9c4d05d592623bce1b74b57107aa978ad53ac0274d9ea6ebf12f92ec3dc71b1c5719efa5f3fca4c3c75c741bc0fe45711640b6d025449ae266
7
+ data.tar.gz: e39d00609e04d7abb483421c76a241b2e278f1d1b2ebe32273a61d2d65416336b8688d962ff2f5c93356c01f59ec6b6ecf214f6ecf2feda284762405c6e3b478
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2026-07-29
3
+ ## [0.1.1] - 2026-08-14
4
+
5
+ ### Fixed
6
+
7
+ - `Thoughtbot/NoBefore` and `Thoughtbot/NoLet` now only flag a call that belongs to
8
+ an RSpec example group (`describe`, `context`, `feature`, `shared_examples` and
9
+ friends, with or without an `RSpec.` receiver). Sinatra and Grape define a
10
+ `before` of their own, so a fake app under `spec/support` was being flagged for a
11
+ hook that has nothing to do with RSpec.
12
+
13
+ ## [0.1.0] - 2026-08-14
4
14
 
5
15
  - Initial release
6
16
  - See [README](README.md) for context
data/README.md CHANGED
@@ -51,14 +51,11 @@ to be more trouble than it's worth will be removed.
51
51
 
52
52
  ## Installation
53
53
 
54
- This gem is not published to RubyGems yet, so install it from GitHub. Add it to
55
- your Gemfile:
54
+ Add the gem to your Gemfile:
56
55
 
57
56
  ```ruby
58
57
  group :development, :test do
59
- gem "rubocop-thoughtbot", github: "thoughtbot/rubocop-thoughtbot", require: false
60
- # Or via SSH while the repo is private
61
- # gem "rubocop-thoughtbot", git: "git@github.com:thoughtbot/rubocop-thoughtbot.git", require: false
58
+ gem "rubocop-thoughtbot", require: false
62
59
  end
63
60
  ```
64
61
 
@@ -146,7 +143,15 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
146
143
 
147
144
  ## Contributing
148
145
 
149
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rubocop-thoughtbot. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/rubocop-thoughtbot/blob/main/CODE_OF_CONDUCT.md).
146
+ Bug reports and pull requests are welcome on GitHub at https://github.com/thoughtbot/rubocop-thoughtbot. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/thoughtbot/rubocop-thoughtbot/blob/main/CODE_OF_CONDUCT.md).
147
+
148
+ ## Resources
149
+
150
+ - [RubyGems] — the published gem
151
+ - [Changelog] — release notes and version history
152
+
153
+ [RubyGems]: https://rubygems.org/gems/rubocop-thoughtbot
154
+ [Changelog]: CHANGELOG.md
150
155
 
151
156
  ## License
152
157
 
@@ -154,4 +159,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
154
159
 
155
160
  ## Code of Conduct
156
161
 
157
- Everyone interacting in the Rubocop::Thoughtbot project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/rubocop-thoughtbot/blob/main/CODE_OF_CONDUCT.md).
162
+ Everyone interacting in the Rubocop::Thoughtbot project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/thoughtbot/rubocop-thoughtbot/blob/main/CODE_OF_CONDUCT.md).
data/config/default.yml CHANGED
@@ -6,6 +6,7 @@ Thoughtbot/NoBefore:
6
6
  Description: 'Checks for `before` hooks in specs.'
7
7
  Enabled: true
8
8
  VersionAdded: '0.1.0'
9
+ VersionChanged: '0.1.1'
9
10
  Include:
10
11
  - '**/*_spec.rb'
11
12
  - '**/spec/**/*.rb'
@@ -14,6 +15,7 @@ Thoughtbot/NoLet:
14
15
  Description: 'Checks for `let` and `let!` declarations in specs.'
15
16
  Enabled: true
16
17
  VersionAdded: '0.1.0'
18
+ VersionChanged: '0.1.1'
17
19
  Include:
18
20
  - '**/*_spec.rb'
19
21
  - '**/spec/**/*.rb'
@@ -16,7 +16,7 @@
16
16
  | Yes
17
17
  | No
18
18
  | 0.1.0
19
- | -
19
+ | 0.1.1
20
20
  |===
21
21
 
22
22
  Checks for `before` hooks in specs.
@@ -38,17 +38,21 @@ See https://thoughtbot.com/blog/the-arrange-act-assert-pattern
38
38
  [source,ruby]
39
39
  ----
40
40
  # bad
41
- before { @user = build(:user) }
41
+ RSpec.describe User do
42
+ before { @user = build(:user) }
42
43
 
43
- it "is valid" do
44
- expect(@user).to be_valid
44
+ it "is valid" do
45
+ expect(@user).to be_valid
46
+ end
45
47
  end
46
48
 
47
49
  # good
48
- it "is valid" do
49
- user = build(:user)
50
+ RSpec.describe User do
51
+ it "is valid" do
52
+ user = build(:user)
50
53
 
51
- expect(user).to be_valid
54
+ expect(user).to be_valid
55
+ end
52
56
  end
53
57
  ----
54
58
 
@@ -73,7 +77,7 @@ end
73
77
  | Yes
74
78
  | No
75
79
  | 0.1.0
76
- | -
80
+ | 0.1.1
77
81
  |===
78
82
 
79
83
  Checks for `let` and `let!` declarations in specs.
@@ -95,17 +99,21 @@ See https://thoughtbot.com/blog/the-arrange-act-assert-pattern
95
99
  [source,ruby]
96
100
  ----
97
101
  # bad
98
- let(:user) { build(:user) }
102
+ RSpec.describe User do
103
+ let(:user) { build(:user) }
99
104
 
100
- it "is valid" do
101
- expect(user).to be_valid
105
+ it "is valid" do
106
+ expect(user).to be_valid
107
+ end
102
108
  end
103
109
 
104
110
  # good
105
- it "is valid" do
106
- user = build(:user)
111
+ RSpec.describe User do
112
+ it "is valid" do
113
+ user = build(:user)
107
114
 
108
- expect(user).to be_valid
115
+ expect(user).to be_valid
116
+ end
109
117
  end
110
118
  ----
111
119
 
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Thoughtbot
6
+ # Common functionality for cops that flag a bare RSpec DSL call.
7
+ #
8
+ # A spec directory holds more than specs. A fake Sinatra or Grape app
9
+ # under `spec/support` defines a `before` of its own, so a cop that
10
+ # matches on the method name alone flags code that has nothing to do
11
+ # with RSpec. Asking where the call sits keeps the cop to RSpec's DSL.
12
+ module SpecGroup
13
+ extend RuboCop::AST::NodePattern::Macros
14
+
15
+ SCOPES = %i[block numblock itblock class module].freeze
16
+
17
+ # Matches rubocop-rspec's `ExampleGroups` and `SharedGroups`.
18
+ SPEC_GROUPS = %i[
19
+ describe context feature example_group
20
+ xdescribe xcontext xfeature
21
+ fdescribe fcontext ffeature
22
+ shared_examples shared_examples_for shared_context
23
+ ].freeze
24
+
25
+ # @!method spec_group?(node)
26
+ def_node_matcher :spec_group?, <<~PATTERN
27
+ (any_block
28
+ (send {nil? (const {nil? cbase} :RSpec)} #spec_group_name? ...) ...)
29
+ PATTERN
30
+
31
+ # @!method extends_shared_context?(node)
32
+ def_node_matcher :extends_shared_context?, <<~PATTERN
33
+ (send nil? :extend (const (const {nil? cbase} :RSpec) :SharedContext))
34
+ PATTERN
35
+
36
+ private
37
+
38
+ def inside_spec_group?(node)
39
+ scope = enclosing_scope(node)
40
+
41
+ spec_group?(scope) || shared_context_module?(scope)
42
+ end
43
+
44
+ def spec_group_name?(name)
45
+ SPEC_GROUPS.include?(name)
46
+ end
47
+
48
+ def shared_context_module?(node)
49
+ return false unless node&.module_type?
50
+
51
+ body_statements(node).any? { |statement| extends_shared_context?(statement) }
52
+ end
53
+
54
+ def body_statements(node)
55
+ body = node.body
56
+
57
+ if body.nil?
58
+ []
59
+ elsif body.begin_type?
60
+ body.children
61
+ else
62
+ [body]
63
+ end
64
+ end
65
+
66
+ def enclosing_scope(node)
67
+ call = node.block_node || node
68
+
69
+ call.each_ancestor(*SCOPES).first
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -18,20 +18,26 @@ module RuboCop
18
18
  #
19
19
  # @example
20
20
  # # bad
21
- # before { @user = build(:user) }
21
+ # RSpec.describe User do
22
+ # before { @user = build(:user) }
22
23
  #
23
- # it "is valid" do
24
- # expect(@user).to be_valid
24
+ # it "is valid" do
25
+ # expect(@user).to be_valid
26
+ # end
25
27
  # end
26
28
  #
27
29
  # # good
28
- # it "is valid" do
29
- # user = build(:user)
30
+ # RSpec.describe User do
31
+ # it "is valid" do
32
+ # user = build(:user)
30
33
  #
31
- # expect(user).to be_valid
34
+ # expect(user).to be_valid
35
+ # end
32
36
  # end
33
37
  #
34
38
  class NoBefore < Base
39
+ include SpecGroup
40
+
35
41
  MSG = "Avoid `before` — set up test data inside each example so it " \
36
42
  "doesn't become a mystery guest. See https://thoughtbot.com/blog/lets-not"
37
43
 
@@ -39,6 +45,7 @@ module RuboCop
39
45
 
40
46
  def on_send(node)
41
47
  return if node.receiver
48
+ return unless inside_spec_group?(node)
42
49
 
43
50
  add_offense(node.loc.selector)
44
51
  end
@@ -18,20 +18,26 @@ module RuboCop
18
18
  #
19
19
  # @example
20
20
  # # bad
21
- # let(:user) { build(:user) }
21
+ # RSpec.describe User do
22
+ # let(:user) { build(:user) }
22
23
  #
23
- # it "is valid" do
24
- # expect(user).to be_valid
24
+ # it "is valid" do
25
+ # expect(user).to be_valid
26
+ # end
25
27
  # end
26
28
  #
27
29
  # # good
28
- # it "is valid" do
29
- # user = build(:user)
30
+ # RSpec.describe User do
31
+ # it "is valid" do
32
+ # user = build(:user)
30
33
  #
31
- # expect(user).to be_valid
34
+ # expect(user).to be_valid
35
+ # end
32
36
  # end
33
37
  #
34
38
  class NoLet < Base
39
+ include SpecGroup
40
+
35
41
  MSG = "Avoid `%<method>s` — set up test data inside each example so it " \
36
42
  "doesn't become a mystery guest. See https://thoughtbot.com/blog/lets-not"
37
43
 
@@ -39,6 +45,7 @@ module RuboCop
39
45
 
40
46
  def on_send(node)
41
47
  return if node.receiver
48
+ return unless inside_spec_group?(node)
42
49
 
43
50
  add_offense(node.loc.selector, message: format(MSG, method: node.method_name))
44
51
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "thoughtbot/mixin/spec_group"
4
+
3
5
  require_relative "thoughtbot/no_before"
4
6
  require_relative "thoughtbot/no_let"
5
7
  require_relative "thoughtbot/resourceful_actions"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Thoughtbot
5
- VERSION = "0.1.0"
5
+ VERSION = "0.1.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-thoughtbot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared Turner
@@ -62,6 +62,7 @@ files:
62
62
  - docs/modules/ROOT/pages/cops.adoc
63
63
  - docs/modules/ROOT/pages/cops_thoughtbot.adoc
64
64
  - lib/rubocop-thoughtbot.rb
65
+ - lib/rubocop/cop/thoughtbot/mixin/spec_group.rb
65
66
  - lib/rubocop/cop/thoughtbot/no_before.rb
66
67
  - lib/rubocop/cop/thoughtbot/no_let.rb
67
68
  - lib/rubocop/cop/thoughtbot/resourceful_actions.rb
@@ -69,13 +70,15 @@ files:
69
70
  - lib/rubocop/thoughtbot.rb
70
71
  - lib/rubocop/thoughtbot/plugin.rb
71
72
  - lib/rubocop/thoughtbot/version.rb
72
- homepage: http://github.com/thoughtbot/rubocop-thoughtbot
73
+ homepage: https://github.com/thoughtbot/rubocop-thoughtbot
73
74
  licenses:
74
75
  - MIT
75
76
  metadata:
76
- homepage_uri: http://github.com/thoughtbot/rubocop-thoughtbot
77
- source_code_uri: http://github.com/thoughtbot/rubocop-thoughtbot
78
- changelog_uri: http://github.com/thoughtbot/rubocop-thoughtbot/blob/main/CHANGELOG.md
77
+ homepage_uri: https://github.com/thoughtbot/rubocop-thoughtbot
78
+ source_code_uri: https://github.com/thoughtbot/rubocop-thoughtbot
79
+ changelog_uri: https://github.com/thoughtbot/rubocop-thoughtbot/blob/main/CHANGELOG.md
80
+ documentation_uri: https://github.com/thoughtbot/rubocop-thoughtbot/blob/main/docs/modules/ROOT/pages/cops_thoughtbot.adoc
81
+ bug_tracker_uri: https://github.com/thoughtbot/rubocop-thoughtbot/issues
79
82
  rubygems_mfa_required: 'true'
80
83
  default_lint_roller_plugin: RuboCop::Thoughtbot::Plugin
81
84
  rdoc_options: []