Skip to content
| Marketplace
Sign in
Visual Studio Code>Snippets>YARD DocumenterNew to Visual Studio Code? Get it now.
YARD Documenter

YARD Documenter

Vitaly Pavlitsky

|
32,095 installs
| (3) | Free
Document Ruby source code with YARD
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

YARD Documenter

Extension generates YARD documentation comments for Ruby source code.

See Readme for more information on this tool.

Features

Extension automatically prepends definitions of methods, classes etc with documentation snippets. No need to remember a formatting tags and styling, just type and describe your code.

It's able to document:

  • Methods: instance methods, initializers, class methods.
  • Blocks accepted by methods (optional, see yard.tags.yield setting).
  • Exceptions raised in methods (optional, see yard.tags.raise setting).
  • Methods overloaded by rbs-inline annotations (optional, see yard.tags.overload setting).
  • Abstract methods raising NotImplementedError.
  • Deprecated methods warning about their deprecation.
  • Definitions hidden from RDoc with # :nodoc:, with @private tag.
  • TODO notes written in methods, with @todo tags (optional, see yard.tags.todo setting).
  • Methods overriding methods of a superclass, with @see tags (optional, see yard.tags.see setting).
  • Version of a gem new definitions are added in, with @since tag (optional, see yard.tags.since setting).
  • Classes and Modules.
  • Constants.
  • Attributes accessors (attr_reader, attr_writer, attr_accessor and more).
  • Struct and Data classes (Point = Struct.new(:x, :y), Point = Data.define(:x, :y)).
  • Methods and attributes YARD doesn't see, with @!method and @!attribute directives: define_method, delegated methods (delegate, def_delegators), Rails scopes, associations and class attributes (class_attribute, cattr_accessor, mattr_reader), methods of ActiveSupport::Concern blocks (included do, class_methods do).

Methods named in ASCII and Japanese are supported.

YARD tags are completed in comments, see Tags completion.

Usage

Position cursor on a first line of a definition you wish to document.

def foo(bar, baz = false) # <- put cursor at any place of this line
end

Hit Ctrl+Alt+Enter (Option+Command+Enter on macOS) or invoke Document with YARD from the command palette.

  #
  # <Description>
  #
  # @param bar [<Type>] <description>
  # @param baz [Boolean] <description>
  #
  # @return [<Type>] <description>
  #
  def foo(bar, baz = false)
  end

Documentation snippet appears on top of the method.

Use Tab and Shift+Tab keys to navigate and fill in placeholders.

  #
  # An example instance method description.
  #
  # @param bar [Integer] first param used for demonstration
  # @param baz [Boolean] second param with a default value
  #
  # @return [nil] nothing returned so it's always nil
  #
  def foo(bar, baz = false)
  end

Done!

Updating documentation

Run the same command on a documented method, with cursor on the method definition or anywhere within its comment, to sync documentation with the code. Texts and tags are kept as they're written, missing tags are added as placeholders:

  • Params are reordered to match the method signature. A param which no longer exists is renamed if a new param takes its place, otherwise it's removed.
  • Missing @abstract, @deprecated, @private, @param, @option, @overload, @yield, @yieldparam, @yieldreturn, @raise, @return, @see and @todo tags are added. Documented exceptions are kept even if a method doesn't raise them.
  • New tags follow the params style of the existing documentation.
#
# Fetch a resource.
#
# @param [String] path resource path
# @param [Integer] retries how many times to retry
#
# @note Raises on timeout.
#
def fetch(url, timeout, retries = 3)
end

becomes

#
# Fetch a resource.
#
# @param [String] url resource path
# @param [<Type>] timeout <description>
# @param [Integer] retries how many times to retry
#
# @return [<Type>] <description>
#
# @note Raises on timeout.
#
def fetch(url, timeout, retries = 3)
end

Documentation of classes, modules, constants, attributes and directives isn't updated.

Tags completion

Type @ in a comment to complete YARD tags. Tags missing in documentation of a definition right below the comment are offered first: undocumented params with their options, block tags, return value, exceptions raised in a method body, author of a class. Standard YARD tags follow them.

# Fetch a resource.
#
# @param [String] url resource path
# @           <- offers @param retries, @param opts, @yield [response], @return,
#                @raise [ArgumentError], then standard tags like @note, @example
def fetch(url, retries = 3, opts = { timeout: 5 })
  raise ArgumentError, "bad url" unless url
  yield response
end

Names are completed after a typed tag: undocumented params after @param , block values after @yieldparam , option keys after @option and exception classes after @raise .

Another snippets examples, default spacers setup:

#
# Class to retry and fail.
#
# @author Author Name <author@example.com>
#
class Foo
  # @return [Integer] count of retries performed before failing
  RETRIES_COUNT=3

  # @return [Boolean] retry operation result
  attr_accessor :succeed

  #
  # Retry something.
  #
  # @return [Boolean] processing result, true if succeed
  #
  def retry
    RETRIES_COUNT.times { puts 'Retrying...' }
    @succeed = false
  end
end

Minimal setup:

# Class to retry and fail.
class Foo
  # @return [Integer] count of retries performed before failing
  RETRIES_COUNT=3

  # @return [Boolean] retry operation result
  attr_accessor :succeed

  # Retry something.
  # @return [Boolean] processing result, true if succeed
  def retry
    RETRIES_COUNT.times { puts 'Retrying...' }
    @succeed = false
  end
end

Feel free to append any needed tags like @note, @example, @see manually after snippet filled in.

Details

Source code is parsed with Prism, the Ruby's own parser, so definitions spanning multiple lines and any Ruby syntax are supported. Requires VS Code 1.90 or newer.

List of generated tags: @abstract, @attr, @attr_reader, @author, @deprecated, @option, @overload, @param, @private, @raise, @return, @see, @since, @todo, @yield, @yieldparam, @yieldreturn. Generated directives: @!attribute, @!method.

@author name and email are taken from git config (user.name and user.email) of the repository the document belongs to, or from global git config if it's outside of a repository. Placeholders are inserted when values can't be resolved.

Splat and block params are named without *, ** and & the same way YARD names them, their types are prefilled with Array<Object>, Hash{Symbol => Object} and Proc. Anonymous splats and arguments forwarding (...) aren't documented since YARD doesn't list them.

Types declared by a Sorbet signature or an rbs-inline annotation are filled in for params, block params, block return value and return value. Sorbet's and RBS types are written as YARD types: T.nilable(String) and String? are String, nil, T::Array[Integer] and Array[Integer] are Array<Integer>, T::Boolean and bool are Boolean, T.untyped and untyped are Object, .void and void are void and so on. Splat params are declared with types of their elements, they're documented as Array<...> and Hash{Symbol => ...}.

Documentation goes above Sorbet sig, the same way yard-sorbet expects it, put cursor on either sig or def line. A method declared abstract gets @abstract tag, attr_reader and other attributes get their types from sig too:

#
# <Description>
#
# @param url [String] <description>
# @param retries [Integer, nil] <description>
#
# @return [Boolean] <description>
#
sig { params(url: String, retries: T.nilable(Integer)).returns(T::Boolean) }
def fetch(url, retries = nil)
end

rbs-inline #: annotation stays right above a method, documentation goes above it. A method type is read from a single #: annotation or # @rbs (...) -> ... comment, see Overloads for methods with several of them. Types of single params are read from # @rbs name: Type comments:

#
# <Description>
#
# @param url [String] <description>
# @param tags [Array<Symbol>] <description>
#
# @return [String, nil] <description>
#
#: (String url, *Symbol tags) -> String?
def fetch(url, *tags)
end

Otherwise types are prefilled as placeholders when they're known, so they can be kept or typed over:

  • Types of params and options with literal default values: retries = 3 is Integer, opts = {} is Hash, format: :json is Symbol, cache = Set.new is Set, parent = nil is Object, nil.

  • Return types of methods returning literal values, both the last expression and explicit return values are looked through, including if and unless branches:

    # @return [Record, nil] <description>
    def record
      return nil if @id.nil?
      Record.new(@id)
    end
    
  • Otherwise return types of conventional methods: predicates (valid?) and comparisons (==, <, >= etc.) return Boolean, conversions return their classes (to_s and inspect return String, to_h returns Hash, to_i returns Integer and so on), size, length, count and hash return Integer, <=> and =~ return Integer, nil.

Options hash params, which are params with a hash default value (opts = {}) or keyword splats (**opts), get an @option tag for each symbol key found in the default hash or read in the method body (opts[:key], opts.fetch(:key, default), opts[:key] || default etc.). A default value is shown when it's known:

#
# <Description>
#
# @param url [<Type>] <description>
# @param opts [Hash] <description>
# @option opts [Integer] :timeout (5) <description>
# @option opts [Integer] :limit (10) <description>
#
# @return [<Type>] <description>
#
def fetch(url, opts = { timeout: 5 })
  limit = opts.fetch(:limit, 10)
end

Blocks are documented when yard.tags.yield setting is enabled. Method body is looked through for yield, block_given? and calls of an explicit &block param, values passed to the block become @yieldparam tags:

