8

典型的な OO パターンがあります。1 つの基本抽象クラス (抽象メソッドを定義する) と、これらの抽象メソッドをクラス固有の方法で実装するいくつかのクラスです。

私は、抽象メソッドで一度だけドキュメントを書くことに慣れていて、それは自動的にいくつかの具体的なクラスに伝播します (少なくとも、Javadoc、Scaladoc、Doxygen では次のように機能します)。つまり、同じ説明を繰り返す必要はありません。すべての具体的なクラスで。

しかし、YARD でそのような伝播を行う方法を見つけることができませんでした。たとえば、次のことを試しました。

# Some description of abstract class.
# @abstract
class AbstractClass
  # Some method description.
  # @return [Symbol] some return description
  # @abstract
  def do_something
    raise AbstractMethodException.new
  end
end

class ConcreteClass < AbstractClass
  def do_something
    puts "Real implementation here"
    return :foo
  end
end

私が得るもの:

  • コードは期待どおりに動作します - つまり、スローAbstractMethodExceptionは抽象クラスで呼び出され、具象クラスでジョブを実行します
  • YARD では、AbstractClass抽象的なものとして明確に定義されている、ConcreteClass正常である
  • メソッドの説明と戻り値の型が良いAbstractClass
  • メソッドはスローAbstractMethodExceptionインと言われていますAbstractClass
  • メソッドにはまったく記述がなく、一般的なObject戻り値ConcreteClassの型が にあり、抽象メソッドが基底クラスに存在するという通知は 1 つもありません。

私が期待するもの:

  • メソッドの説明と戻り値の型は、ConcreteClassfrom info atに継承 (コピー) されます。AbstractClass
  • 理想的には、このメソッドは説明の「継承」または「実装」セクションで指定され、からへConcreteClassの参照リンクがあります。ConcreteClass#do_somethingAbstractMethod#do_something

そうすることは可能ですか?

4

2 に答える 2

4

問題は、あなたが何をしようとしているのかにかかっていると思います。Ruby でインターフェイスを実装しようとしているように見えますが、これは Java または .NET から来ている場合は理にかなっていますが、Ruby 開発者が実際に作業する傾向がある方法ではありません。

以下は、Ruby のインターフェースに関する一般的な考え方についての情報です: What is java interface equals in Ruby?

そうは言っても、あなたがやろうとしていることは理解しています。AbstractClass を直接実装したくないが、( Design by Contractのように) AbstractClass が規定するように動作するクラスで使用できるメソッドを定義したい場合は、おそらくモジュールを使用する必要があります。モジュールはコードをDRYに保つためには非常にうまく機能しますが、オーバーライドされたメソッドの文書化に関連する問題を完全には解決しません。したがって、この時点で、ドキュメントへのアプローチ方法を再考するか、少なくともより Ruby っぽい方法でアプローチすることができると思います。

Ruby での継承は、実際には (一般的に私自身の経験から言えば) いくつかの理由でのみ使用されます。

  • 再利用可能なコードと属性
  • デフォルトの動作
  • 専門化

もちろん他にもエッジケースはありますが、正直これはRubyで継承が使われる傾向にあるものです。これは、あなたがやっていることでうまくいかなかったり、ルールに違反したりするという意味ではなく、Ruby (またはほとんどの動的型付け言語) では一般的ではないということです。YARD (およびその他の Ruby doc ジェネレーター) が期待どおりに動作しないのは、おそらくこの非定型の動作が原因です。とはいえ、サブクラスに存在する必要があるメソッドのみを定義する抽象クラスを作成しても、コードの観点からはほとんどメリットがありません。定義されていないメソッドは、いずれにせよ NoMethodError 例外がスローされ、#respond_to?(:some_method)(またはメタを取得するための他のリフレクション ツールを使用して) メソッドを呼び出すものからのメソッド呼び出し (またはそのメッセージ) にオブジェクトが応答するかどうかをプログラムで確認できます。もの)。それはすべて戻ってきます ルビー'ダックタイピング

純粋なドキュメントの場合、実際に使用していないメソッドをドキュメント化するのはなぜですか? メソッドの呼び出しによって送受信されるオブジェクトのクラスについてはあまり気にする必要はなく、それらのオブジェクトが何に応答するかだけを気にする必要があります。したがって、ここで実際の価値が追加されない場合は、最初に AbstractClass を作成する必要はありません。実際にオーバーライドせずに直接呼び出すメソッドが含まれている場合は、モジュールを作成し、そこに文書化し、実行$ yardoc --embed-mixinsして、混合モジュールで定義されたメソッド (およびその説明) を含めます。それ以外の場合は、実装ごとに異なる必要があるため、実際に実装するメソッドを文書化します(そうでない場合は、再実装する必要があります)。

あなたがやっていることと似たようなことをする方法は次のとおりです。

# An awesome Module chock-full of reusable code
module Stuff
  # A powerful method for doing things with stuff, mostly turning stuff into a Symbol
  def do_stuff(thing)
    if thing.kind_of?(String)
      return thing.to_sym
    else
      return thing.to_s.to_sym
    end
  end
end

# Some description of the class
class ConcreteClass
  include Stuff

  # real (and only implementation)
  def do_something
    puts "Real implementation here"
    return :foo
  end
end

an_instance = ConcreteClass.new
an_instance.do_somthing       # => :foo
# > Real implementation here
an_instance.do_stuff("bar")   # => :bar

YARD を (--embed-mixins を指定して) 実行すると、Stuff モジュールから混合されたメソッドが (その説明とともに) 含まれ、Stuff モジュールを含むすべてのオブジェクトが期待どおりのメソッドを持つことがわかります。

Ruby Contractsも参照してください。これは、必要なオブジェクトのタイプのみを受け入れて返すメソッドを絶対に強制するために探しているものに近いかもしれませんが、それが YARD でどのように機能するかはわかりません.

于 2013-10-23T17:24:23.353 に答える