yard icon indicating copy to clipboard operation
yard copied to clipboard

Licensing comments, standardrb, and top-level module documentation

Open dmlary opened this issue 1 year ago • 2 comments

This issue is a confluence of multiple pieces (SPDX licensing comments & standardrb) that is resulting in yard replacing top-level module documentation with required licensing comments. I'm hoping there is some workaround to allow me to write the top-level module documentation in the top-level file.

Problem description

First off the layout of the project is something like this:

lib/my_module.rb
lib/my_module/my_class.rb
# 30+ more classes in the MyModule namespace

At the top of each file is SPDX^1 licensing comment:

# SPDX-FileCopyrightText: 2025 Company Name
# SPDX-License-Identifier: MIT

The contents of the top-level file (lib/my_module.rb) is:

# SPDX-FileCopyrightText: 2025 Company Name
# SPDX-License-Identifier: MIT

require_relative "my_module/my_class"

# This is the documentation for MyModule
# @example
#    ...
module MyModule
end

All classes and modules within the gem are declared as follows so they can easily access things in the MyModule namespace.

# SPDX-FileCopyrightText: 2025 Company Name
# SPDX-License-Identifier: MIT

module MyModule
  # This is the documentation for MyClass
  # @example using MyClass
  class MyClass
  end
end

Running yard doc in that repo, the documentation for MyModule written in lib/my_module.rb is replaced with the license block from lib/my_module/my_class.rb. In reality it's replaced with an obscure file about 5 levels lower, and not the last file required.

Using the --load script described in https://github.com/lsegal/yard/issues/1173#issuecomment-400428506 I'm able to see that in my codebase, the top-level module documentation is being overwritten with an obscure file four directories below the top-level module source file.

Attempted work-around or standardrb gets in the way

I found in some old issue that yard will ignore higher blocks of comments if you separate them with two newlines. I tried it, and standardrb immediately deleted the two blank lines because extra blank lines are not permitted^2.

Suggested solution

Is there any way to expand the ignored comment selection used for encoding: and frozen_string_literal: comments to include SPDX license comments?

dmlary avatar Feb 17 '25 17:02 dmlary

Is there any way to expand the ignored comment selection used for encoding: and frozen_string_literal: comments to include SPDX license comments?

This is very unlikely. encoding and frozen_string_literal are Ruby concepts as part of the Ruby syntax and grammar. Also: they are encoded into the parsed file. SPDX is just text-based metadata. Ignoring it would be unwise, as you could very well expect a yard-spdx type plugin to want to parse this data and attribute it in some user-specific way. Parsing it would require YARD to fully adopt the SPDX spec and provide a first-class API rather than allowing plugins to parse data in its own way. Candidly, there's pretty much no interest for YARD to provide such an API, since SPDX already duplicates much of what is already available in YARD, namely, metadata tags for structured data.

The tl;dr here is that this is a standardrb issue. Standardrb is a very specific formatter that, if it does not support this syntax, is seemingly incompatible with YARD, period. YARD expects Ruby source files to allow \n\n\n separators, a convention which long predates the existence of standardrb (and rubocop). You should probably open an issue with standardrb to have the discussion there.

I would hope that a tool whose goal is to format "Standard Ruby" would acknowledge the existence of standardized documentation tooling. You could make the argument that YARD is, or isn't, a standard tool, but ultimately that's up to standardrb.

That said, I see two potential hacky workarounds, both of which YMMV:

  1. Move SPDX to the bottom of the source file-- or anywhere other than the top. I see nothing in the SPDX specification that requires them at the top of a file. The only specific language I found in a third-party doc says "near the top of the file", but not actually the top. I have no clue what tools you are using to parse this metadata, but I would assume given the lack of specification on this it should be able to support various locations that are not above the module definition line.
  2. Create a fake method or reuse some shared module name and place that method/module name below the SPDX comments to change how they get attached:
# lib/mylib.rb
# This is defined in your toplevel source so it's accessible to subsequent sources
module MyModule
  # You could also use `module` here to avoid possible linter warnings on capitalized methods
  # @private
  def self.Copyright; end
end

# SPDX-License-Identifier: MIT
MyModule::Copyright

module MyModule
  ...
end

This is likely not ideal but should unblock until you can get formatting issues sorted. You could also obviously just switch to Rubocop which gives you more control over formatting (specifically disabling these rules or tweaking Layout/EmptyLinesAroundModuleBody), but I'm guessing that was already a non-starter.

lsegal avatar Feb 18 '25 02:02 lsegal

Thank you for taking the time to provide an in-depth response; I appreciate it.

For your workarounds:

  1. I'm asking internally if license blocks at the bottom are acceptable
  2. Hmm, that's a clever workaround, but I'd like to avoid it unless absolutely necessary. It's too much of an incantation for me to be comfortable adding it.

I have reached out to standardrb to start a conversation about finding some way to allow separation of license comment blocks^1.

On the yard side of things, would you accept a PR that adds functionality to break documentation blocks at "\n\n" guarded behind a command-line flag?

dmlary avatar Feb 18 '25 17:02 dmlary