我习惯在抽象方法中只编写一次文档然后自动传播到几个具体的类(至少它在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中的方法描述和返回类型都很好
> Method说在AbstractClass中抛出AbstractMethodException
> Method在ConcreteClass中根本没有描述和泛型Object返回类型,没有一个通知表明基类中存在抽象方法.
我期望得到什么:
> Method的描述和返回类型从AbstractClass的info继承(即复制)到ConcreteClass
>理想情况下,此方法在ConcreteClass描述的“继承”或“已实现”部分中指定,具有从ConcreteClass#do_something到AbstractMethod#do_something的一些参考链接.
有可能这样做吗?
解决方法
以下是关于Ruby中接口的典型思想的一些信息:What is java interface equivalent in Ruby?
那就是说,我明白你要做什么.如果您不希望直接实现AbstractClass,但是您想要定义可以在类似AbstractClass规定的类中使用的方法(如Design by Contract),那么您可能希望使用模块.模块可以很好地保存代码DRY,但是它们并没有完全解决与记录overridden methods相关的问题.所以,在这一点上,我认为你可以重新考虑如何处理文档,或者至少在更多Ruby-ith中处理它办法.
Ruby中的继承(实际上根据我自己的经验)仅用于以下几个原因:
显然还有其他边缘情况,但老实说这就是Ruby中常用的继承.这并不意味着你正在做的事情不起作用或违反某些规则,它在Ruby(或大多数动态类型语言)中并不常见.这种非典型行为可能是YARD(和其他Ruby doc生成器)没有达到预期效果的原因.也就是说,创建一个只定义子类中必须存在的方法的抽象类,从代码的角度来看,实际上只能获得很少的收益.未定义的方法将导致无论如何抛出NoMethodError异常,并且您可以使用#respond_to?(:some_method)以编程方式检查对象是否将从方法调用方法调用(或任何消息)响应该方法.或其他用于获取元素的反射工具).这一切都归功于Ruby对Duck Typing的使用.
对于纯文档,为什么要记录一个实际上没有使用的方法?您不应该真正关心通过调用方法发送或接收的对象的类,只是这些对象响应的内容.因此,如果在这里没有添加任何实际值,请不要首先创建您的AbstractClass.如果它包含您实际将直接调用的方法而不覆盖,则创建一个Module,在那里记录它们,并运行$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一起使用.