
TL;DR
- Add trailing commas everywhere
- Use consistent indentation
- Disallow whitespace for formatting/aligning
- Consider leading dot syntax, YMMW
The story
For me it all started with theannouncement of version 1.0 release of thestandard
gem sometime back in March, 2021. Here was a library by the accomplished @searls that pre-configured Rubocop for the benefit of all mankind, and I was eager to imbibe. Perusing the readme, I immediately noticed the "Leading dots on multi-line method chains" point and opened thethread that lead to that decision.
The first argument for adopting the particular approach was that it would reduce the lines highlighted by git as changed if a new call was added to the end of a chain:
# trailing dot, noisyupcase.chars.-drop(1)+drop(1).+reverse# leading dot, quiet.upcase.chars.drop(1)+.reverse
I had never really appreciated how last lines in chains like this, and, similarly, last lines in hashes and arrays are made different by the style used.
I had been burned by the occasional missing comma in a hash or array, but always figured aesthetics demand no comma at the end; now there was a good argument, even two, for breaking with aesthetics and instead adopting an approach that favours consistency and results in fewer mistakes and less noise!
# no final comma, inconsistent, very noisy{name:"Bob",faves:[:apples,-:beer+:beer,+:candy-]+],+dislikes:[:radishes]}# final comma, very quiet{name:"Bob",faves:[:apples,:beer,+:candy,],+dislikes:[:radishes],}
The same goes for multiline argument lists. Basically in any multiline list where individual entries would be comma-separated, keep adding trailing comma.
data.dig(:properties,0,:rooms,-1,-:size+:size,+:square_meters)data.dig(:properties,0,:rooms,-1,:size,+:square_meters,)
Now I was sold. Looking to minimise diff noise was a valid and powerful way to drive style decisions!
I looked through some of my recent commits to see what else produces noise and discovered a surprising fact - whitespace was the number one culprit for noise. It results from whitespace being used for alignment, thus tying several lines together, and sometimes change in one line demands changes in all. Extreme noise ensues.
An example with often-seen style where arbitrary leading whitespace is allowed (this sometimes even produces odd-numbered space indent, yuck!). Only the class name is changed, but it's impossible to easily tell. Good style setup should constrain any line to beingat most one level deeper than the previous line.
-SomeClass.where(vip:true)-.where(local:false)-.where(name:"Jack",-title:"mr",)+SomeOtherClass.where(vip:true)+.where(local:false)+.where(name:"Jack",+title:"mr",)# contrast with consistent indentation approach-SomeClass+SomeOtherClass.where(vip:true).where(local:false).where(name:"Jack",title:"mr",)
An example with often-seen arbitrary options hash alignment. Having consistent indentation and requiring that options hash starts on its own line also improves readability as to where positional args end and kwargs/options begin.
FactoryBot.build_stubbed(-:some_model,:full_build,vip:true-best:true+:some_model,:no_build,vip:true+best:true)# contrast with consistent indentationFactoryBot.build_stubbed(-:some_model,:full_build,+:some_model,:no_build,vip:truebest:true)
And an example with aligned hashes, what got changed? (hint, a new longest key appeared)
{-the_longest_key:"value",-middle_key:"value",-mini_key:"value",+the_longeest_key:"value",+the_longest_key:"value",+middle_key:"value",+mini_key:"value",}# contrast with disallowed whitespace for alignment{+the_longeest_key:"value",the_longest_key:"value",middle_key:"value",mini_key:"value",}
The cops
This is not an exhaustive list, created with Rubocop v1.22 in mind. The settings provided should reduce whitespace abuses and add commas everywhere.
Layout/ArgumentAlignment: EnforcedStyle: with_fixed_indentationLayout/ArrayAlignment: EnforcedStyle: with_fixed_indentationLayout/ExtraSpacing: Enabled: true AllowForAlignment: false AllowBeforeTrailingComments: true ForceEqualSignAlignment: falseLayout/ParameterAlignment: EnforcedStyle: with_fixed_indentationLayout/SpaceAroundOperators: AllowForAlignment: false EnforcedStyleForExponentOperator: no_space Style/TrailingCommaInArguments: EnforcedStyleForMultiline: consistent_commaStyle/TrailingCommaInArrayLiteral: EnforcedStyleForMultiline: consistent_commaStyle/TrailingCommaInHashLiteral: EnforcedStyleForMultiline: consistent_commaLayout/DotPosition: EnforcedStyle: leading
Addendum
You may also look atLayout/First*
cops. Using them withEnforcedStyle: consistent
complements alignment cops.
# with only alignmentsome_method(:arg1,:arg2,:arg3,)other_method(arg,key1: :value1,key2: :value2,)# with First* copssome_method(:arg1,:arg2,:arg3,)other_method(arg,key1: :value1,key2: :value2,)
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse