Skip to content
This repository has been archived by the owner on Jan 16, 2025. It is now read-only.

Defining rubocop style #33219

Closed
wants to merge 1 commit into from
Closed

Conversation

lloeki
Copy link
Contributor

@lloeki lloeki commented Oct 16, 2014

This PR initially contains an empty .rubocop.yml and a freshly-generated .rubocop-todo.yml at the root.

In this PR we can discuss about each cop (disabling, enabling as is or setting parameters and variants) possibly even straight in the todo file code. I'm not going to be picky, if a cop does not make sense, it gets disabled: no need to be too stringent as it would encourage bad code.

For each decision that is taken, the selected cop configuration is written to .rubocop.yml and removed from the todo file, updating the PR branch.

Once the todo file is empty, it gets removed and we have our target style documented in rubocop.yml. At this point the goal is not to have zero violations but to have a file that will support us into making code more conformant and uniform in later PRs either automatically with autocorrect or on a case by case basis, according to homebrew's management team policies and preferences.

From then on anyway, the mere presence of the file will entice people having rubocop installed and creating new files or edit existing files fix those files one by one as time goes by.

# Offense count: 32747
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/StringLiterals:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: This one has the most offenses. I seemed to notice the homebrew style is to prefer double quotes in most cases, except when too much escape sequences come in. This can be set up by using EnforcedStyle: double_quotes instead of the default.

@lloeki
Copy link
Contributor Author

lloeki commented Oct 16, 2014

Default rubocop configuration can be seen here, including possible alternative settings for each cop.

@MikeMcQuaid
Copy link
Member

We're using the Ruby Style Guide in case that helps at all.

@lloeki
Copy link
Contributor Author

lloeki commented Oct 20, 2014

Most of Rubocop defaults follow that guide already.

It seems Library/Homebrew/cmd/doctor.rb can't decide whether it's indented or not inside the Check class, possibly to save two spaces given its length. I suggest indenting everything consistently, especially since two spaces are not worth it.

@@ -82,7 +82,7 @@ class ExampleFormula < Formula
# 64bit binary/library). TODO: better explain what this means for PPC.
option :universal
option "with-spam", "The description goes here without a dot at the end"
option "with-qt", "Text here overwrites the autogenerated one from `depends_on "qt"`"
option "with-qt", 'Text here overwrites the autogenerated one from `depends_on "qt"`'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed a nudge here, else the file was unparsable.

@lloeki
Copy link
Contributor Author

lloeki commented Oct 20, 2014

After enforcing double quotes, 19k violations remain on that one. Many of them are C-style single-char strings.


# Offense count: 54
# Cop supports --auto-correct.
Style/CharacterLiteral:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of them are in the same file. Rubocop recommends using string delimiters instead (I didn't even know about this syntax)

@jacknagel
Copy link
Contributor

It seems Library/Homebrew/cmd/doctor.rb can't decide whether it's indented or not inside the Check class, possibly to save two spaces given its length. I suggest indenting everything consistently, especially since two spaces are not worth it.

See https://github.com/Homebrew/homebrew/blob/290934c096c25482a89500c7ce1c95c7043e434c/Library/Homebrew/cmd/doctor.rb#L73; most of the code in that file predates the Checks class, so it wasn't reindented to avoid churn.

@lloeki lloeki force-pushed the define_rubocop_style branch from 08365a7 to b805c16 Compare October 21, 2014 09:24
@DomT4 DomT4 mentioned this pull request Nov 19, 2014
@lloeki
Copy link
Contributor Author

lloeki commented Dec 3, 2014

Just a quick note that I'm still working on this, but I have a few deadlines not to miss.

@MikeMcQuaid
Copy link
Member

Just FYI: I'm wanting to integrate something like this into our CI for new formulae/files so I'd be interested in pushing whatever's ready.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 28, 2014

OK, turns out I'll have some spare time tomorrow, so I'll dive into this again and push some stuff for you.

@jacknagel
Copy link
Contributor

One thing that might help move this along quicker is if we only enable it on the formula directory for now. Is that something that can be done?

We have a pretty good idea of what formula style should look like, but the style guidelines for the "core" may differ somewhat, as it is more like actual application code than the domain-specific code in formulae.

Perhaps we can enable it for formulae now and worry about core later?

@MikeMcQuaid
Copy link
Member

Yeh, I'm planning on setting it up so, initially at least, we're running it on individual (new) files rather than all of them.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 29, 2014

We have a pretty good idea of what formula style should look like, but the style guidelines for the "core" may differ somewhat, as it is more like actual application code than the domain-specific code in formulae.

@jacknagel that's totally possible to set up, we just need to have one .rubocop.yml file in Library/Formula and one in Library/Homebrew. If needed, they could inherit_from a common one in Library or at the root (like as of now) for common rules.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 29, 2014

I noticed this perl backref pattern:

    version_info = `#{emacs_binary} --version`
    version_info =~ /GNU Emacs (\d+)\./
    major = $1

There are only a few occurrences in formulas (vs ~90 in the core) and some of them may be dangerous to the untrained eye, or its intrinsic untested branching quickly overlooked. It could be useful to enforce the rule on Formula.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 30, 2014

Please note that due to a rubocop bug it may be needed to write # rubocop:disable before __END__, or to globally disable offending cops (currently Style/TrailingWhitespace and Style/Tab).

@lloeki
Copy link
Contributor Author

lloeki commented Dec 30, 2014

Need your feedback on Style/TrailingComma. It's about this:

x = [
   "foo",
   "bar"
]
# vs
x = [
   "foo",
   "bar",     # final comma presence makes things easy to reorder, insert or delete
]

See gcc formula for a concrete example.

Ruby style guide is mute on that point, and currently it's about 40 vs 20 respectively. I personally prefer the latter style very much (for pragmatic reasons, as it's very editor friendly). What's your opinion on this?

@MikeMcQuaid
Copy link
Member

Please note that due to a rubocop bug it may be needed to write # rubocop:disable before END, or to globally disable offending cops (currently Style/TrailingWhitespace and Style/Tab).

Let's just disable these.

Style/WordArray (i.e using %w(foo bar) instead of ["foo", "bar"]) has 18 violations among 429 total uses but is arguably worse in some of said violations. Given the ratio, do we enforce nonetheless to comply with the Ruby style guide?

I prefer the latter here, actually, as it's more obvious what it's doing to non-Ruby folks.

Need your feedback on Style/TrailingComma. It's about this:

Definitely prefer the trailing comma too.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 30, 2014

Enforcing SpaceAroundOperators is very useful for readability and recommended by the style guide. Yet it may conflict with the current use of / for concatenating paths, which seems to favour no spaces around. Autocorrecting gave me a few real-life examples and it's actually not that bad having spaces around, making the variables and concatenation points stand out a little more:

bin/"foo"
# vs
bin / "foo"  # seems striking at first, but mostly because we're not used to it

Disabling SpaceAroundOperators comes at the cost of people landing random space presence around operators, as each one seems (violations do show frequent inconsistencies, although spacing things is favored) to have its own preferences, or rather, tolerance. On the other side of the coin, no-space-around-/ looks very shell-ish. It really depends on whether you want it to appear like magic (and possibly opaque to non-ruby users) strings or slightly hint that it's actually a nice concatenation operator.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 30, 2014

There's no way currently to enforce forbidden use of %(). I've opened an issue upstream.

@MikeMcQuaid
Copy link
Member

I prefer the prior wrt SpaceAroundOperators

@lloeki
Copy link
Contributor Author

lloeki commented Dec 30, 2014

Pushed an update. As we said before, please disregard the formula fixes as only rubocop.yml will remain once I'm done.

@MikeMcQuaid
Copy link
Member

This needs rebased on master. Please remove the formula fixes if you don't mind as it'll kick off a massive CI job that I'll need to kill (doing this now).

@lloeki lloeki force-pushed the define_rubocop_style branch from 825cec6 to 6cb0a88 Compare December 31, 2014 14:21
@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

Removed formula fixes, and squash-rebased rubocop files. I had to remove the simple inheritance thingy because it seems to make things a bit flaky since I named both levels .rubocop.yml, so I though since we're focusing on formulas, we might as well make things simple and clear both to us and to everyone else (including both tooling and formula contributors).

@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

Style/UnneededPercentX has ~400 occurences of backticks vs ~15 occurences of %x{}. I personally favor %x{} for multiline as stranded backticks just don't stand out enough, especially with some fonts and colors. A case can be made for or against on single line either for consistency, shell-likeness, chained method call readability or stringiness of result.

An issue is opened upstream to enforce %x{} in such cases (default is to enforce backticks everywhere).

@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

Style/SpecialGlobalVars warns about use of $?, $0 and $/, favoring explicit synonyms like $CHILD_STATUS, $PROGRAM_NAME, and $INPUT_RECORD_SEPARATOR or $RS respectively. The habit displayed in current formula seems to confirm this is not a problem, so I disabled it but feel free to say otherwise.

Style/Tab:
Enabled: false
Style/TrailingBlankLines:
Enabled: false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't live in the Formula directory, unfortunately, as everything in there is treated as a formula. Let's just do a single file in Library instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I'll move it up, although please note it'll apply to the whole tree. I'm surprised there's no globbing though: what if I happen to have a go.rb~ or .DS_Store in there?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bunch of known issues with this but it is what it is for now, sadly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May as well consolidate the two in this case: I'm not convinced we need separate rules (for now) for Library/Formula and Library/Homebrew.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core of Homebrew ignores non-.rb files, but things like test-bot that read paths from diff output do not.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

