Documenting dry-structs

Documenting attributes using YARD for Plain Old Ruby Objects is fairly straightforward:

class Location
  # Geographic coordinate that specifies the north–south position
  # of a point on the Earth's surface
  # 
  # @return [Float]
  attr_reader :latitude
  
  # Geographic coordinate that specifies the east-west position
  # of a point on the Earth's surface.
  # 
  # @return [Float] 
  attr_reader :longitude
  
  def initialize(latitude:, longitude:)
    @latitude  = latitude
    @longitude = longitude
  end
end

But sometimes the attributes are created using metaprogramming. One such example is dry-struct, a gem built on top of dry-types which provides a virtus-like DSL for defining typed struct classes:

class Location < Dry::Struct
  # Geographic coordinate that specifies the north–south position
  # of a point on the Earth's surface
  # 
  # @return [Float]
  attribute :latitude, Types::Strict::Float
  
  # Geographic coordinate that specifies the east-west position
  # of a point on the Earth's surface.
  # 
  # @return [Float] 
  attribute :longitude, Types::Strict::Float
end

The shortcoming of this approach is that YARD does not know how to generate documentation from the attribute declarations. This is where the directive @!attribute comes in.

It defines an attribute with a given name, using indented block data as the attribute’s docstring. If the type specifier is supplied with "r", "w", or "rw", the attribute is made readonly, writeonly or readwrite respectively. A readwrite attribute is the default, if no type is specified. The comment containing this directive does not need to be attached to any source, but if it is, that source code will be used as the method’s source.

class Location < Dry::Struct
  # Geographic coordinate that specifies the north–south position
  # of a point on the Earth's surface
  # 
  # @!attribute [r] latitude
  #   @return [Float]
  attribute :latitude, Types::Strict::Float
  
  # Geographic coordinate that specifies the east-west position
  # of a point on the Earth's surface.
  # 
  # @!attribute [r] longitude
  #   @return [Float]
  attribute :longitude, Types::Strict::Float
end