Techioz Blog

Java からのオーバーライド アノテーションを Ruby で複製することは可能ですか?

概要

Java では、Override アノテーションがスーパークラスに次のメソッドがあるかどうかをチェックすることはわかっています。

class Animal {
  public void speak () {
    System.out.println("Hello!");
  }
}
class Dog extends Animal {
  @override
  public void eat () { //this kind of stuff
    System.out.println("omnomnom");
  }
}

Rubyでこれを(関数か何かとして)行う方法はありますか?

解決策

最上位の eigenclass でクラス メソッドを定義すれば、これは比較的簡単です。

class Animal
  def speak; :ok; end

  def self.override *ms
    ms = ms - Animal.instance_methods
    puts "⚠️ #{ms.inspect} method(s) missing " \
         "in #{self}’s ancestors" unless ms.empty?
  end
end

class Dog < Animal
  override :speak
  def speak; :ok; end

  override :eat
  def eat; :ok; end
end

上記は印刷されます

# ⚠️ [:eat] method(s) missing in Dog’s ancestors

ここでオーバーライドする呼び出しは、引数を指定した Module#module_function の呼び出しに似ており、コード内の任意の場所に配置して、必要な数のメソッド名を受け入れることができます。

eigenclass インスタンス変数を使用して、Java バージョンに近づけることもできます。

class Animal
  def speak
    :ok
  end

  def self.inherited(base)
    base.instance_variable_set(:@override, ->(*ms) {
      ms = ms - Animal.instance_methods
      puts "⚠️ #{ms.inspect} method(s) without super" \
        unless ms.empty?
    })
  end
end

class Dog < Animal
  @override[:speak]
  def speak; :ok; end

  @override[:eat]
  def eat; :ok; end
end

TracePoint や Module#method_added を使用して Java 構文を完全に複製することもできますが、私はそれがあまり明示的ではないため、上記のように直接メソッド名を渡すことを避けます。