我有一个典型的OO模式:一个基本抽象类(定义抽象方法)和几个以类特定方式实现这些抽象方法的类。
我习惯在抽象方法中只编写一次文档然后自动传播到几个具体的类(至少它在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
,在具体类中完成工作AbstractClass
明确定义为摘要,ConcreteClass
是正常的AbstractClass
AbstractMethodException
AbstractClass
Object
中的泛型ConcreteClass
返回类型,基类中不存在抽象方法的通知。我期望获得:
ConcreteClass
AbstractClass
ConcreteClass
描述的“已继承”或“已实施”部分中指定,并带有从ConcreteClass#do_something
到AbstractMethod#do_something
的参考链接。是否可以这样做?
答案 0 :(得分:4)
我认为这个问题归结为你想要做的事情。看起来你正在尝试在Ruby中实现一个接口,如果你来自Java或.NET,这是有道理的,但实际上并不是Ruby开发人员的工作方式。
以下是关于Ruby中接口的典型思想的一些信息:What is java interface equivalent in Ruby?
那就是说,我明白你要做什么。如果您不希望直接实现AbstractClass,但是您想要定义可以在类似AbstractClass规定的类中使用的方法(如Design by Contract中所述),那么您可能希望使用模块。模块可以很好地保存您的代码DRY,但它们并不能完全解决与记录overridden methods相关的问题。所以,在这一点上,我认为你可以重新考虑如何处理文档,或者至少以更加Ruby的方式处理它。
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模块在内的任何对象都将具有您期望的方法。 p>
您可能还想查看Ruby Contracts,因为它可能更接近您正在寻找的绝对强制方法接受并仅返回您想要的对象类型,但我不确定如何与YARD一起玩。
答案 1 :(得分:1)