Skip to content

Add RuboCop cop enforcing Data.define over Struct.new and convert existing usages #2878

Description

@mroderick

Olle's review on #2855 asked for Data.define instead of Struct.new in ActivityStrip. RuboCop has no built-in cop for this preference, so we should add one and clean up existing usages.

Work

  1. Add a custom cop Style/PreferDataDefine (in lib/rubocop/cop/style/prefer_data_define.rb, required from .rubocop.yml). It flags Struct.new sends. No autocorrection: the rewrite isn't safely mechanical (mutability and keyword semantics differ), so each hit gets a human decision.
module RuboCop
  module Cop
    module Style
      class PreferDataDefine < Base
        MSG = 'Prefer `Data.define` over `Struct.new` for immutable value objects.'

        def on_send(node)
          return unless node.receiver&.const_type? && node.receiver.value == :Struct
          return unless node.method?(:new)

          add_offense(node)
        end
      end
    end
  end
end
  1. Convert the existing offenses: the 7 Struct.new(:id, :email).new(...) test doubles in spec/helpers/email_header_helper_spec.rb. They are the only usages in the repo, and Data.define(:id, :email).new(1, '...') works with the same positional arguments, so the conversion is mechanical there.

  2. Add cop tests (spec/rubocop/... or inline) covering the flag case and a pass case for Data.define.

Notes

  • After adding the cop, regenerate .rubocop_todo.yml if needed and confirm CI passes.
  • Alternative rejected: a grep-based CI check — less precise and bypasses the existing RuboCop todo workflow.

Context: #2855 (comment)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions