Educate RuboCop, try out rubocop.yml which prioritize the speed to the rules

  • Post author:
  • Post last modified:2020-11-25
  • Post category:Code Review
  • Reading time:9 mins read

Hello there. I assume some of you fond RuboCop is too fussy about the rules. We have developed rubocop.yml files that prioritize developing speed to the rules.
You can have a try!
This is about optimization and configuration of Rubocop which focuses on “finding codes which lead to the bug”.

By place the rubocop.yml file in the top of the directory of repository, SideCI will follow the configuration for the verification and provide you comments. It would be good for those who use just RuboCop rather than SideCI.

Table Of Contents

  • Use RuboCop effectively and suppress bugs
  • Enable Lint cops by default
  • Lintcops to be disabled exceptionally
  • Disable Style cops by default
  • Style cops to be enabled exceptionally
  • Other cops
  • .rubocop.yml with above understanding
  • “I still have many violations!” when you’d like to perform only simple verification even more effectively
  • Summary

Use RuboCop effectively and suppress bugs

「RuboCop」 is a static analytical tool for Ruby.

Although RuboCop is assumed for a coding verification tool, you can use it as “a tool that finds codes which lead to the bug”.

But, you will have many violations if you use RuboCop for Rails application development with default configuration.

With such conditions, the violation which will be a bug won’t be recognized either.

Here, we shall configure .rubocop.yml to enable only the cop which finds the violation to be a bug.

Enable Lint cops by default

The term “cop” is the rules to verify the codes in RuboCop.

Lint cops are the one which detects the codes which may cause bugs.

In README of RuboCop, it describes that disabling Lint cops is a ”bad idea”.

For example, below Ruby code has a bug, but even a programmer many not recognize it immediately.

def raises_sometimes(value)
if value == 1
raise '1 is bad value!'
elif value == 2
raise '2 is bad value, too!'
end
end

Lint cops can indirectly detect the place that may have bugs.

You can verify only Lint cop by -l/--lint option (surely you can also verify without this option).

I execute here.

rubocop test.rb --lint
Inspecting 1 file
W
Offenses:
test.rb:4:5: W: Lint/UnreachableCode: Unreachable code detected.
elif value == 2
^^^^^^^^^^^^^^^
1 file inspected, 1 offense detected

Since elif is not in ruby(it should be elseif), the rows after raise is detected as UnreachableCode(unreachable).
In this example, since it is fine for the syntax of Ruby, it can’t be detected by ruby -c.
Since it may detect such violations, we shall enable Lint cops.

Lintcops to be disabled exceptionally

Following 2 cops are assumed that exceptionally won’t contribute the detection of bugs which influence immediately.

Lint/DeprecatedClassMethods

It detects depreciated methods such as File.exists?.
Although it is better not to use deprecated methods, it doesn’t cause bugs immediately.

Lint/StringConversionInInterpolation

It detects the place which is calling extra #to_s.
Again, it is better not to call unnecessary methods, but it doesn’t cause bugs immediately
For above 2 cops, we shall disable in .rubocop.yml file of this entry exceptionally.

Disable Style cops by default

As mentioned earlier, you will have many violations if you use RuboCop for Rails application development with default configuration..
Most of the case the cop for Style doesn’t contribute to detect bugs, you can disable it.

Style cops to be enabled exceptionally

For exceptional cases, the following 3 Style cops may contribute to detect the bugs.

Style/AndOr

Cop that recommends && over and, and || over or. and and && have a different binding priority.
Since this is a bit complicated, I explain by using this easy-to-understand description article.

if true and false
puts "1: true"
else
puts "1: false"
end
#=> 1: false

The code is not so surprising, but it produces a surprising result when combined with (=).

true_and_false = true and false
if true_and_false
puts "2: true"
else
puts "2: false"
end
#=> 2: true

To prevent this bug, it is useful to use && and ||.

Style/CaseEquality
A cop that restricts the usage of ===.
 === is used in the Case format and it might operate differently as expected so this cop will be of use.

Style/GlobalVars
A cop that restricts the use of global variables.
Global variable might operate differently as expected.
Those 3 Style cops mentioned above to be enabled in the .rubocop.yml of this entry.

Other cops

Other cops follow the below.

  • Disable Metrics cops, since those are more related to clean codes.
    *Enable Performance cops, since the number of cops is less and it may detect the issue of efficiency.
  • Enable Rails cops, although some are related to Style but the number is less and it detects the date and time(Rails/Date andRails/TimeZone) items.

.rubocop.yml with above understanding

With above understanding, now the .rubocop.yml is as shown in below.

Download: rubocop.yml

Since most of Style cops are disabled, you will have much less violations.
Please rename the file to .rubocop.yml when downloading the file from the link above.

AllCops:
Exclude:
- 'vendor/**/*'
RunRailsCops: true
DisplayCopNames: true
Style/AccessModifierIndentation:
Enabled: false
Style/AccessorMethodName:
Enabled: false
Style/Alias:
Enabled: false
Style/AlignArray:
Enabled: false
Style/AlignHash:
Enabled: false
Style/AlignParameters:
Enabled: false
Style/AndOr:
Enabled: true
Style/ArrayJoin:
Enabled: false
Style/AsciiComments:
Enabled: false
Style/AsciiIdentifiers:
Enabled: false
Style/Attr:
Enabled: false
Style/BeginBlock:
Enabled: false
Style/BarePercentLiterals:
Enabled: false
Style/BlockComments:
Enabled: false
Style/BlockEndNewline:
Enabled: false
Style/Blocks:
Enabled: false
Style/BracesAroundHashParameters:
Enabled: false
Style/CaseEquality:
Enabled: true
Style/CaseIndentation:
Enabled: false
Style/CharacterLiteral:
Enabled: false
Style/ClassAndModuleCamelCase:
Enabled: false
Style/ClassAndModuleChildren:
Enabled: false
Style/ClassCheck:
Enabled: false
Style/ClassMethods:
Enabled: false
Style/ClassVars:
Enabled: false
Style/ColonMethodCall:
Enabled: false
Style/CommentAnnotation:
Enabled: false
Style/CommentIndentation:
Enabled: false
Style/ConstantName:
Enabled: false
Style/DefWithParentheses:
Enabled: false
Style/DeprecatedHashMethods:
Enabled: false
Style/Documentation:
Enabled: false
Style/DotPosition:
Enabled: false
Style/DoubleNegation:
Enabled: false
Style/EachWithObject:
Enabled: false
Style/ElseAlignment:
Enabled: false
Style/EmptyElse:
Enabled: false
Style/EmptyLineBetweenDefs:
Enabled: false
Style/EmptyLines:
Enabled: false
Style/EmptyLinesAroundAccessModifier:
Enabled: false
Style/EmptyLinesAroundBlockBody:
Enabled: false
Style/EmptyLinesAroundClassBody:
Enabled: false
Style/EmptyLinesAroundModuleBody:
Enabled: false
Style/EmptyLinesAroundMethodBody:
Enabled: false
Style/EmptyLiteral:
Enabled: false
Style/EndBlock:
Enabled: false
Style/EndOfLine:
Enabled: false
Style/EvenOdd:
Enabled: false
Style/FileName:
Enabled: false
Style/FirstParameterIndentation:
Enabled: false
Style/FlipFlop:
Enabled: false
Style/For:
Enabled: false
Style/FormatString:
Enabled: false
Style/GlobalVars:
Enabled: true
Style/GuardClause:
Enabled: false
Style/HashSyntax:
Enabled: false
Style/IfUnlessModifier:
Enabled: false
Style/IfWithSemicolon:
Enabled: false
Style/IndentationConsistency:
Enabled: false
Style/IndentationWidth:
Enabled: false
Style/IndentArray:
Enabled: false
Style/IndentHash:
Enabled: false
Style/InfiniteLoop:
Enabled: false
Style/Lambda:
Enabled: false
Style/LambdaCall:
Enabled: false
Style/LeadingCommentSpace:
Enabled: false
Style/LineEndConcatenation:
Enabled: false
Style/MethodCallParentheses:
Enabled: false
Style/MethodDefParentheses:
Enabled: false
Style/MethodName:
Enabled: false
Style/ModuleFunction:
Enabled: false
Style/MultilineBlockChain:
Enabled: false
Style/MultilineBlockLayout:
Enabled: false
Style/MultilineIfThen:
Enabled: false
Style/MultilineOperationIndentation:
Enabled: false
Style/MultilineTernaryOperator:
Enabled: false
Style/NegatedIf:
Enabled: false
Style/NegatedWhile:
Enabled: false
Style/NestedTernaryOperator:
Enabled: false
Style/Next:
Enabled: false
Style/NilComparison:
Enabled: false
Style/NonNilCheck:
Enabled: false
Style/Not:
Enabled: false
Style/NumericLiterals:
Enabled: false
Style/OneLineConditional:
Enabled: false
Style/OpMethod:
Enabled: false
Style/ParenthesesAroundCondition:
Enabled: false
Style/PercentLiteralDelimiters:
Enabled: false
Style/PercentQLiterals:
Enabled: false
Style/PerlBackrefs:
Enabled: false
Style/PredicateName:
Enabled: false
Style/Proc:
Enabled: false
Style/RaiseArgs:
Enabled: false
Style/RedundantBegin:
Enabled: false
Style/RedundantException:
Enabled: false
Style/RedundantReturn:
Enabled: false
Style/RedundantSelf:
Enabled: false
Style/RegexpLiteral:
Enabled: false
Style/RescueModifier:
Enabled: false
Style/SelfAssignment:
Enabled: false
Style/Semicolon:
Enabled: false
Style/SignalException:
Enabled: false
Style/SingleLineBlockParams:
Enabled: false
Style/SingleLineMethods:
Enabled: false
Style/SingleSpaceBeforeFirstArg:
Enabled: false
Style/SpaceAfterColon:
Enabled: false
Style/SpaceAfterComma:
Enabled: false
Style/SpaceAfterControlKeyword:
Enabled: false
Style/SpaceAfterMethodName:
Enabled: false
Style/SpaceAfterNot:
Enabled: false
Style/SpaceAfterSemicolon:
Enabled: false
Style/SpaceBeforeBlockBraces:
Enabled: false
Style/SpaceBeforeComma:
Enabled: false
Style/SpaceBeforeComment:
Enabled: false
Style/SpaceBeforeSemicolon:
Enabled: false
Style/SpaceInsideBlockBraces:
Enabled: false
Style/SpaceAroundBlockParameters:
Enabled: false
Style/SpaceAroundEqualsInParameterDefault:
Enabled: false
Style/SpaceAroundOperators:
Enabled: false
Style/SpaceBeforeModifierKeyword:
Enabled: false
Style/SpaceInsideBrackets:
Enabled: false
Style/SpaceInsideHashLiteralBraces:
Enabled: false
Style/SpaceInsideParens:
Enabled: false
Style/SpaceInsideRangeLiteral:
Enabled: false
Style/SpecialGlobalVars:
Enabled: false
Style/StringLiterals:
Enabled: false
Style/StringLiteralsInInterpolation:
Enabled: false
Style/StructInheritance:
Enabled: false
Style/SymbolProc:
Enabled: false
Style/Tab:
Enabled: false
Style/TrailingBlankLines:
Enabled: false
Style/TrailingComma:
Enabled: false
Style/TrailingWhitespace:
Enabled: false
Style/TrivialAccessors:
Enabled: false
Style/UnlessElse:
Enabled: false
Style/UnneededCapitalW:
Enabled: false
Style/UnneededPercentQ:
Enabled: false
Style/UnneededPercentX:
Enabled: false
Style/VariableInterpolation:
Enabled: false
Style/VariableName:
Enabled: false
Style/WhenThen:
Enabled: false
Style/WhileUntilDo:
Enabled: false
Style/WhileUntilModifier:
Enabled: false
Style/WordArray:
Enabled: false
Lint/DeprecatedClassMethods:
Enabled: false
Lint/StringConversionInInterpolation:
Enabled: false
Metrics/AbcSize:
Enabled: false
Metrics/BlockNesting:
Enabled: false
Metrics/ClassLength:
Enabled: false
Metrics/CyclomaticComplexity:
Enabled: false
Metrics/LineLength:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/ParameterLists:
Enabled: false
Metrics/PerceivedComplexity:
Enabled: false

“I still have many violations!” when you’d like to perform only simple verification even more effectively

Based on the above .rubocop.yml rules, when execute rubocop for any 8 Rails projects (the number of stars are more than 300 and committed recently) which are published in github, the number of violation got less around 10%-50% by comparing with the default settings.
But, for large scale Rails applications, the number of violations are still more than 1000 and hard to check all.
We have selected below 4 cops which are simple yet detect the bugs well. These will help you to verify easily especially for the beginning.

Lint/Debugger
It detects whether methods for debug (p/pp/puts/print) are still remaining.

Lint/DuplicateMethods
It detects the locations which have duplicated method definition in the same class.

Lint/UnreachableCode
It detects unreachable locations .

Lint/Void
It detects the locations which have only operators, variables or literals and have done nothing.
To execute only above 4 cops, you can execute below command without having .rubocop.yml file.

$ rubocop — only Lint/Debugger,Lint/DuplicateMethods,Lint/UnreachableCode,Lint/Void

Followings are the result of executing this command to 8 Rails projects.

sample result

There are areas that are fine without fixing the violations, but it detected that there are 4 out of 8 Rails projects which require some fixing.
In case the developing Rails application is huge and difficult to fix or check all detected violations, by fixing those 4 violations lead to find bugs.

Summary

How did you find this?
In this entry, we have seen when Lint cop is useful and that importance, the example of .rubocop.yml especially important Lint cop.
When actually using RuboCop, you will need to determine enable/disable for respective cops.
For those who want to try out rubocop but have never done, since this judgment is already difficult, I sincerely suggest you to start with performing this .rubocop.yml and the last 4 cops.

More articles about RuboCop


For more information about Sider, please go to our website.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.