#
# <Description>
#
# @param prefix [<Type>] <description>
#
# @yield [key, value] <description>
# @yieldparam key [<Type>] <description>
# @yieldparam value [<Type>] <description>
# @yieldreturn [<Type>] <description>
#
# @return [<Type>] <description>
#
def each_pair(prefix)
  @items.each { |key, value| yield key, value }
end

An explicit &block param is documented with these tags instead of @param. When a passed value isn't a plain local variable (for example yield @items.first) its name is left as a placeholder, filled in once for both @yield and @yieldparam.

Exceptions raised in a method body get a @raise tag each, when yard.tags.raise setting is enabled (it's on by default). Exceptions are detected in raise and fail calls with a class (raise ArgumentError, raise ArgumentError, "message", raise Net::ReadTimeout.new(...)), raising a message is documented as RuntimeError. A bare re-raise and exceptions raised in nested method definitions are skipped:

#
# <Description>
#
# @param url [<Type>] <description>
#
# @raise [ArgumentError] <description>
# @raise [RuntimeError] <description>
#
# @return [<Type>] <description>
#
def fetch(url)
  raise ArgumentError, "bad url" unless url
  fail "empty url" if url.empty?
rescue IOError
  raise
end

A method whose body only raises NotImplementedError is documented as abstract with an @abstract tag, NotImplementedError isn't listed with @raise then:

#
# <Description>
#
# @abstract <description>
#
# @param request [<Type>] <description>
#
# @return [<Type>] <description>
#
def call(request)
  raise NotImplementedError, "#{self.class} must implement #{__method__}"
end

A method warning about its deprecation is documented with a @deprecated tag. Deprecation warnings are warn calls with a message mentioning a deprecation or with category: :deprecated, and warn calls of deprecators like ActiveSupport::Deprecation.warn or MyGem.deprecator.warn:

#
# <Description>
#
# @deprecated <description>
#
# @param url [<Type>] <description>
#
# @return [<Type>] <description>
#
def old_fetch(url)
  warn "old_fetch is deprecated, use fetch instead"
  fetch(url)
end

A method, a class, a module, a constant or an attribute hidden from RDoc with a # :nodoc: comment trailing its first line is documented with a @private tag, YARD doesn't read RDoc's directive. It's hidden from YARD documentation generated with --no-private option:

#
# <Description>
#
# @private
#
# @return [<Type>] <description>
#
def internal_state # :nodoc:
end

TODO notes written in comments within a method get a @todo tag each, when yard.tags.todo setting is enabled. Notes are comments starting with TODO, FIXME, XXX, HACK or OPTIMIZE, written on their own lines or trailing code. Updating documentation adds tags of undocumented notes, documented notes are kept:

#
# <Description>
#
# @param url [<Type>] <description>
#
# @return [<Type>] <description>
#
# @todo retry on timeout
# @todo handle redirects
#
def fetch(url)
  # TODO: retry on timeout
  get(url) # FIXME handle redirects
end

A method calling super refers to the method it overrides with a @see tag, when yard.tags.see setting is enabled. YARD doesn't link overridden methods, and documentation of a method isn't inherited once it's documented. The overridden method is looked up in a superclass written as a constant, methods of class << self and def self.name methods refer to class methods. Methods of modules and blocks don't get the tag, super goes to an unknown ancestor there:

class Admin < Base::User
  #
  # <Description>
  #
  # @return [<Type>] <description>
  #
  # @see Base::User#name
  #
  def name
    super.upcase
  end
end

New documentation of methods, classes, modules, constants and attributes ends with a @since tag, when yard.tags.since setting is enabled. Its version is a placeholder prefilled with a version of the gem a document belongs to, so it can be kept or typed over with a next version. The gem is the nearest directory with a gemspec up from the document, version is read from the gemspec (spec.version = "1.4.0") or from VERSION constant of lib/**/version.rb. Updating documentation doesn't add @since tag, existing definitions aren't new:

#
# <Description>
#
# @return [<Type>] <description>
#
# @since 1.4.0
#
def fetch
end

Overloads

A method with several rbs-inline method types, written as several #: annotations or as # @rbs (...) -> ... comment followed by # | (...) -> ... lines, gets an @overload tag for each method type when yard.tags.overload setting is enabled. Otherwise its tags aren't typed. Params of an overload are named after the method params they match by position or by keyword name, otherwise after names written in the method type. Unknown names are placeholders filled in together with the param tag:

#
# <Description>
#
# @overload find(id)
#   @param id [Integer] <description>
#   @return [User] <description>
# @overload find(<name>, limit = <default>)
#   @param <name> [String] <description>
#   @param limit [Integer] <description>
#   @return [Array<User>] <description>
#
#: (Integer id) -> User
#: (String, ?Integer limit) -> Array[User]
def find(*args)
end

Updating documentation adds overloads if a method has none of them documented, documented overloads are kept as they're written. Documentation with params or return value documented without overloads is updated the usual way.

Directives

Methods and attributes defined by calls aren't seen by YARD unless they're documented with @!method and @!attribute directives, their documentation is nested in a directive:

# @!method greet(name, greeting = "Hello")
#   <Description>
#   @param name [<Type>] <description>
#   @param greeting [String] <description>
#   @return [String] <description>
define_method(:greet) do |name, greeting = "Hello"|
  "#{greeting}, #{name}"
end
  • define_method and define_singleton_method with a block or a lambda are documented the same way methods are.

  • Each method delegated with Rails delegate (including its prefix: option) and Forwardable's def_delegators and def_delegator gets its own @!method directive.

  • Rails scope is documented as a class method returning ActiveRecord::Relation.

  • Rails has_many, has_one, belongs_to and has_and_belongs_to_many are documented with @!attribute [rw] directives. Their types are guessed from association names or class_name: options: has_many :categories returns ActiveRecord::Associations::CollectionProxy<Category>, belongs_to :author, class_name: "User", optional: true returns User, nil.

  • Rails class attributes defined with class_attribute, cattr_* and mattr_* get an @!attribute directive each, named with self. the way YARD tells class attributes: cattr_accessor :host is documented with @!attribute [rw] self.host.

  • YARD doesn't look into included do, prepended do and class_methods do blocks of ActiveSupport::Concern, even comments within them are lost. Documenting the block puts directives above it: @!method for each method, methods of class_methods are class methods, @!attribute for each attribute, and directives of scopes, associations and delegated methods. Methods following private or protected aren't documented.

    # @!attribute [rw] comments
    #   <Description>
    #   @return [ActiveRecord::Associations::CollectionProxy<Comment>] <description>
    # @!method publish(at = Time.now)
    #   <Description>
    #   @param at [<Type>] <description>
    #   @return [<Type>] <description>
    included do
      has_many :comments
    
      def publish(at = Time.now)
      end
    end
    

Struct and Data classes assigned to constants are documented as classes, YARD reads types of their members from @attr and @attr_reader tags. class Point < Struct.new(:x, :y) gets @attr tags too:

#
# <Description>
#
# @attr x [<Type>] <description>
# @attr y [<Type>] <description>
#
Point = Struct.new(:x, :y)

Configuration

Insertion of empty lines are configurable to make it able to tune between a curt and verbose documentation styles. Settings are listed with their default values:

{
  "yard.spacers.beforeDescription": true, // Prepend an empty line to descriptive texts
  "yard.spacers.afterDescription": true, // Append an empty line to descriptive texts
  "yard.spacers.beforeTags": true, // Prepend an empty line to all method's tags
  "yard.spacers.separateTags": true, // Separate method's tags of the same name (@params and @return) with an empty line
  "yard.spacers.afterTags": true, // Append an empty line to all method's tags
  "yard.spacers.beforeSingleTag": false, // Prepend an empty line to directives or single tags (for example constants)
  "yard.spacers.afterSingleTag": false, // Append an empty line to directives or single tags (for example constants)
  "yard.tags.author": false, // Append @author tag to Class and Module documentation
  "yard.tags.authorFromGit": true, // Fill @author name and email from git config (user.name and user.email)
  "yard.tags.yield": false, // Document blocks of methods with @yield, @yieldparam and @yieldreturn tags
  "yard.tags.raise": true, // Document exceptions raised in methods with @raise tags
  "yard.tags.overload": false, // Document methods overloaded by rbs-inline annotations with @overload tags
  "yard.tags.see": false, // Refer to methods of superclasses overridden by methods calling super with @see tags
  "yard.tags.since": false, // Append @since tag to new documentation, prefilled with a version of a gem
  "yard.tags.todo": false, // Document TODO, FIXME, XXX, HACK and OPTIMIZE notes written in method bodies with @todo tags
  "yard.tags.paramNameBeforeType": true, // Print param name before its type (for example '@param username [String]')
  "yard.completion.enabled": true // Complete YARD tags in comments
}

Troubleshooting

If hotkey isn't working open VS Code Keyboard Shortcuts and check for keybinging conflicts.

This also may happen if a documented definition isn't a method or its documentation is up to date. In this case extension silently does nothing.

Methods with syntax errors in their signature, for example def foo(bar, baz qux), aren't documented, a status bar message tells about it. Fix the signature and run the command again.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft