Rubyにてセッタをもたないimmutableなクラスを作り、to_hashで値を取ってくるようにしたのでまとめます。
今回は例として本(Book)クラスを作ります。
完成品
class Book ATTRIBUTE_NAMES = [:name, :author, :price].freeze attr_reader *ATTRIBUTE_NAMES def initialize(name, author, price) @name = name @author = author @price = price end def to_hash ATTRIBUTE_NAMES.inject({}) do |hash, attribute_name| hash.merge({ attribute_name => send(attribute_name) }) end end alias_method :to_h, :to_hash end puts Book.new("こころ", "夏目漱石", 1980).to_hash # {:name=>"こころ", :author=>"夏目漱石", :price=>100}
attr_reader
でゲッタをまとめて定義しています。attr_accessor
との違いはセッタの有無です。セッタを無くしimmutableに近づけています。
本来は
attr_reader :name, :author, :price
のように指定するのですが、直接指定すると後ほど指定した:name
, :author
, :price
の3つの名前を手軽に取ってくることができなかったため、まずクラスの定数に入れています。
to_hash
メソッドでは先程のクラスの定数ATTRIBUTE_NAMES
を元にハッシュを作成しています。
def to_hash ATTRIBUTE_NAMES.inject({}) do |hash, attribute_name| hash.merge({ attribute_name => send(attribute_name) }) end end
keyを:name
などの属性名のシンボルで、valueにname
などのゲッタメソッドを叩いて取ってきた値を入れたハッシュを作って返しています。sendを使わない場合は以下でも動きます。
def to_hash ATTRIBUTE_NAMES.inject({}) do |hash, attribute_name| hash.merge({ attribute_name => instance_variable_get("@#{attribute_name}") }) end end
あと一応to_h
でも大丈夫なようにエイリアスを貼りました。
DDDにおけるドメインオブジェクトとかはこんな感じで作っていったらなと思いました。また何かあればアップデートしていきます。
injectを初めてまともに使えた気がする…。