メソッドの override を強制する

## 概要

継承や Mix-in を利用する際に、特定のメソッドの override を強制したいな。
そのような場合は [NotImplementedError](http://docs.ruby-lang.org/ja/2.1.0/class/NotImplementedError.html) を利用すると便利です。

## 1. 継承の場合

``` ruby
class Mage
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job} の #{name} は #{magic} を唱えた！"
  end

  private

  # サブクラスで必ず実装しておいて欲しい。
  def job
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end

  # サブクラスで必ず実装しておいて欲しい。
  def magic
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end
end

class BlackMage < Mage
  private

  def job
    "黒魔道士"
  end
end

class WhiteMage < Mage
  private

  def magic
    "ケアル"
  end
end

class BlueMage < Mage
  private

  def job
    "青魔道士"
  end

  def magic
    "マイティガード"
  end
end

BlackMage.new("ビビ").spell
#=> NotImplementedError: You must implement BlackMage#magic

WhiteMage.new("エーコ").spell
#=> NotImplementedError: You must implement WhiteMage#job

BlueMage.new("クイナ").spell
#=> "青魔道士 の クイナ は マイティガード を唱えた！"
```

## 2. Mix-in の場合

``` ruby
module Mage
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job} の #{name} は #{magic} を唱えた！"
  end

  private

  # Mix-in する Class で必ず実装しておいて欲しい。
  def job
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end

  # Mix-in する Class で必ず実装しておいて欲しい。
  def magic
    raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
  end
end

class BlackMage
  include Mage

  private

  def job
    "黒魔道士"
  end
end

class WhiteMage
  include Mage

  private

  def magic
    "ケアル"
  end
end

class BlueMage
  include Mage

  private

  def job
    "青魔道士"
  end

  def magic
    "マイティガード"
  end
end

BlackMage.new("ビビ").spell
#=> NotImplementedError: You must implement BlackMage#magic

WhiteMage.new("エーコ").spell
#=> NotImplementedError: You must implement WhiteMage#job

BlueMage.new("クイナ").spell
#=> "青魔道士 の クイナ は マイティガード を唱えた！"
```

このように実装しておけば、
未実装の場合にメソッドを呼び出した際には NotImplementedError が発生し、
例外のメッセージで実装すべきインスタンスメソッドを知らせてくれるので便利です。

## 3. 発展: クラスアノテーション化する

複数のメソッドに
`raise NotImplementedError.new("You must implement #{self.class}##{__method__}")`
と書くのは面倒です。
そこで [クラスアノテーション](http://d.hatena.ne.jp/asakichy/20100624/1277339618) として宣言できるようにしてみました。

``` ruby
module NecessaryToOverride
  # 必ず Override すべきメソッドを列挙する。
  def necessary_to_override(*methods)
    methods.each do |method|
      define_method(method) do |*_args|
        raise NotImplementedError.new("You must implement #{self.class}##{__method__}")
      end
    end
  end
end

Module.include(NecessaryToOverride)
```

以下のように利用します。

### 3-1. 継承の場合

``` ruby
class Mage
  # サブクラスで job と magic というメソッドを必ず実装しておいて欲しい。
  necessary_to_override :job, :magic
  
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job} の #{name} は #{magic} を唱えた！"
  end
end

class BlackMage < Mage
  private

  def magic
    "ファイア"
  end
end

BlackMage.new("ビビ").spell
#=> NotImplementedError: You must implement BlackMage#job
```

### 3-2. Mix-in の場合

``` ruby
module Mage
  # Mix-in する Class で job と magic というメソッドを必ず実装しておいて欲しい。
  necessary_to_override :job, :magic
  
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def spell
    "#{job} の #{name} は #{magic} を唱えた！"
  end
end

class WhiteMage
  include Mage

  private

  def job
    "白魔道士"
  end
end

WhiteMage.new("エーコ").spell
#=> NotImplementedError: You must implement WhiteMage#magic
```

## 参考

* [Ruby Patterns](http://r7kamura.hatenablog.com/entry/2014/01/22/223346)
  * 「Overrideしてほしいメソッドの実装にNotImplementedErrorを利用する」の節