Lint/ParenthesesAsGroupedExpression warns about ~20 priority-forcing, off-putting syntax:

# excerpts:
assert (output_dir/"url.txt").read.include?("http://brew.sh")
rm_rf (couchdb_share/"www/script/test/geocouch")
assert (Pathname.pwd/"foo").read.include? "hello homebrew!"
inreplace (share/"geocouch/geocouch.plist"), "%bindir%/%couchdb_command_name%", \
cd ("yara-python") do
cd (buildpath+"Ghcsource/tests") do

I can understand the will of consistently not using parentheses for method calls and spacing things like we're the shell, but from an outsider point of view not intimate with ruby's parser, this can be highly confusing, and given the low number of occurences I'd favor leaving the cop active. What's your take on this one?

@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

Style/AlignParameters wants to change things this way:

     system "make", "-C", "ace", "-f", "GNUmakefile.ACE",
                    "INSTALL_PREFIX=#{prefix}",
                    "LDFLAGS=",
                    "DESTDIR=",
                    "INST_DIR=/ace",
                    "debug=0",
                    "shared_libs=1",
                    "static_libs=0",
                    "install"
# into
     system "make",
            "-C", "ace", "-f", "GNUmakefile.ACE",
            "INSTALL_PREFIX=#{prefix}",
            "LDFLAGS=",
            "DESTDIR=",
            "INST_DIR=/ace",
            "debug=0",
            "shared_libs=1",
            "static_libs=0",
            "install"

Do you think the second style is suitable for formulas or should I disable the cop (created an issue upstream)? It sounds sensible to have system be a special case.

@MikeMcQuaid
Copy link
Member

Yeh, disable the second cop. With parens I don't think we want to consistently enforce them and the errors when they are ambigious are relatively obvious. We can always tweak these things later, thanks!

@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

Style/PercentLiteralDelimiters raises ~300 violations when respecting the style guide (i.e use () except for %r), mostly made of inconsistent %W and %w. The most used style for wW seems to be [], followed by {}, and finally the style-recommended (). When electing to enforce [] (which IMHO looks best, in a tie with (), especially next to often-used string interpolations), this is down to about 140, so I've set it this way, and you can always tweak it to something else later.

@lloeki lloeki force-pushed the define_rubocop_style branch from 6cb0a88 to 9848319 Compare December 31, 2014 17:05
@lloeki lloeki force-pushed the define_rubocop_style branch from 9848319 to 960c9e6 Compare December 31, 2014 17:06
@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

This last push marks the completion of the analysis from the formulas, moves .rubocop.yml in Library, and removes .rubocop_todo.yml together with its inclusion form inside .rubocop.yml. What remains if you run rubocop Formula from Library is actual violations (pending tweaks).

@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

For a little bit of statistics, this totals 17262 violations, of which 13644 are double quotes and 2858 are line length, the remainder being a long tail of small, inconsequential violations mostly counted in the single (or barely double) digits, that will be easily fixed one formula at a time.

@MikeMcQuaid
Copy link
Member

Thanks for the work here @lloeki! Will try and get this hooked up when I get the chance.

@DomT4
Copy link
Contributor

DomT4 commented Dec 31, 2014

Neat. This is awesome. I presume we can just gem install rubocop and rubocop in the formula directory and it'll generate a report based on the new ruleset?

@MikeMcQuaid
Copy link
Member

Yep. I'm going to tweak it a bit further though.

@lloeki
Copy link
Contributor Author

lloeki commented Dec 31, 2014

Yes gem install rubocop will do. Remember that rubocop is regularly updated, so it's best to have a 'latest version only' policy and rerun this from time to time (if this is a problem we can talk about Gemfiles). rubocop [path or file, or ommited] will output violations on stdout, while editors plugins (like syntastic for vim or linter+linter-ruby+linter-rubocop for Atom) will highlight violations straight in the editor, which will be very useful (and used to be very annoying :-)) to formula authors that also happen to have the plugins. Please note that to generate a file, you have to use rubocop --auto-gen-config and since this currently does not take an argument, it will output rubocop_todo.yml for the whole Library tree. A workaround is to move .rubocop.yml into Formula and run the command from there.

@jasonmp85
Copy link

As someone who once flippantly asked "why am I being told that I need to use double quotes for everything instead of your project having a rubocop file?" I am happy to see Homebrew finally get a rubocop file 👍.

@MikeMcQuaid
Copy link
Member

As someone who once flippantly asked "why am I being told that I need to use double quotes for everything instead of your project having a rubocop file?" I am happy to see Homebrew finally get a rubocop file .

A Rubocop file that'll fail submissions of new formulae that don't meet the style guidelines, too. Glad to hear you appreciate it, thanks @jasonmp85 and @lloeki for getting us there!

@Homebrew Homebrew locked and limited conversation to collaborators Feb 17, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants