Skip to content

Enable Style/FrozenStringLiteralComment - #193

Merged
dduugg merged 1 commit into
mainfrom
enable-frozen-string-literal-comment
Sep 26, 2026
Merged

dduugg merged 1 commit into
mainfrom
enable-frozen-string-literal-comment

Conversation

@dduugg

@dduugg dduugg commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

Why

With # frozen_string_literal: true, an accidental in-place change to a string literal raises a FrozenError right where it happens, rather than quietly changing shared state. The pragma also means each literal is allocated once instead of every time the line runs. On Ruby 3.4+, files without the pragma already emit "literal string will be frozen in the future" deprecation warnings when they mutate a literal, so turning the cop on now keeps us ahead of that.

Config change

.rubocop.yml: removed this block:

# Disabling for now until it's clearer why we want this
Style/FrozenStringLiteralComment:
  Enabled: false

With it gone, the cop picks up EnforcedStyle: always_true from the inherited rubocop-gusto config/default.yml. .rubocop_todo.yml had no entry for this cop, so it is unchanged.

Files changed

  • 40 files got the pragma: everything under lib/, plus bin/packs, Gemfile, Rakefile, packs.gemspec, spec/packs_spec.rb, spec/packs/private/cli_spec.rb and spec/verify_docs_spec.rb.
  • 6 more files already had it (bin/rubocop, bin/tapioca, sorbet/tapioca/require.rb, spec/spec_helper.rb, and two interactive CLI specs). That makes 46, the number of files rubocop inspects.
  • No exclusions were added. The only generated Ruby is sorbet/rbi/**/*.rbi, which rubocop already skips.
  • In bin/packs, the pragma goes on line 3, after the shebang and # typed: strict. Ruby still honors it there.

Runtime fixes

None were needed. No spec failed. A static review of every string literal in lib/ and bin/ found none that reaches an in-place String mutation. Every << in lib/ appends to an Array, and the gems that receive our literals (Thor, tty-prompt/tty-reader, Pastel, Rainbow, CSV, parse_packwerk, code_ownership, packwerk) either copy them or never change them.

Heads-up for downstream code: a few public methods now return frozen Strings. These are the <<~MSG heredocs without interpolation in Packs::UserEventLogger#after_make_public and #after_add_dependency, the literal in #documentation_link, and Packs::Private.rename_pack. A custom logger that did super << "..." would now raise FrozenError. Nothing in this repo or its docs does that, and a GitHub code search turned up no such overrides. It was already deprecated too: on main, that pattern warns on Ruby 3.4+.

Verification

  • Specs: origin/main gave 119 examples, 0 failures. This branch gives 119 examples, 0 failures on Ruby 4.0.7 and on 3.3.11, the lowest version in the CI matrix. Those runs used -W:deprecated --debug-frozen-string-literal and produced no chilled-string warnings or FrozenErrors. The suite also passes with RUBYOPT=--enable-frozen-string-literal.
  • Rubocop: 46 files inspected, no offenses. srb tc has no errors.
  • Static sweep:
    • Checked with Prism that the pragma takes effect in every tracked Ruby file.
    • Listed all 531 string-literal nodes in lib/ and bin/ and traced each one to what consumes it. That covered method return values, default arguments, Hash and Array values, and arguments handed to gems. For the gems, I read the source of the exact locked versions.
    • required_ruby_version is >= 3.3, so interpolated strings stay unfrozen.
  • Dynamic checks: specs don't cover everything, so the uncovered paths were run by hand on Ruby 4.0.7 and 3.3.11 against a fixture app, with the output compared to main.
    • 71 bin/packs CLI invocations: every subcommand, help for all 16 commands, and the error paths.
    • 21 interactive-mode scenarios through TTY::Prompt::Test, plus real-PTY runs of the menu, Rename, Create and Ctrl-C.
    • Direct calls to the private helpers.
    • gem build and rake -T.
    • stdout/stderr and the resulting files matched main.
  • Fresh Eyes local review: 0 blockers, 0 major, 0 minor.

Checklist

  • I bumped the gem version (or don't need to) 💎 (no bump needed: this is a lint/config change with no intended behavior change)

Remove the .rubocop.yml entry that disabled Style/FrozenStringLiteralComment,
so the cop now runs with rubocop-gusto's EnforcedStyle: always_true.

Add "# frozen_string_literal: true" to the 40 files the cop flagged: everything
under lib/, bin/packs, the remaining specs, Gemfile, Rakefile and packs.gemspec.
Where a file has a Sorbet "# typed:" sigil, the pragma goes on the line below
it, matching the files that already had the pragma (spec_helper.rb,
sorbet/tapioca/require.rb, the interactive CLI specs). Gemfile and packs.gemspec
also get the blank line that Layout/EmptyLineAfterMagicComment requires.

No mutation fixes were needed. A static sweep of every newly frozen literal
found none that is mutated in place, either in this repo or by the libraries
they are passed to (Thor, tty-prompt/tty-reader, Rainbow, Pastel, CSV,
parse_packwerk, packwerk). The spec suite, a run with -W:deprecated (which
reported no chilled-string warnings), and smoke runs of every bin/packs
command and interactive use case all pass.
@dduugg
dduugg requested a review from a team as a code owner September 26, 2026 17:23
@github-project-automation github-project-automation Bot moved this to Triage in Modularity Sep 26, 2026
@dduugg
dduugg merged commit 6376c07 into main Sep 26, 2026
9 checks passed
@dduugg
dduugg deleted the enable-frozen-string-literal-comment branch September 26, 2026 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant