Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

卜部昌平のあまりreblogしないtumblr RSS

Mar
2nd
Tue
permalink

[ruby][howto]クラスを生成するクラスの作り方

Rubyな話。

「とあるオブジェクト群はそのなかでクラスタに分かれていて、クラスタごとに振る舞いが違うんだけど、そのクラスタの数が不定」という状況がたまぁ〜にある。Ruby なおまえらがよく知っている例としては Active Record パターンとかはそう。Active Record パターンだとオブジェクトは DB の行で、したがって振る舞いは DB のテーブル(かビュー)によって決まるんだけど、Active Record の基底クラスを設計している段階ではどんなテーブルがあるかなんてのは当然すべてのパターンを網羅的に作成しておく事はできない。

んで、Rails についてくる ActiveRecord::Base だと、そのへんはかつては「クラスが継承されたときにそこにフックして派生クラスに実装を注入」というインド人もびっくりの力技で解決されていて(今見たら今はそこまでじゃないが)、まあそれでみんな不満なくお使いですので特に申し上げることはございませんが、世の中にはもう少しエレガントな解決方法もありえて、つまりクラスを明示的に生成するメソッドがあればいい。そういう例はたとえば Ruby には Struct というクラスがあって、 Struct.new は Struct のインスタンスではなくて Struct の派生クラスを返す。

で、そのようなメソッドをどう作るかというと、これはイディオムがあって

class Foo
    def self.foo
        Class.new self
    end
end

はい、これ試験に出ますよ(メタプログラミング検定3級)。ただし Struct.new みたいに new で新しいクラスを作成しようと思うとちょっとひねらないといけない。なんでかというと

class Foo
    def self.new
        Class.new self
    end
end

だとインスタンスを作成するための new がつぶれちゃうから。これを回避するには、

class Foo
    def self.new
        Class.new self do
            class << self
                define_method :new, Class.instance_method(:new)
            end
        end
    end
end

こんな風にする。Class の instance method の new とはようするに、普通の new だ。

というわけで今回は特に毒があるエントリではないけど、この件は見た感じレシピ系の本にはどれにも載ってなさそうっぽいので、書いておくことにした。おまえらは知っておいて損はないよ。

  1. naotoo reblogged this from shyouhei
  2. ftnk reblogged this from shyouhei
  3. tmaedax reblogged this from shyouhei
  4. la3 reblogged this from shyouhei
  5. kakutani reblogged this from shyouhei
  6. tyru-tech reblogged this from shyouhei
  7. iwadon reblogged this from shyouhei
  8. kiyo-shit reblogged this from shyouhei
  9. shyouhei posted this