You are starting a new open-source Ruby gem that supports Ruby 3.2 and later: how would you set up Standard, and when would plain RuboCop be the better choice?
answer
- standard in the Gemfile, not the gemspec
- ruby_version: 3.2 in .standard.yml
- rake default runs test and standard
- Standard pins the RuboCop series
- per-cop tuning needs RuboCop
basics
~20 sPut standard in the Gemfile's development group, set ruby_version: 3.2 in .standard.yml, and make rake's default task run tests and standard. Choose plain RuboCop to tune cops, enforce Metrics, or use features newer than Standard's pinned RuboCop.
solid answer
~50 sFor the gem I would put `gem "standard"` in the **Gemfile** (development group), not as a gemspec dependency, so users of the gem never install a linter. `.standard.yml` gets `ruby_version: 3.2`, because without it Standard targets whatever Ruby runs it, and on Ruby 4.0 `--fix` could rewrite `_1` to `it`, which Ruby 3.2 treats as a call to an undefined method. The Rakefile requires `standard/rake` and sets `task default: %i[test standard]`, CI runs `bundle exec rake` on the oldest and newest supported Rubies, and contributors run `standardrb --fix`. The gain is no style debates in pull requests and no `.rubocop.yml` to maintain. I would pick plain RuboCop instead when the project must change a built-in rule, enforce `Metrics` limits, use cops Standard does not enable, or needs RuboCop features newer than the 1.88 series Standard 1.56 pins, such as `disable-next` or `AllCops: FailLevel`.
code
yaml · 3 lines# .standard.yml
ruby_version: 3.2
parallel: truego deeper
Recall the setup: standard in the Gemfile, require standard/rake, and standardrb --fix before committing.
Explain why ruby_version must be pinned for a gem and how the rake default task makes one command run tests and style.
Lay out the CI matrix, the upgrade path through Standard releases, and the concrete needs that would push the project to plain RuboCop.
Weigh contributor friction and maintenance cost against control over rules and RuboCop versions, and record the decision for future maintainers.
## The situation A new open-source gem will receive pull requests from people who have never seen the codebase, and it must keep working on every Ruby it claims to support, here 3.2 through 4.0. Its style tooling should make contributions consistent without generating arguments, and it must never make the gem's code incompatible with its oldest supported Ruby. ## Setting up Standard 1. **Dependency placement.** Add `gem "standard", require: false` to the `Gemfile`'s development group. A runtime dependency in the gemspec would install Standard, RuboCop and their dependencies for every user of the gem. 2. **Target Ruby.** Create `.standard.yml` with `ruby_version: 3.2`. Standard sets RuboCop's `TargetRubyVersion` from this key and, when it is absent, from the running interpreter's `RUBY_VERSION`, ignoring the gemspec's `required_ruby_version`. A maintainer on Ruby 4.0 without the key would get suggestions, and `--fix` rewrites, that older Rubies cannot run: Standard's `Style/ItBlockParameter` turns `_1` into the `it` parameter from Ruby 3.4, which Ruby 3.2 reads as a call to an undefined method `it`. 3. **Rake integration.** In the `Rakefile`, `require "standard/rake"` and `task default: %i[test standard]`, so `bundle exec rake` is the single command contributors and CI run. 4. **CI.** Run `bundle exec rake` on a matrix with at least the oldest (3.2) and newest (4.0) supported Rubies. With `ruby_version` pinned, the lint result is the same on every entry. 5. **Contributor workflow.** Document `bundle exec standardrb --fix` in the contributing guide, and point editor users at Standard's language server (`standardrb --lsp`). 6. **Upgrades.** Let a dependency bot propose Standard upgrades; each one moves RuboCop and the ruleset together, and the pull request shows any new offenses. ## What Standard gives an open-source project - **No configuration to review.** A contributor cannot propose changing a rule in `.standard.yml`, because rules are not configurable there. - **Familiarity.** Contributors who have used Standard elsewhere meet the same rules. - **Low maintenance.** Standard, not the maintainer, decides how each new RuboCop cop is configured. ## When plain RuboCop is the better choice | Need | Why Standard cannot meet it | |---|---| | change a built-in rule (quotes, a specific cop) | Standard's rules are first-in-wins and not configurable | | enforce `Metrics` or `Layout/LineLength` limits | Standard switches those cops off | | a specific RuboCop release or newer feature | Standard 1.56 depends on `rubocop ~> 1.88.0` | | an existing, detailed `.rubocop.yml` the team relies on | Standard ignores `.rubocop.yml` | | per-cop `Severity` or `AllCops: FailLevel` policies | not expressible in `.standard.yml` | The version row deserves emphasis. With Standard 1.56 the project runs RuboCop 1.88.x, so the `disable-next` directive (1.90), `AllCops: FailLevel` (1.91) and the Preview channel (1.91) are unavailable until a Standard release moves the pin. ## A middle path, and its limits A project can add rules on top of Standard with `plugins:` (lint_roller gems) and `extend_config:` (RuboCop YAML files). That covers framework rules and project-specific cops, but not changing Standard's own choices. The README also describes loading Standard's YAML from `.rubocop.yml` through `inherit_gem`, and labels that route unsupported. ## Keeping the setup honest - Commit `.standard.yml` and `Gemfile.lock`, so every contributor and CI job runs the same Standard, RuboCop and options. - Revisit `ruby_version` whenever the gemspec's `required_ruby_version` changes; the two should always name the same oldest Ruby. - Keep `standard:disable` comments rare and explained, since contributors copy what they see. - Re-read the decision when a Standard upgrade lags a RuboCop feature the project needs. ## Recommendation For a small or medium open-source gem whose maintainers do not have strong style requirements, Standard with a pinned `ruby_version` is the lower-maintenance choice. For a project with established conventions, strict size limits, or a need to track RuboCop closely, plain RuboCop with a reviewed `.rubocop.yml` is the better fit.
- Why put standard in the Gemfile instead of add_development_dependency in the gemspec?Both keep it out of users' installs, but the Gemfile is where the project's own tooling lives and where `Gemfile.lock` pins the exact Standard, and therefore RuboCop, version for every contributor and CI run. What must never happen is a runtime `add_dependency`, which would install the linter for every user of the gem.
- A contributor on Ruby 4.0 runs standardrb --fix and CI on Ruby 3.2 then fails with NameError for it. What was missing?`ruby_version` in `.standard.yml`. Without it Standard used the contributor's Ruby 4.0 as the target, so its safe fixes replaced `_1` with `it`, the block parameter added in Ruby 3.4, which 3.2 treats as an undefined method. Pinning `ruby_version: 3.2` makes every run target the oldest supported Ruby.
saying these in an interview costs you the question
- Add standard as a runtime dependency in the gemspec so contributors get it.
- Standard reads required_ruby_version from the gemspec, so ruby_version is unnecessary.
- Standard 1.56 lets you use RuboCop 1.91 by pinning it in the Gemfile.
- If one rule bothers you, disable it in .standard.yml.
- A gem's lint target should be the newest Ruby it supports.