アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

Lisp on Rails 第2回 〜 メタクラス

こんにちは!! tahara です。 Lisp on Rails 第2回です!

ActiveRecord::Base ではクラスメソッドとして find や all の検索メソッドが定義されています。

Common Lisp でそれらを実装するにあたり、メタクラスのメソッドとして実装してみます。 Common Lisp では自分でメタクラスを定義することができます。 次のようにメタクラスを定義します。 なんとなく、テーブル名とカラム情報を持たせています。

(defclass active-record-class (standard-class)
  ((%table-name :initarg :%table-name :accessor %table-name-of)
   (%columns :initarg :%columns :accessor %columns-of)))

各テーブル毎のクラスはこの active-record-class のインスタンスになり、 インスタンス変数としてテーブル名とカラム情報を持つイメージです。

メタクラスに全レコードを取得する all メソッドを実装します。

(defmethod all ((class active-record-class))
  (multiple-value-bind (rows columns)
      (clsql-sys:query (format nil "select * from ~a" (%table-name-of class)))
    (loop for i in rows
          collect (make-instance-from-row class i columns))))

(def-record post) は次のように展開されて :METACLASS ACTIVE-RECORD::ACTIVE-RECORD-CLASS を指定します。

(PROGN
  (DEFPARAMETER POST
    (DEFCLASS POST (BASE)
      ((ID :INITARG :ID :INITFORM NIL :ACCESSOR ID-OF)
       (NAME :INITARG :NAME :INITFORM NIL :ACCESSOR NAME-OF)
       (TITLE :INITARG :TITLE :INITFORM NIL :ACCESSOR TITLE-OF)
       (CONTENT :INITARG :CONTENT :INITFORM NIL :ACCESSOR CONTENT-OF)
       (CREATED-AT :INITARG :CREATED-AT :INITFORM NIL :ACCESSOR
                   CREATED-AT-OF)
       (UPDATED-AT :INITARG :UPDATED-AT :INITFORM NIL :ACCESSOR
                   UPDATED-AT-OF))
      (:METACLASS ACTIVE-RECORD::ACTIVE-RECORD-CLASS)))
      ...

Ruby のクラス定義と違って Common Lisp のクラス定義ではクラス名に何も束縛しないため、 わざわざ defparameter しています。

そんな感じでメタクラスによる

(all post)

ができました。

ソースはこちらから http://github.com/quek/lisp-on-rails

第3回につづきます