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
- 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
-
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.
-
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)
Olle's review on #2855 asked for
Data.defineinstead ofStruct.newinActivityStrip. RuboCop has no built-in cop for this preference, so we should add one and clean up existing usages.Work
Style/PreferDataDefine(inlib/rubocop/cop/style/prefer_data_define.rb, required from.rubocop.yml). It flagsStruct.newsends. No autocorrection: the rewrite isn't safely mechanical (mutability and keyword semantics differ), so each hit gets a human decision.Convert the existing offenses: the 7
Struct.new(:id, :email).new(...)test doubles inspec/helpers/email_header_helper_spec.rb. They are the only usages in the repo, andData.define(:id, :email).new(1, '...')works with the same positional arguments, so the conversion is mechanical there.Add cop tests (
spec/rubocop/...or inline) covering the flag case and a pass case forData.define.Notes
.rubocop_todo.ymlif needed and confirm CI passes.Context: #2855 (comment)