結論
以下のようにするのがベストではないかと思ってますが、もっと良いやり方あったらコメントください。
module ValueObjectable
def initialize(args)
super(args)
freeze
end
end
class Location < Struct.new(:country, :city, keyword_init: true)
include ValueObjectable
end
## 特徴 ##
# 1. OpenStructのように Hash で初期化できる
tokyo = Location.new(country: 'Japan', city: 'Tokyo')
=> #<struct Location country="Japan", city="Tokyo">
# 2. 比較演算ロジックを自前で定義しないでいい
fukuoka = Location.new(country: 'Japan', city: 'Fukuoka')
tokyo == fukuoka
=> false
# 3. 値は不変
tokyo.country = 'U.S'
FrozenError: can't modify frozen Location