From: murayama <locutus / pg8.so-net.ne.jp>
Subject: [ruby-list:42683] Re: Javaの interfaceのようなもの
Date: Sun, 13 Aug 2006 12:25:22 +0900

るびきちです。

> ・「スーパークラス」で必要なメソッドを全部定義し、例外を投げるように記述する。
> (それらのメソッドはサブクラスで適切にオーバーライドすることが前提。)

ちょいやってみました。
module_evalは言語レベルでどうにかするのにとても便利…柔軟性万歳。

使い方はスーパークラス側でextendします。

class NotImplemented < Exception; end
module MustImplement
  def must_implement(*methods)
    methods.each do |meth|
      module_eval %{
        def #{meth}(*args)
          raise NotImplemented, "Method `#{meth}' must be implemented in subclass."
        end
      }
    end
  end
end


require 'test/unit'
class TestMustImplement < Test::Unit::TestCase
  # sample usage
  class Base
    extend MustImplement
    must_implement :foo, :bar
  end

  class NotImplementedClass < Base
  end

  class ImplementedClass < Base
    def foo
      "implemented"
    end
    def bar
      "implemented"
    end
  end
  # /sample usage

  def test_not_implemted_class
    assert_raise(NotImplemented) { NotImplementedClass.new.foo }
  end

  def test_base
    assert_raise(NotImplemented) { Base.new.foo }
  end

  def test_implemented_class
    assert_equal("implemented", ImplementedClass.new.foo)
    assert_equal("implemented", ImplementedClass.new.bar)
  end
end

> ・起動時に、そのクラスのサブクラス一覧を取得し(これの取得方法はアプリ依存?
> それともリフレクションとかで可能?)、それらサブクラス全てについて上記に該当する
> メソッドを全て呼び出し、例外が出ないことを確認させる。(コンパイルエラーに相当。)

これはユニットテストでカバーできるのではないでしょうか?
--
rubikitch
http://www.rubyist.net/~rubikitch/