rubocop-factory_bot 2.22.0
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 +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
|
+
[](https://gitter.im/rubocop-rspec/Lobby)
|
4
|
+
[](https://rubygems.org/gems/rubocop-factory_bot)
|
5
|
+

|
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
|