rubocop-sane_conditionals 1.0.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/LICENSE.txt +21 -0
- data/README.md +196 -0
- data/config/default.yml +16 -0
- data/lib/rubocop/cop/style/if_unless_modifier_multiline.rb +63 -0
- data/lib/rubocop/cop/style/no_unless.rb +113 -0
- data/lib/rubocop-sane_conditionals/version.rb +7 -0
- data/lib/rubocop-sane_conditionals.rb +10 -0
- metadata +67 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 145264fffb5808ff6c7f5dfe04ffbf1340fd91fd1e86e150f471a9c41f086a39
|
|
4
|
+
data.tar.gz: fd868cb346b3296caee3e963831a43760ad7eb3c6f6ec430b818f3740c093034
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: eb90cdf3cd716033916415e0ebe1fb2ea864a295828b6284cf93c17e3a418848f6f00f6fcabaf9977714edcdbc7fb9f4d9ba39f346589883938d96047fcea35e
|
|
7
|
+
data.tar.gz: 962ae39df0757a3702fdd2f413b7ac3f98a185031f84eb859a9a23cc787955e3bb582de437941a50092035ce746b70937b576356f7d701bf6bda13e2ed9b4e03
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Federico
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do 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,196 @@
|
|
|
1
|
+
# rubocop-sane_conditionals
|
|
2
|
+
|
|
3
|
+
RuboCop cops for people who want to read code, not decode it.
|
|
4
|
+
|
|
5
|
+
## The Problem
|
|
6
|
+
|
|
7
|
+
Ruby is a beautiful language. It is expressive, elegant, and reads almost like
|
|
8
|
+
English. This is exactly the problem.
|
|
9
|
+
|
|
10
|
+
At some point, someone decided that because Ruby *can* read like English, it
|
|
11
|
+
*should* read like English — and then they implemented the wrong kind of
|
|
12
|
+
English. The kind where the subject comes last. The kind you have to read
|
|
13
|
+
backwards. The kind that makes you go:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
send_email unless already_sent?
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Cool. So do we send the email, or do we not? Let me just... hold that `send_email`
|
|
20
|
+
in working memory while I parse `unless`... flip the boolean in my head...
|
|
21
|
+
re-check the variable name... oh. OH. We send the email when `already_sent?` is
|
|
22
|
+
`false`. Got it. Only took 600ms and a small cortisol spike.
|
|
23
|
+
|
|
24
|
+
And then there is:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
destroy! if admin? && confirmed?
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This one is great. Your eye lands on `destroy!`. Your adrenal gland fires.
|
|
31
|
+
Your hand moves toward the keyboard. Then you read `if admin? && confirmed?`
|
|
32
|
+
and you relax. But the damage is done. Your heart rate is up. You have aged
|
|
33
|
+
slightly. The code has won.
|
|
34
|
+
|
|
35
|
+
This gem fights back.
|
|
36
|
+
|
|
37
|
+
## What It Does
|
|
38
|
+
|
|
39
|
+
### `Style/NoUnless`
|
|
40
|
+
|
|
41
|
+
Bans `unless` in all its forms. Replaces it with a negated `if`.
|
|
42
|
+
|
|
43
|
+
`unless` is syntactic sugar. Sugar is fine in coffee. Sugar is not fine when
|
|
44
|
+
you are trying to understand whether a background job is going to run or not
|
|
45
|
+
at 11pm during an incident.
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
# Before (your colleagues wrote this)
|
|
49
|
+
unless user.banned?
|
|
50
|
+
grant_access
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# After (the cop wrote this)
|
|
54
|
+
if !user.banned?
|
|
55
|
+
grant_access
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Yes, `!condition` looks slightly more aggressive. It is slightly more
|
|
60
|
+
aggressive. That is the point. You are negating something. Own it.
|
|
61
|
+
|
|
62
|
+
When the condition is compound, the parens come with it:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
# Before (your colleagues wrote this)
|
|
66
|
+
unless user.banned? && account.locked?
|
|
67
|
+
grant_access
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# After (the cop wrote this)
|
|
71
|
+
if !(user.banned? && account.locked?)
|
|
72
|
+
grant_access
|
|
73
|
+
end
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
# Before (someone thought this was clever)
|
|
78
|
+
render_page unless maintenance_mode?
|
|
79
|
+
|
|
80
|
+
# After
|
|
81
|
+
if !maintenance_mode?
|
|
82
|
+
render_page
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**"But `unless foo` is so readable!"**
|
|
87
|
+
|
|
88
|
+
It is readable the first time. The fourteenth time you see it in a file, your
|
|
89
|
+
brain has learned to pattern-match it and skip the inversion step — which means
|
|
90
|
+
you are now *silently wrong* about what the code does until you stop and
|
|
91
|
+
actually re-read it. Congratulations on training yourself to make subtle errors
|
|
92
|
+
efficiently.
|
|
93
|
+
|
|
94
|
+
### `Style/IfUnlessModifierMultiline`
|
|
95
|
+
|
|
96
|
+
Bans modifier `if`. Expands it to a normal `if` block.
|
|
97
|
+
|
|
98
|
+
Modifier `if` is a style borrowed from Perl. If you are taking style advice
|
|
99
|
+
from Perl, please close this README and reconsider your choices.
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
# Before (you thought you were saving lines)
|
|
103
|
+
do_the_thing if condition_is_met?
|
|
104
|
+
|
|
105
|
+
# After (you are saving brain cells instead)
|
|
106
|
+
if condition_is_met?
|
|
107
|
+
do_the_thing
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The argument for modifier `if` is always "it's more concise." This is true.
|
|
112
|
+
It is also more concise to write variable names as single letters, skip
|
|
113
|
+
comments entirely, and put everything on one line. Conciseness is not the
|
|
114
|
+
goal. Clarity is the goal.
|
|
115
|
+
|
|
116
|
+
When you write `do_thing if bar`, a reader must:
|
|
117
|
+
|
|
118
|
+
1. Parse `do_thing`
|
|
119
|
+
2. Begin forming the intention "ok, we do the thing"
|
|
120
|
+
3. Hit `if`
|
|
121
|
+
4. Backtrack
|
|
122
|
+
5. Parse `bar`
|
|
123
|
+
6. Decide whether to do the thing
|
|
124
|
+
7. Wonder why this person hates them
|
|
125
|
+
|
|
126
|
+
When you write `if bar` on its own line, a reader:
|
|
127
|
+
|
|
128
|
+
1. Parses `if bar`
|
|
129
|
+
2. Decides whether to enter the block
|
|
130
|
+
3. Does or does not enter the block
|
|
131
|
+
4. Goes home at a reasonable hour
|
|
132
|
+
|
|
133
|
+
Note: modifier `unless` (`do_thing unless bar`) is also banned, but by
|
|
134
|
+
`Style/NoUnless`. It is doubly bad — it is both backwards *and* inverted — and
|
|
135
|
+
it gets its own cop because it deserves special attention.
|
|
136
|
+
|
|
137
|
+
## Installation
|
|
138
|
+
|
|
139
|
+
Add this to your `Gemfile`:
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
gem "rubocop-sane_conditionals", require: false
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Then add this to your `.rubocop.yml`:
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
require:
|
|
149
|
+
- rubocop-sane_conditionals
|
|
150
|
+
|
|
151
|
+
Style/NoUnless:
|
|
152
|
+
Enabled: true
|
|
153
|
+
|
|
154
|
+
Style/IfUnlessModifierMultiline:
|
|
155
|
+
Enabled: true
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Run `bundle exec rubocop --autocorrect` and let the gem fix your codebase
|
|
159
|
+
while you make tea and quietly reflect on past decisions.
|
|
160
|
+
|
|
161
|
+
## FAQ
|
|
162
|
+
|
|
163
|
+
**Q: Isn't `unless` idiomatic Ruby?**
|
|
164
|
+
|
|
165
|
+
A: Yes. So is `BEGIN`, `$PROGRAM_NAME`, and the flip-flop operator. Idiomatic
|
|
166
|
+
does not mean good. It means common. A lot of common things are bad.
|
|
167
|
+
|
|
168
|
+
**Q: My team loves `unless`. They will push back.**
|
|
169
|
+
|
|
170
|
+
A: Show them this gem. If they still push back, that is useful information
|
|
171
|
+
about your team.
|
|
172
|
+
|
|
173
|
+
**Q: What about `if !foo`? Isn't `unless foo` cleaner?**
|
|
174
|
+
|
|
175
|
+
A: No. `if !foo` is a complete, unambiguous statement. `unless foo` requires
|
|
176
|
+
the reader to know that `unless` means `if not`, apply that transformation,
|
|
177
|
+
and then continue. This is one extra step. Over a long career, these extra
|
|
178
|
+
steps add up to a measurable amount of time you could have spent doing
|
|
179
|
+
something else.
|
|
180
|
+
|
|
181
|
+
**Q: Why does `unless foo && bar` become `if !(foo && bar)` instead of `if !foo && !bar`?**
|
|
182
|
+
|
|
183
|
+
A: Because that would be wrong. De Morgan's law says `!(A && B)` equals
|
|
184
|
+
`!A || !B`, not `!A && !B`. The cop is not here to do your boolean algebra
|
|
185
|
+
for you. It is here to make the negation visible. The parens make it clear
|
|
186
|
+
that the whole compound condition is being negated, which is exactly what
|
|
187
|
+
`unless` was hiding.
|
|
188
|
+
|
|
189
|
+
**Q: You seem angry about this.**
|
|
190
|
+
|
|
191
|
+
A: I am not angry. I am tired. There is a difference. One of them requires
|
|
192
|
+
backtracking to determine the meaning.
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT. Use it. Improve it. Inflict it on your colleagues.
|
data/config/default.yml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
Style/NoUnless:
|
|
3
|
+
Description: >-
|
|
4
|
+
Use negated `if` instead of `unless`. Unless is cute. Unless is also
|
|
5
|
+
a brain trap. Please stop.
|
|
6
|
+
Enabled: true
|
|
7
|
+
VersionAdded: "0.1"
|
|
8
|
+
AutoCorrect: true
|
|
9
|
+
|
|
10
|
+
Style/IfUnlessModifierMultiline:
|
|
11
|
+
Description: >-
|
|
12
|
+
Expand modifier `if` to multi-line form. Your code is not a tweet.
|
|
13
|
+
You have all the lines you want.
|
|
14
|
+
Enabled: true
|
|
15
|
+
VersionAdded: "0.1"
|
|
16
|
+
AutoCorrect: true
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Disallows modifier `if` (i.e. `foo if bar`) and converts it to a
|
|
7
|
+
# standard multi-line `if` block.
|
|
8
|
+
#
|
|
9
|
+
# Modifier `if` reads right-to-left: your eye hits `foo`, your brain
|
|
10
|
+
# starts processing "ok, we do foo", then hits `if bar` and has to
|
|
11
|
+
# backtrack. Congratulations, you have implemented a for-loop in a
|
|
12
|
+
# human brain. It will crash.
|
|
13
|
+
#
|
|
14
|
+
# Note: modifier `unless` is handled separately by `Style/NoUnless`.
|
|
15
|
+
# Don't worry, it's also banned.
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# # bad
|
|
19
|
+
# do_something if condition
|
|
20
|
+
#
|
|
21
|
+
# # good
|
|
22
|
+
# if condition
|
|
23
|
+
# do_something
|
|
24
|
+
# end
|
|
25
|
+
class IfUnlessModifierMultiline < Base
|
|
26
|
+
extend AutoCorrector
|
|
27
|
+
|
|
28
|
+
MSG = 'Convert modifier `if` to multi-line form. Reading left-to-right ' \
|
|
29
|
+
'is a feature, not a suggestion.'
|
|
30
|
+
|
|
31
|
+
def on_if(node)
|
|
32
|
+
if !node.modifier_form?
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if node.unless?
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
add_offense(node) do |corrector|
|
|
41
|
+
autocorrect(corrector, node)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def autocorrect(corrector, node)
|
|
48
|
+
condition = node.condition.source
|
|
49
|
+
body = node.body.source
|
|
50
|
+
indentation = ' ' * node.loc.column
|
|
51
|
+
|
|
52
|
+
replacement = <<~RUBY.chomp
|
|
53
|
+
if #{condition}
|
|
54
|
+
#{indentation} #{body}
|
|
55
|
+
#{indentation}end
|
|
56
|
+
RUBY
|
|
57
|
+
|
|
58
|
+
corrector.replace(node, replacement)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Disallows `unless` in all its forms and replaces it with a negated `if`.
|
|
7
|
+
#
|
|
8
|
+
# `unless` is syntactic sugar that requires the reader to mentally invert
|
|
9
|
+
# the condition. This is fine if your reader is a compiler. Your reader is
|
|
10
|
+
# not a compiler. Your reader is a tired human at 4pm on a Friday who just
|
|
11
|
+
# wants to know whether the code runs the thing or does not run the thing.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# # bad
|
|
15
|
+
# unless foo
|
|
16
|
+
# bar
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# # good
|
|
20
|
+
# if !foo
|
|
21
|
+
# bar
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# # bad
|
|
25
|
+
# unless foo && bar
|
|
26
|
+
# baz
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# # good
|
|
30
|
+
# if !(foo && bar)
|
|
31
|
+
# baz
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# # bad
|
|
35
|
+
# bar unless foo
|
|
36
|
+
#
|
|
37
|
+
# # good
|
|
38
|
+
# if !foo
|
|
39
|
+
# bar
|
|
40
|
+
# end
|
|
41
|
+
class NoUnless < Base
|
|
42
|
+
extend AutoCorrector
|
|
43
|
+
|
|
44
|
+
MSG = 'Use negated `if` instead of `unless`. Your future self will thank you. ' \
|
|
45
|
+
'Your colleagues will thank you. English teachers need not apply.'
|
|
46
|
+
|
|
47
|
+
def on_if(node)
|
|
48
|
+
if !node.unless?
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
add_offense(node) do |corrector|
|
|
53
|
+
autocorrect(corrector, node)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def autocorrect(corrector, node)
|
|
60
|
+
condition_node = node.condition
|
|
61
|
+
condition_source = condition_node.source
|
|
62
|
+
|
|
63
|
+
negated_condition = if requires_parens?(condition_node)
|
|
64
|
+
"!(#{condition_source})"
|
|
65
|
+
else
|
|
66
|
+
"!#{condition_source}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if node.modifier_form?
|
|
70
|
+
autocorrect_modifier(corrector, node, negated_condition)
|
|
71
|
+
else
|
|
72
|
+
autocorrect_multiline(corrector, node, negated_condition)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def requires_parens?(condition_node)
|
|
77
|
+
condition_node.and_type? || condition_node.or_type?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def autocorrect_modifier(corrector, node, negated_condition)
|
|
81
|
+
body = node.body.source
|
|
82
|
+
indentation = ' ' * node.loc.column
|
|
83
|
+
replacement = "if #{negated_condition}\n#{indentation} #{body}\n#{indentation}end"
|
|
84
|
+
corrector.replace(node, replacement)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def autocorrect_multiline(corrector, node, negated_condition)
|
|
88
|
+
body_source = node.body.source
|
|
89
|
+
indentation = ' ' * node.loc.column
|
|
90
|
+
|
|
91
|
+
replacement = if node.else_branch
|
|
92
|
+
else_body = node.else_branch.source
|
|
93
|
+
<<~RUBY.chomp
|
|
94
|
+
if #{negated_condition}
|
|
95
|
+
#{indentation} #{body_source}
|
|
96
|
+
#{indentation}else
|
|
97
|
+
#{indentation} #{else_body}
|
|
98
|
+
#{indentation}end
|
|
99
|
+
RUBY
|
|
100
|
+
else
|
|
101
|
+
<<~RUBY.chomp
|
|
102
|
+
if #{negated_condition}
|
|
103
|
+
#{indentation} #{body_source}
|
|
104
|
+
#{indentation}end
|
|
105
|
+
RUBY
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
corrector.replace(node, replacement)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rubocop'
|
|
4
|
+
require_relative 'rubocop-sane_conditionals/version'
|
|
5
|
+
require_relative 'rubocop/cop/style/no_unless'
|
|
6
|
+
require_relative 'rubocop/cop/style/if_unless_modifier_multiline'
|
|
7
|
+
|
|
8
|
+
if defined?(Rake)
|
|
9
|
+
RuboCop::RakeTask
|
|
10
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rubocop-sane_conditionals
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Federico
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-11 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rubocop
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.0'
|
|
27
|
+
description: |
|
|
28
|
+
Enforces conditional style that does not require you to hold the entire
|
|
29
|
+
sentence in working memory while your brain tries to figure out what
|
|
30
|
+
"do_thing if !foo unless bar" means. It means you hate your colleagues.
|
|
31
|
+
email:
|
|
32
|
+
executables: []
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- LICENSE.txt
|
|
37
|
+
- README.md
|
|
38
|
+
- config/default.yml
|
|
39
|
+
- lib/rubocop-sane_conditionals.rb
|
|
40
|
+
- lib/rubocop-sane_conditionals/version.rb
|
|
41
|
+
- lib/rubocop/cop/style/if_unless_modifier_multiline.rb
|
|
42
|
+
- lib/rubocop/cop/style/no_unless.rb
|
|
43
|
+
homepage: https://github.com/jmfederico/rubocop-sane_conditionals
|
|
44
|
+
licenses:
|
|
45
|
+
- MIT
|
|
46
|
+
metadata:
|
|
47
|
+
rubygems_mfa_required: 'true'
|
|
48
|
+
post_install_message:
|
|
49
|
+
rdoc_options: []
|
|
50
|
+
require_paths:
|
|
51
|
+
- lib
|
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '3.0'
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
requirements: []
|
|
63
|
+
rubygems_version: 3.4.10
|
|
64
|
+
signing_key:
|
|
65
|
+
specification_version: 4
|
|
66
|
+
summary: RuboCop cops for humans who can read.
|
|
67
|
+
test_files: []
|