WHITELEAF:Kindle応援サイト

KindleでWEB小説を読もう! Narou.rb 公開中

abstract method

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/15841
こちらを書き直し

class AbstractMethodCallError < NotImplementedError
end

class AbstractNotImplementedError < NotImplementedError
end

class Module
  @@_abstract_methods = {}

  def abstract_method(*names)
    names.map! { |name|
      Symbol === name ? name : name.to_s.intern
    }
    @@_abstract_methods[self] ||= []
    @@_abstract_methods[self] |= names
    names.each { |name|
      self.module_eval {
        define_method(name) {
          raise AbstractMethodCallError, "Method `#{name}' must be implemented in subclass."
        }
      }
    }
  end

  # 未実装な abstract method の一覧を取得
  def not_implemented_methods
    methods = []
    ancestors.reverse_each { |mod|
      methods -= mod.instance_methods(false).map { |name|
        name.intern
      }
      methods -= mod.private_instance_methods(false).map { |name|
        name.intern
      }
      methods |= @@_abstract_methods[mod] if @@_abstract_methods.include?(mod)
    }
    return methods
  end

  def check_abstract
    methods = not_implemented_methods
    if methods.length > 0
      puts "Not implemented method list:"
      methods.each do |name|
        puts self.to_s + "#" + name.to_s
      end
      raise AbstractNotImplementedError
    end
  end
end

__END__

# 使い方
class A
  abstract_method :a, :b
  ...
end

class C < A
  ...
end

C.check_abstract

どうしても abstract にしたいのが出てくるので。

2010/04/30更新:
private methods も取得するように変更