rubocop-factory_bot 2.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +69 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/MIT-LICENSE.md +21 -0
- data/README.md +88 -0
- data/config/default.yml +75 -0
- data/lib/rubocop/cop/factory_bot/attribute_defined_statically.rb +126 -0
- data/lib/rubocop/cop/factory_bot/consistent_parentheses_style.rb +115 -0
- data/lib/rubocop/cop/factory_bot/create_list.rb +258 -0
- data/lib/rubocop/cop/factory_bot/factory_class_name.rb +54 -0
- data/lib/rubocop/cop/factory_bot/factory_name_style.rb +72 -0
- data/lib/rubocop/cop/factory_bot/syntax_methods.rb +119 -0
- data/lib/rubocop/cop/factory_bot_cops.rb +8 -0
- data/lib/rubocop/factory_bot/config_formatter.rb +55 -0
- data/lib/rubocop/factory_bot/description_extractor.rb +70 -0
- data/lib/rubocop/factory_bot/factory_bot.rb +62 -0
- data/lib/rubocop/factory_bot/language.rb +35 -0
- data/lib/rubocop/factory_bot/version.rb +10 -0
- data/lib/rubocop-factory_bot.rb +16 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 44482485fe839223a23464d6739cbd0160ebaffa5402c9057d2fdc0e3c9b3295
|
4
|
+
data.tar.gz: 035ac59bb998b1268bf0803bce35b9c2ab75ac6f232a427e28996f0ea857f386
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fd92b4d37f8a352e1acc98ae2bbbad05982248d3ef97dfb6b99edfe5173ba087a4259db3718e1e05c0b7951574652b657b694d2f02a5c34cf162d17fe427303a
|
7
|
+
data.tar.gz: 10cf9b7446c6fbd09a2ffcfe8629be12c2dc334132d6515acd8015b0f22a7e06e01d704f42316730e096901889f189adcaff8730571df86e401e7767688c07f3
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## Master (Unreleased)
|
4
|
+
|
5
|
+
## 2.22.0 (2023-05-04)
|
6
|
+
|
7
|
+
- Extracted from `rubocop-rspec` into a separate repository for easier use with Minitest/Cucumber. ([@ydah])
|
8
|
+
|
9
|
+
## Previously (see [rubocop-rspec's changelist](https://github.com/rubocop/rubocop-rspec/blob/70a97b1895ce4b9bcd6ff336d5d343ddc6175fe6/CHANGELOG.md) for details)
|
10
|
+
|
11
|
+
- Fix a false positive for `RSpec/FactoryBot/ConsistentParenthesesStyle` inside `&&`, `||` and `:?` when `omit_parentheses` is on ([@dmitrytsepelev])
|
12
|
+
- Add new `RSpec/FactoryBot/FactoryNameStyle` cop. ([@ydah])
|
13
|
+
- Fix wrong autocorrection in `n_times` style on `RSpec/FactoryBot/CreateList`. ([@r7kamura])
|
14
|
+
- Fix a false positive for `RSpec/FactoryBot/ConsistentParenthesesStyle` when using `generate` with multiple arguments. ([@ydah])
|
15
|
+
- Fix `RSpec/FactoryBot/ConsistentParenthesesStyle` to ignore calls without the first positional argument. ([@pirj])
|
16
|
+
- Fix `RSpec/FactoryBot/ConsistentParenthesesStyle` to ignore calls inside a Hash or an Array. ([@pirj])
|
17
|
+
- Fix an incorrect autocorrect for `FactoryBot/ConsistentParenthesesStyle` with `omit_parentheses` option when method name and first argument are not on same line. ([@ydah])
|
18
|
+
- Add `RSpec/FactoryBot/ConsistentParenthesesStyle` cop. ([@Liberatys])
|
19
|
+
- Support `Array.new(n)` on `RSpec/FactoryBot/CreateList` cop. ([@r7kamura])
|
20
|
+
- Fixed false offense detection in `FactoryBot/CreateList` when a n.times block is including method calls in the factory create arguments. ([@ngouy])
|
21
|
+
- Fix error in `RSpec/RSpec/FactoryBot/CreateList` cop for empty block. ([@tejasbubane])
|
22
|
+
- Fix `RSpec/FactoryBot/SyntaxMethods` and `RSpec/Capybara/FeatureMethods` to inspect shared groups. ([@pirj])
|
23
|
+
- Add new `RSpec/FactoryBot/SyntaxMethods` cop. ([@leoarnold])
|
24
|
+
- Change namespace of several cops (`Capybara/*` -> `RSpec/Capybara/*`, `FactoryBot/*` -> `RSpec/FactoryBot/*`, `Rails/*` -> `RSpec/Rails/*`). ([@pirj], [@bquorning])
|
25
|
+
- Fix `FactoryBot/AttributeDefinedStatically` to allow `#traits_for_enum` without a block. ([@harrylewis])
|
26
|
+
- Improve the performance of `FactoryBot/AttributeDefinedStatically`, `RSpec/InstanceVariable`, `RSpec/LetSetup`, `RSpec/NestedGroups` and `RSpec/ReturnFromStub`. ([@andrykonchin])
|
27
|
+
- Improve message and description of `FactoryBot/FactoryClassName`. ([@ybiquitous])
|
28
|
+
- Fix `FactoryBot/FactoryClassName` to ignore `Hash` and `OpenStruct`. ([@jfragoulis])
|
29
|
+
- Add `FactoryBot/FactoryClassName` cop. ([@jfragoulis])
|
30
|
+
- Fix `FactoryBot/AttributeDefinedStatically` not working with an explicit receiver. ([@composerinteralia])
|
31
|
+
- Fix `FactoryBot/CreateList` autocorrect crashing when the factory is called with a block=. ([@Darhazer])
|
32
|
+
- `FactoryBot/CreateList` now ignores `times` blocks with an argument. ([@Darhazer])
|
33
|
+
- Fix `FactoryBot/AttributeDefinedStatically` not working when there is a non-symbol key. ([@vzvu3k6k])
|
34
|
+
- Fix false negative in `FactoryBot/AttributeDefinedStatically` when attribute is defined on `self`. ([@Darhazer])
|
35
|
+
- `RSpec/FactoryBot` cops will now also inspect the `spec/factories.rb` path by default. ([@bquorning])
|
36
|
+
- Add `FactoryBot/AttributeDefinedStatically` cop to help FactoryBot users with the deprecation of static attributes. ([@composerinteralia], [@seanpdoyle])
|
37
|
+
- Remove `FactoryBot/DynamicAttributeDefinedStatically` and `FactoryBot/StaticAttributeDefinedDynamically` cops. ([@composerinteralia])
|
38
|
+
- Fix `FactoryBot/DynamicAttributeDefinedStatically` false positive when using symbol proc argument for a sequence. ([@tdeo])
|
39
|
+
- Add `FactoryBot/CreateList` cop. ([@Darhazer])
|
40
|
+
- Fix `FactoryBot/StaticAttributeDefinedDynamically` to handle empty block. ([@abrom])
|
41
|
+
- Fix false positive in `FactoryBot/DynamicAttributeDefinedStatically` when a before/after callback has a symbol proc argument. ([@abrom])
|
42
|
+
- Fix `FactoryBot/DynamicAttributeDefinedStatically` to handle dynamic attributes inside arrays/hashes. ([@abrom])
|
43
|
+
- Add `FactoryBot/StaticAttributeDefinedDynamically` (based on dynamic attribute cop). ([@abrom])
|
44
|
+
- Rename namespace `FactoryGirl` to `FactoryBot` following original library update. ([@walf443])
|
45
|
+
- Add `RSpec/FactoryGirl` namespace including the first cop for factories: `FactoryGirl/DynamicAttributeDefinedStatically`. ([@jonatas])
|
46
|
+
|
47
|
+
<!-- Contributors (alphabetically) -->
|
48
|
+
|
49
|
+
[@abrom]: https://github.com/abrom
|
50
|
+
[@andrykonchin]: https://github.com/andrykonchin
|
51
|
+
[@bquorning]: https://github.com/bquorning
|
52
|
+
[@composerinteralia]: https://github.com/composerinteralia
|
53
|
+
[@darhazer]: https://github.com/Darhazer
|
54
|
+
[@dmitrytsepelev]: https://github.com/dmitrytsepelev
|
55
|
+
[@harrylewis]: https://github.com/harrylewis
|
56
|
+
[@jfragoulis]: https://github.com/jfragoulis
|
57
|
+
[@jonatas]: https://github.com/jonatas
|
58
|
+
[@leoarnold]: https://github.com/leoarnold
|
59
|
+
[@liberatys]: https://github.com/Liberatys
|
60
|
+
[@ngouy]: https://github.com/ngouy
|
61
|
+
[@pirj]: https://github.com/pirj
|
62
|
+
[@r7kamura]: https://github.com/r7kamura
|
63
|
+
[@seanpdoyle]: https://github.com/seanpdoyle
|
64
|
+
[@tdeo]: https://github.com/tdeo
|
65
|
+
[@tejasbubane]: https://github.com/tejasbubane
|
66
|
+
[@vzvu3k6k]: https://github.com/vzvu3k6k
|
67
|
+
[@walf443]: https://github.com/walf443
|
68
|
+
[@ybiquitous]: https://github.com/ybiquitous
|
69
|
+
[@ydah]: https://github.com/ydah
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# The RuboCop Community Code of Conduct
|
2
|
+
|
3
|
+
**Note:** We have picked the following code of conduct based on [Ruby's own
|
4
|
+
code of conduct](https://www.ruby-lang.org/en/conduct/).
|
5
|
+
|
6
|
+
This document provides a few simple community guidelines for a safe, respectful,
|
7
|
+
productive, and collaborative place for any person who is willing to contribute
|
8
|
+
to the RuboCop community. It applies to all "collaborative spaces", which are
|
9
|
+
defined as community communications channels (such as mailing lists, submitted
|
10
|
+
patches, commit comments, etc.).
|
11
|
+
|
12
|
+
- Participants will be tolerant of opposing views.
|
13
|
+
- Participants must ensure that their language and actions are free of personal
|
14
|
+
attacks and disparaging personal remarks.
|
15
|
+
- When interpreting the words and actions of others, participants should always
|
16
|
+
assume good intentions.
|
17
|
+
- Behaviour which can be reasonably considered harassment will not be tolerated.
|
data/MIT-LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Ian MacLeod <ian@nevir.net>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# RuboCop factory_bot
|
2
|
+
|
3
|
+
[![Join the chat at https://gitter.im/rubocop-rspec/Lobby](https://badges.gitter.im/rubocop-rspec/Lobby.svg)](https://gitter.im/rubocop-rspec/Lobby)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/rubocop-factory_bot.svg)](https://rubygems.org/gems/rubocop-factory_bot)
|
5
|
+
![CI](https://github.com/rubocop/rubocop-factory_bot/workflows/CI/badge.svg)
|
6
|
+
|
7
|
+
[Factory Bot](https://www.rubydoc.info/gems/factory_bot)-specific analysis for your projects, as an extension to
|
8
|
+
[RuboCop](https://github.com/rubocop/rubocop).
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Just install the `rubocop-factory_bot` gem
|
13
|
+
|
14
|
+
```bash
|
15
|
+
gem install rubocop-factory_bot
|
16
|
+
```
|
17
|
+
|
18
|
+
or if you use bundler put this in your `Gemfile`
|
19
|
+
|
20
|
+
```
|
21
|
+
gem 'rubocop-factory_bot', require: false
|
22
|
+
```
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
You need to tell RuboCop to load the Factory Bot extension. There are three
|
27
|
+
ways to do this:
|
28
|
+
|
29
|
+
### RuboCop configuration file
|
30
|
+
|
31
|
+
Put this into your `.rubocop.yml`.
|
32
|
+
|
33
|
+
```yaml
|
34
|
+
require: rubocop-factory_bot
|
35
|
+
```
|
36
|
+
|
37
|
+
Alternatively, use the following array notation when specifying multiple extensions.
|
38
|
+
|
39
|
+
```yaml
|
40
|
+
require:
|
41
|
+
- rubocop-other-extension
|
42
|
+
- rubocop-factory_bot
|
43
|
+
```
|
44
|
+
|
45
|
+
Now you can run `rubocop` and it will automatically load the RuboCop factory_bot
|
46
|
+
cops together with the standard cops.
|
47
|
+
|
48
|
+
### Command line
|
49
|
+
|
50
|
+
```bash
|
51
|
+
rubocop --require rubocop-factory_bot
|
52
|
+
```
|
53
|
+
|
54
|
+
### Rake task
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
RuboCop::RakeTask.new do |task|
|
58
|
+
task.requires << 'rubocop-factory_bot'
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
## Documentation
|
63
|
+
|
64
|
+
You can read more about RuboCop factory_bot in its [official manual](https://docs.rubocop.org/rubocop-factory_bot).
|
65
|
+
|
66
|
+
## The Cops
|
67
|
+
|
68
|
+
All cops are located under
|
69
|
+
[`lib/rubocop/cop/factory_bot`](lib/rubocop/cop/factory_bot), and contain
|
70
|
+
examples/documentation.
|
71
|
+
|
72
|
+
In your `.rubocop.yml`, you may treat the Factory Bot cops just like any other
|
73
|
+
cop. For example:
|
74
|
+
|
75
|
+
```yaml
|
76
|
+
FactoryBot/AttributeDefinedStatically:
|
77
|
+
Exclude:
|
78
|
+
- spec/factories/my_factory.rb
|
79
|
+
```
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
Checkout the [contribution guidelines](.github/CONTRIBUTING.md).
|
84
|
+
|
85
|
+
## License
|
86
|
+
|
87
|
+
`rubocop-factory_bot` is MIT licensed. [See the accompanying file](MIT-LICENSE.md) for
|
88
|
+
the full text.
|
data/config/default.yml
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
---
|
2
|
+
FactoryBot:
|
3
|
+
Enabled: true
|
4
|
+
Include:
|
5
|
+
- "**/*_spec.rb"
|
6
|
+
- "**/spec/**/*"
|
7
|
+
- "**/test/**/*"
|
8
|
+
- "**/features/support/factories/**/*.rb"
|
9
|
+
DocumentationBaseURL: https://docs.rubocop.org/rubocop-factory_bot
|
10
|
+
|
11
|
+
FactoryBot/AttributeDefinedStatically:
|
12
|
+
Description: Always declare attribute values as blocks.
|
13
|
+
Enabled: true
|
14
|
+
Include:
|
15
|
+
- spec/factories.rb
|
16
|
+
- spec/factories/**/*.rb
|
17
|
+
- features/support/factories/**/*.rb
|
18
|
+
VersionAdded: '1.28'
|
19
|
+
VersionChanged: '2.0'
|
20
|
+
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/AttributeDefinedStatically
|
21
|
+
|
22
|
+
FactoryBot/ConsistentParenthesesStyle:
|
23
|
+
Description: Use a consistent style for parentheses in factory bot calls.
|
24
|
+
Enabled: pending
|
25
|
+
EnforcedStyle: require_parentheses
|
26
|
+
SupportedStyles:
|
27
|
+
- require_parentheses
|
28
|
+
- omit_parentheses
|
29
|
+
VersionAdded: '2.14'
|
30
|
+
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/ConsistentParenthesesStyle
|
31
|
+
|
32
|
+
FactoryBot/CreateList:
|
33
|
+
Description: Checks for create_list usage.
|
34
|
+
Enabled: true
|
35
|
+
Include:
|
36
|
+
- "**/*_spec.rb"
|
37
|
+
- "**/spec/**/*"
|
38
|
+
- spec/factories.rb
|
39
|
+
- spec/factories/**/*.rb
|
40
|
+
- features/support/factories/**/*.rb
|
41
|
+
EnforcedStyle: create_list
|
42
|
+
SupportedStyles:
|
43
|
+
- create_list
|
44
|
+
- n_times
|
45
|
+
VersionAdded: '1.25'
|
46
|
+
VersionChanged: '2.0'
|
47
|
+
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/CreateList
|
48
|
+
|
49
|
+
FactoryBot/FactoryClassName:
|
50
|
+
Description: Use string value when setting the class attribute explicitly.
|
51
|
+
Enabled: true
|
52
|
+
Include:
|
53
|
+
- spec/factories.rb
|
54
|
+
- spec/factories/**/*.rb
|
55
|
+
- features/support/factories/**/*.rb
|
56
|
+
VersionAdded: '1.37'
|
57
|
+
VersionChanged: '2.0'
|
58
|
+
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/FactoryClassName
|
59
|
+
|
60
|
+
FactoryBot/FactoryNameStyle:
|
61
|
+
Description: Checks for name style for argument of FactoryBot::Syntax::Methods.
|
62
|
+
Enabled: pending
|
63
|
+
VersionAdded: '2.16'
|
64
|
+
EnforcedStyle: symbol
|
65
|
+
SupportedStyles:
|
66
|
+
- symbol
|
67
|
+
- string
|
68
|
+
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/FactoryNameStyle
|
69
|
+
|
70
|
+
FactoryBot/SyntaxMethods:
|
71
|
+
Description: Use shorthands from `FactoryBot::Syntax::Methods` in your specs.
|
72
|
+
Enabled: pending
|
73
|
+
SafeAutoCorrect: false
|
74
|
+
VersionAdded: '2.7'
|
75
|
+
Reference: https://www.rubydoc.info/gems/rubocop-factory_bot/RuboCop/Cop/FactoryBot/SyntaxMethods
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module FactoryBot
|
6
|
+
# Always declare attribute values as blocks.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# kind [:active, :rejected].sample
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# kind { [:active, :rejected].sample }
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# closed_at 1.day.from_now
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# closed_at { 1.day.from_now }
|
20
|
+
#
|
21
|
+
# # bad
|
22
|
+
# count 1
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# count { 1 }
|
26
|
+
#
|
27
|
+
class AttributeDefinedStatically < ::RuboCop::Cop::Base
|
28
|
+
extend AutoCorrector
|
29
|
+
|
30
|
+
MSG = 'Use a block to declare attribute values.'
|
31
|
+
|
32
|
+
# @!method value_matcher(node)
|
33
|
+
def_node_matcher :value_matcher, <<-PATTERN
|
34
|
+
(send _ !#reserved_method? $...)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
# @!method factory_attributes(node)
|
38
|
+
def_node_matcher :factory_attributes, <<-PATTERN
|
39
|
+
(block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } )
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
43
|
+
attributes = factory_attributes(node) || []
|
44
|
+
attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective
|
45
|
+
|
46
|
+
attributes.each do |attribute|
|
47
|
+
next unless offensive_receiver?(attribute.receiver, node)
|
48
|
+
next if proc?(attribute) || association?(attribute.first_argument)
|
49
|
+
|
50
|
+
add_offense(attribute) do |corrector|
|
51
|
+
autocorrect(corrector, attribute)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def autocorrect(corrector, node)
|
59
|
+
if node.parenthesized?
|
60
|
+
autocorrect_replacing_parens(corrector, node)
|
61
|
+
else
|
62
|
+
autocorrect_without_parens(corrector, node)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def offensive_receiver?(receiver, node)
|
67
|
+
receiver.nil? ||
|
68
|
+
receiver.self_type? ||
|
69
|
+
receiver_matches_first_block_argument?(receiver, node)
|
70
|
+
end
|
71
|
+
|
72
|
+
def receiver_matches_first_block_argument?(receiver, node)
|
73
|
+
first_block_argument = node.arguments.first
|
74
|
+
|
75
|
+
!first_block_argument.nil? &&
|
76
|
+
receiver.lvar_type? &&
|
77
|
+
receiver.node_parts == first_block_argument.node_parts
|
78
|
+
end
|
79
|
+
|
80
|
+
def proc?(attribute)
|
81
|
+
value_matcher(attribute).to_a.all?(&:block_pass_type?)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @!method association?(node)
|
85
|
+
def_node_matcher :association?, '(hash <(pair (sym :factory) _) ...>)'
|
86
|
+
|
87
|
+
def autocorrect_replacing_parens(corrector, node)
|
88
|
+
left_braces, right_braces = braces(node)
|
89
|
+
|
90
|
+
corrector.replace(node.location.begin, " #{left_braces}")
|
91
|
+
corrector.replace(node.location.end, right_braces)
|
92
|
+
end
|
93
|
+
|
94
|
+
def autocorrect_without_parens(corrector, node)
|
95
|
+
left_braces, right_braces = braces(node)
|
96
|
+
|
97
|
+
argument = node.first_argument
|
98
|
+
expression = argument.source_range
|
99
|
+
corrector.insert_before(expression, left_braces)
|
100
|
+
corrector.insert_after(expression, right_braces)
|
101
|
+
end
|
102
|
+
|
103
|
+
def braces(node)
|
104
|
+
if value_hash_without_braces?(node.first_argument)
|
105
|
+
['{ { ', ' } }']
|
106
|
+
else
|
107
|
+
['{ ', ' }']
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def value_hash_without_braces?(node)
|
112
|
+
node.hash_type? && !node.braces?
|
113
|
+
end
|
114
|
+
|
115
|
+
def reserved_method?(method_name)
|
116
|
+
RuboCop::FactoryBot.reserved_methods.include?(method_name)
|
117
|
+
end
|
118
|
+
|
119
|
+
def attribute_defining_method?(method_name)
|
120
|
+
RuboCop::FactoryBot.attribute_defining_methods
|
121
|
+
.include?(method_name)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module FactoryBot
|
6
|
+
# Use a consistent style for parentheses in factory bot calls.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# create :user
|
12
|
+
# build(:user)
|
13
|
+
# create(:login)
|
14
|
+
# create :login
|
15
|
+
#
|
16
|
+
# @example `EnforcedStyle: require_parentheses` (default)
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# create(:user)
|
20
|
+
# create(:user)
|
21
|
+
# create(:login)
|
22
|
+
# build(:login)
|
23
|
+
#
|
24
|
+
# @example `EnforcedStyle: omit_parentheses`
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# create :user
|
28
|
+
# build :user
|
29
|
+
# create :login
|
30
|
+
# create :login
|
31
|
+
#
|
32
|
+
# # also good
|
33
|
+
# # when method name and first argument are not on same line
|
34
|
+
# create(
|
35
|
+
# :user
|
36
|
+
# )
|
37
|
+
# build(
|
38
|
+
# :user,
|
39
|
+
# name: 'foo'
|
40
|
+
# )
|
41
|
+
#
|
42
|
+
class ConsistentParenthesesStyle < ::RuboCop::Cop::Base
|
43
|
+
extend AutoCorrector
|
44
|
+
include ConfigurableEnforcedStyle
|
45
|
+
include RuboCop::FactoryBot::Language
|
46
|
+
include RuboCop::Cop::Util
|
47
|
+
|
48
|
+
def self.autocorrect_incompatible_with
|
49
|
+
[Style::MethodCallWithArgsParentheses]
|
50
|
+
end
|
51
|
+
|
52
|
+
MSG_REQUIRE_PARENS = 'Prefer method call with parentheses'
|
53
|
+
MSG_OMIT_PARENS = 'Prefer method call without parentheses'
|
54
|
+
|
55
|
+
FACTORY_CALLS = RuboCop::FactoryBot::Language::METHODS
|
56
|
+
|
57
|
+
RESTRICT_ON_SEND = FACTORY_CALLS
|
58
|
+
|
59
|
+
# @!method factory_call(node)
|
60
|
+
def_node_matcher :factory_call, <<-PATTERN
|
61
|
+
(send
|
62
|
+
{#factory_bot? nil?} %FACTORY_CALLS
|
63
|
+
{sym str send lvar} _*
|
64
|
+
)
|
65
|
+
PATTERN
|
66
|
+
|
67
|
+
def on_send(node)
|
68
|
+
return if ambiguous_without_parentheses?(node)
|
69
|
+
|
70
|
+
factory_call(node) do
|
71
|
+
return if node.method?(:generate) && node.arguments.count > 1
|
72
|
+
|
73
|
+
if node.parenthesized?
|
74
|
+
process_with_parentheses(node)
|
75
|
+
else
|
76
|
+
process_without_parentheses(node)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def process_with_parentheses(node)
|
84
|
+
return unless style == :omit_parentheses
|
85
|
+
return unless same_line?(node, node.first_argument)
|
86
|
+
|
87
|
+
add_offense(node.loc.selector,
|
88
|
+
message: MSG_OMIT_PARENS) do |corrector|
|
89
|
+
remove_parentheses(corrector, node)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def process_without_parentheses(node)
|
94
|
+
return unless style == :require_parentheses
|
95
|
+
|
96
|
+
add_offense(node.loc.selector,
|
97
|
+
message: MSG_REQUIRE_PARENS) do |corrector|
|
98
|
+
add_parentheses(node, corrector)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
AMBIGUOUS_TYPES = %i[send pair array and or if].freeze
|
103
|
+
|
104
|
+
def ambiguous_without_parentheses?(node)
|
105
|
+
node.parent && AMBIGUOUS_TYPES.include?(node.parent.type)
|
106
|
+
end
|
107
|
+
|
108
|
+
def remove_parentheses(corrector, node)
|
109
|
+
corrector.replace(node.location.begin, ' ')
|
110
|
+
corrector.remove(node.location.end)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|