There are many code documentation specifications for Ruby like RDoc, YARD, TomDoc etc. but personally I prefer using YARD.
To use YARD for documenting your code, you will need to install the YARD gem
using gem install yard
Then, you can add YARD comments to your code, following a specific syntax. For example
class Person
# Greets a person
#
# @param [String] name the name of the person
#
# @return [String] the greeting
def greet(name)
"Hello #{name}"
end
end
Once you have added YARD comments to your code,
generate the documentation site by running the yard
command. For example yard doc person.rb
.
This will generate the documentation site in the doc
directory.
You can run it locally using yard server
command
It is a list of static html files, so it can be hosted on any web server.
I have created a cheatsheet to remember the relevant tags
# Represents a generic document in a document management system.
# @abstract
# @author John Doe
# @since 1.0.0
# @deprecated Use NewDocument instead.
class Document
# @!attribute [r] title
# @return [String]
attr_reader :title
# @!attribute [w] description
# @return [String]
attr_writer :description
# @!attribute [rw] sections
# @api private
# @return [Array<Section>]
attr_accessor :sections
# Initializes a new Document instance.
# @note This method should be called with care.
#
# @param [String] title the title of the document
# @param [String] description the description of the document
# @param [Hash] options additional configuration options
# @option options [Boolean] :editable whether the document can be edited
# @yieldparam [String] content The content of the document.
# @yieldreturn [String] Returns a modified content.
#
# @raise [ArgumentError] if the title is nil
#
# @return [Document] a new Document instance
def initialize(title, description, options = {})
raise ArgumentError, "Title cannot be nil" unless title
@title = title
@description = description
@editable = options.fetch(:editable, true)
@content = yield(content) if block_given?
end
# Edits the document content.
#
# @overload edit(new_content)
# @param [String] new_content the new content for the document
# @return [Boolean] true if editing was successful, false otherwise
#
# @overload edit
# @yield Gives a block to process the current content.
# @yieldreturn [String] Returns the new content after processing.
# @return [Boolean] true if editing was successful, false otherwise
#
# @deprecated Use `modify` method instead.
def edit(new_content = nil)
if new_content
@content = new_content
true
elsif block_given?
@content = yield(@content)
true
else
false
end
end
# @todo Implement a proper save mechanism
def save
# Implementation pending
end
# Views the document
#
# @example Viewing the document title
# document.view_title #=> "Sample Document"
#
# @see #edit
# @return [String] the title of the document
def view_title
@title
end
end
This covers all the tags. It is available as gist.
YARD supports .yardopts
file to store configuration options. It can also used for custom tags.
I use custom tags to document Rails controller actions.
--tag url
--tag action
class DocumentsController < ApplicationController
# @url /documents
# @action GET
#
# List all documents.
#
def index
@documents = Document.all
end
# @url /documents/:id
# @action GET
#
# Show a single document.
#
def show
@document = Document.find(params[:id])
end
end
Since params
is not explicitly passed as an argument, you cannot use @param
and @option
to document them.
One of the method that the YARD author suggests to document these methods is to use @overload
tag.
# @overload show(params)
# @param params [Hash]
# @option params [String] :id the id of the document
def show
@document = Document.find(params[:id])
end
VSCode has a YARD extension that provides auto-completion for YARD tags.
It adds the documentation you hit Ctrl+Alt+Enter
(Option+Command+Enter
on macOS) when placing the cursor on the end of the method definition.
def foo(name, baz = false) # <- put cursor at any place of this line
end
It generates
#
# <Description>
#
# @param [<Type>] name <description>
# @param [<Type>] baz <description>
#
# @return [<Type>] <description>
#
def foo(name, baz = false)
end
I like using YARD because as you can see it’s easy to use, extensible and customizable. And after reading this, I hope you’re sold on it too! Happy documenting!