In a Ruby gem, how do RDoc's :nodoc: and :doc: directives and YARD's @api private tag control which methods appear in the documentation?
answer
- trailing comment on the def line
- RDoc default visibility: protected
- :nodoc: all for nested classes
- :stopdoc: ... :startdoc: regions
- --hide-api private, --no-private
basics
~20 sRDoc documents public and protected methods by default; a trailing # :nodoc: hides a definition and # :doc: forces one in, such as a private method. YARD ignores those directives and uses @api private or @private with --hide-api private or --no-private.
solid answer
~40 sRDoc's `--visibility` defaults to `protected`, so public and protected methods are documented and private ones are not. Appending `# :nodoc:` to a `def`, `class`, constant or `attr_*` line hides that object; on a class, nested classes are still documented unless you write `:nodoc: all`. Appending `# :doc:` forces an object in even when it would otherwise be skipped, typically a private method. `:stopdoc:`/`:startdoc:` hide a region, `:enddoc:` hides the rest of the file, and `#--`/`#++` cut an internal note out of a comment. YARD does not act on these directives: by default it shows **public** methods only (`--protected`, `--private` add more), and internal but technically public objects are tagged `@api private`, which shows a notice and can be removed with `--hide-api private`, or `@private` together with `--no-private`.
code
ruby · 13 linesmodule GeoLookup
class Cache # :nodoc: all
class Entry # hidden too, because of "all"
end
end
class Client
# Signs each request with the account key.
def sign(params) # :doc:
end
private :sign
end
endgo deeper
Recall that # :nodoc: after a definition hides it from RDoc and that private methods are skipped by default.
Explain RDoc's protected default visibility, :doc: for private methods, :nodoc: all for nested classes, and region directives like :stopdoc: and #--.
Show the YARD side: public-only by default, @api private with --hide-api private, @private with --no-private, and why RDoc directives do nothing under yard doc.
Frame the policy: documentation visibility defines the supported API surface, so a team should mark internal classes consistently and treat anything documented as a compatibility promise.
## The problem A gem's public API is smaller than the set of methods Ruby calls public. `GeoLookup::Client#geocode` is API; `GeoLookup::HttpAdapter`, a helper class every file uses, is public in Ruby terms but is not something users should call. Documentation has to draw that line, and RDoc and YARD draw it with different mechanisms. ## RDoc's default and its switches RDoc documents by **visibility**. Its `--visibility` option takes `public`, `protected` (**the default**), `private` or `nodoc`, and it means "the minimum visibility to document": - With the default, public and protected methods appear, private ones do not. - `rdoc --all` (or `-a`) is a synonym for `--visibility=private`. - `--visibility=nodoc` shows everything, including objects marked `:nodoc:`. ## RDoc directives on a definition line **Directives** are words between colons that RDoc reads from comments. Three of them are written as a **trailing comment on the line that defines** the object: | Directive | Effect | |---|---| | `:nodoc:` | do not document this class, module, method, alias, constant or attribute | | `:nodoc: all` | on a class or module, also hide the nested classes and modules | | `:doc:` | document this object even if it would otherwise be skipped | | `:notnew:` | on `initialize`, do not document the implied `new` | The `all` argument matters: by default, a nested class inside a `:nodoc:` class **is** still documented. `:doc:` is the reverse switch. Because `initialize` and other private methods are skipped by default, a private method you want readers to see needs `# :doc:`. ## RDoc directives for regions Other directives stand on a line of their own: 1. `# :stopdoc:` stops documenting until the next `# :startdoc:`. 2. `# :enddoc:` stops documenting for the rest of the file, whatever follows. 3. `#--` ... `#++` inside a comment hides the lines between them, handy for a maintainer's note that should not reach users. ## YARD's approach YARD does not implement RDoc's `:nodoc:`; its WhatsNew notes say `@private` is not meant to be an equivalent of it, and it recommends documenting private objects too. Instead: - `yard doc` shows **public** methods by default; `--protected` and `--private` add those visibilities. - `@api private` marks an object as internal API. The HTML shows a notice that it is not for external use, and `yard doc --hide-api private` leaves such objects out. - `@private` marks something Ruby cannot make private itself, and `--no-private` hides everything tagged with it. For constants, YARD's own docs point to `private_constant` as the better tool. - `@api` is **transitive**: tagging a module applies it to the objects inside it unless they say otherwise. ## Which to use for the geocoding gem ```ruby module GeoLookup class HttpAdapter # :nodoc: end # @api private class ResponseParser end class Client private def sign_request(params) # :doc: end end end ``` - For an RDoc-built gem, `:nodoc:` removes `HttpAdapter`, and `:doc:` publishes the private `sign_request` because it explains the signing scheme. - For a YARD-built gem, the `:nodoc:` comment has no effect; `@api private` plus `--hide-api private` in `.yardopts` removes `ResponseParser`. ## Common mistakes - Expecting `:nodoc:` on a namespace to hide the classes nested inside it. - Assuming YARD honours RDoc directives because it reads RDoc-style comments. - Using `:nodoc:` to hide an object users do depend on, which leaves them reading source to learn the API.
- Why does RDoc still show `new` for a class whose `initialize` is private?RDoc fakes a documented singleton `new` from `initialize`, because that is how callers create the object even though `initialize` itself is private. Appending `# :notnew:` to the `def initialize` line tells RDoc not to document that implied `new`.
- How would you hide an internal note from a method's RDoc comment without deleting it?Wrap it in `#--` and `#++`: RDoc stops reading at `#--` and resumes after `#++`, so the lines between stay in the source for maintainers but never reach the rendered docs. It is shorthand for `:stopdoc:` and `:startdoc:` inside Ruby comments.
saying these in an interview costs you the question
- RDoc documents private methods by default.
- :nodoc: on a class automatically hides every class nested inside it.
- YARD honours RDoc's :nodoc: comments the same way RDoc does.
- @api private makes the method private at runtime.
- Private methods can never appear in RDoc output.
- The only way to hide a helper is to make it private in Ruby.