- Published on
Rubyのクラスで定義されたattr_accessor一覧をそのクラスのインスタンス変数から取り出す方法
- Authors
- ジャバ・ザ・ハットリ
一応題名の通りで「Ruby のクラスで定義された attr_accessor 一覧をそのクラスのインスタンス変数から取り出す方法」なのだが、何を言ってるのか書いた本人でも「?」となりがちなのでまずはやりたかったことから説明する。
例えば Book クラスがあって、そこに attr_accessor が定義されている。
class Book
attr_accessor :id, :title, :author
end
Book クラスを作ってインスタンス変数を作る。
@book = Book.new
attr_accessor に定義されているように以下のように変数にアクセスできる。
> @book.title "STAR WARS"
やりたかったのはこの@book を使って中で定義されている attr_accessor の一覧を取り出すこと。
こんな感じ。
> @book.something\_something [:id, :title, :author]
結果的にできた方法はこれ
class BaseModel
def self.attr_accessor(*vars)
@@attributes ||= []
@@attributes.concat vars
super
end
def attributes
@@attributes
end
end
class Book < BaseModel
attr_accessor :id, :title, :author
end
こうしておくと以下のように一覧が出る。やってみれば単純だけど、最初ちょっと悩んだ。
> @book.attributes [:id, :title, :author]
解説
クラスメソッドの attr_accessor の処理を上書きし、クラス変数として@@attributes を定義して、そこに一覧を格納しておくようにする。
def self.attr_accessor(*vars)
@@attributes ||= []
@@attributes.concat vars
super
end
インスタンス変数@book からインスタンスメソッドの attributes が呼ばれたら、クラス変数を返す。
def attributes
@@attributes
end
なんでこんなことをやっているのかというと個人プロジェクトで作っている Rail に Google Cloud Datastore をつなげようとしたのがことの始まり。Google Cloud Platform は Java や Go、Python なんかには初期から対応していたのに Ruby はかなり後回し。最近になってやっと対応してくれたと思ったら、その公式サイトから出ているコードがなんとも微妙。
例えば Google Cloud Datastore をつなげた Rails の Model のコード例がこんな感じ。
class Book
attr_accessor :id, :title, :author, :published_on, :description
# [START to_entity]
# ...
def to_entity
entity = Google::Cloud::Datastore::Entity.new
entity.key = Google::Cloud::Datastore::Key.new "Book", id
entity["title"] = title
entity["author"] = author if author
entity["published_on"] = published_on if published_on
entity["description"] = description if description
entity
end
# [END to_entity]
end
Book クラスが1つだけならいいけど、後から作るモデルクラスにも全部いちいち entity["なんやら"]って定義する訳にいかない。
初心者向けチュートリアルでわかりやすいといえばわかりやすいけど。