Rubyのクラスで定義されたattr_accessor一覧をそのクラスのインスタンス変数から取り出す方法
移転しました。
一応題名の通りで「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["なんやら"]って定義する訳にいかない。
初心者向けチュートリアルでわかりやすいといえばわかりやすいけど。