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 +4 -4
- data/CHANGELOG.md +11 -1
- data/README.md +12 -7
- data/config/default.yml +2 -0
- data/docs/modules/ROOT/pages/cops_thoughtbot.adoc +22 -14
- data/lib/rubocop/cop/thoughtbot/mixin/spec_group.rb +74 -0
- data/lib/rubocop/cop/thoughtbot/no_before.rb +13 -6
- data/lib/rubocop/cop/thoughtbot/no_let.rb +13 -6
- data/lib/rubocop/cop/thoughtbot_cops.rb +2 -0
- data/lib/rubocop/thoughtbot/version.rb +1 -1
- metadata +8 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c605025e3fecafd33bad54f248518f13564c99fb048c788fb3a08c73d9f1eb88
|
|
4
|
+
data.tar.gz: 6f5410b06ae7db53ec37016e0e09ba41edc71b4f410c258152c03bd976d946e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
-
|
|
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",
|
|
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/
|
|
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/
|
|
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
|
-
|
|
41
|
+
RSpec.describe User do
|
|
42
|
+
before { @user = build(:user) }
|
|
42
43
|
|
|
43
|
-
it "is valid" do
|
|
44
|
-
|
|
44
|
+
it "is valid" do
|
|
45
|
+
expect(@user).to be_valid
|
|
46
|
+
end
|
|
45
47
|
end
|
|
46
48
|
|
|
47
49
|
# good
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
RSpec.describe User do
|
|
51
|
+
it "is valid" do
|
|
52
|
+
user = build(:user)
|
|
50
53
|
|
|
51
|
-
|
|
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
|
-
|
|
102
|
+
RSpec.describe User do
|
|
103
|
+
let(:user) { build(:user) }
|
|
99
104
|
|
|
100
|
-
it "is valid" do
|
|
101
|
-
|
|
105
|
+
it "is valid" do
|
|
106
|
+
expect(user).to be_valid
|
|
107
|
+
end
|
|
102
108
|
end
|
|
103
109
|
|
|
104
110
|
# good
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
RSpec.describe User do
|
|
112
|
+
it "is valid" do
|
|
113
|
+
user = build(:user)
|
|
107
114
|
|
|
108
|
-
|
|
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
|
-
#
|
|
21
|
+
# RSpec.describe User do
|
|
22
|
+
# before { @user = build(:user) }
|
|
22
23
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
24
|
+
# it "is valid" do
|
|
25
|
+
# expect(@user).to be_valid
|
|
26
|
+
# end
|
|
25
27
|
# end
|
|
26
28
|
#
|
|
27
29
|
# # good
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
+
# RSpec.describe User do
|
|
31
|
+
# it "is valid" do
|
|
32
|
+
# user = build(:user)
|
|
30
33
|
#
|
|
31
|
-
#
|
|
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
|
-
#
|
|
21
|
+
# RSpec.describe User do
|
|
22
|
+
# let(:user) { build(:user) }
|
|
22
23
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
24
|
+
# it "is valid" do
|
|
25
|
+
# expect(user).to be_valid
|
|
26
|
+
# end
|
|
25
27
|
# end
|
|
26
28
|
#
|
|
27
29
|
# # good
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
+
# RSpec.describe User do
|
|
31
|
+
# it "is valid" do
|
|
32
|
+
# user = build(:user)
|
|
30
33
|
#
|
|
31
|
-
#
|
|
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
|
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.
|
|
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:
|
|
73
|
+
homepage: https://github.com/thoughtbot/rubocop-thoughtbot
|
|
73
74
|
licenses:
|
|
74
75
|
- MIT
|
|
75
76
|
metadata:
|
|
76
|
-
homepage_uri:
|
|
77
|
-
source_code_uri:
|
|
78
|
-
changelog_uri:
|
|
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: []
|