Skip to content

Replace virtus with an internal attributes module#1

Closed
pnomolos wants to merge 1 commit into
mainfrom
ps.replace-virtus
Closed

Replace virtus with an internal attributes module#1
pnomolos wants to merge 1 commit into
mainfrom
ps.replace-virtus

Conversation

@pnomolos

Copy link
Copy Markdown
Owner

Why

virtus is unmaintained and pulls in a chain of abandoned gems
(axiom-types, coercible, descendants_tracker, ice_nine) plus the
deprecated thread_safe (superseded by concurrent-ruby). RubyCritic only
used a tiny slice of virtus -- an attribute DSL on two classes -- so
carrying that whole dependency tree wasn't justified.

A custom module was chosen over dry-rb deliberately: dry-struct would just
trade one transitive tree for another (dry-core, dry-types, dry-logic,
zeitwerk...), which runs counter to the goal and to the codebase's recent
direction of shedding/leaning out dependencies (e.g. preferring prism over
the parser gem, dropping cucumber).

What changed

  • New internal RubyCritic::Attributes module reproducing only the used
    virtus subset: an attribute macro, type coercion, per-instance duped
    defaults, and a hash-accepting initializer.
  • Smell and AnalysedModule now include RubyCritic::Attributes instead
    of Virtus.model.
  • virtus runtime dependency removed; ostruct moved to a development
    dependency (only used in tests).
  • .reek.yml and CHANGELOG.md updated accordingly.

Verification

  • Full rake suite is green: tests, reek (0 warnings), and rubocop (no
    offenses).
  • The full virtus dependency chain is confirmed gone from the bundle.
  • Behavior verified faithful to virtus: mutable defaults duped per-instance,
    Float::INFINITY/Symbol defaults preserved, coercion applied on writers,
    and method overrides intact.

Checklist

🤖 Generated with Claude Code

The `virtus` gem is unmaintained and drags in a chain of abandoned
transitive dependencies: axiom-types, coercible, descendants_tracker,
ice_nine, and the deprecated thread_safe (superseded by concurrent-ruby).
RubyCritic only used a tiny slice of virtus -- an `attribute` DSL on two
classes -- so carrying that whole tree was not justified.

Introduce a small internal `RubyCritic::Attributes` module that
reproduces only the used subset: an `attribute` class macro with
reader/writer generation, type coercion (Float/Integer/Array/Symbol),
per-instance duped mutable defaults, and a hash-accepting initializer.
`Smell` and `AnalysedModule` now include it instead of `Virtus.model`.
Drop the `virtus` runtime dependency and move `ostruct` to a development
dependency (only referenced in tests). Update `.reek.yml` and the
changelog accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pnomolos

Copy link
Copy Markdown
Owner Author

Superseded by the upstream PR against whitesmith/rubycritic (whitesmith#574).

@pnomolos pnomolos closed this Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant