Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,15 @@ gem:
doc: true
```

To generate documentation for all gems except specific ones, set `doc.exclude` to the gem names. This form enables documentation. The excluded gems still get RBI files, but comments from their source code are not copied into those files:

```yaml
gem:
doc:
exclude:
- irb
```

Additionally, if you always want to exclude the `AASM` and `ActiveRecordFixtures` DSL compilers in your DSL RBI generation runs, your config file would then look like this:

```yaml
Expand Down
6 changes: 5 additions & 1 deletion lib/tapioca/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ def gem(*gems)
raise MalformattedArgumentError, "Option '--verify' must be provided without any other arguments" if verify
end

doc = options[:doc]
doc_exclude = doc.is_a?(Hash) ? doc.fetch("exclude", []) : []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a --config flag which complicates things, imagine someone doing tapioca gem foo --doc --config sorbet/tapioca/config.yml and the config has exclude. In that case I think we should instead respect the exclude flag. We also need a test for this behaviour where they are used together.


command_args = {
gem_names: all ? [] : gems,
exclude: options[:exclude],
Expand All @@ -311,7 +314,8 @@ def gem(*gems)
typed_overrides: options[:typed_overrides],
outpath: Pathname.new(options[:outdir]),
file_header: options[:file_header],
include_doc: options[:doc],
include_doc: doc != false,
doc_exclude: doc_exclude,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that this hash, true or false setup reads better in the config.yml but I wonder if it's confusing since this defaults to doc: true and exclude: foo. Wdyt?

gem:
  doc:
    exclude:
    - foo

Compared to having

gem:
  doc: true
  exclude_doc:
  - foo

include_loc: options[:loc],
include_exported_rbis: options[:exported_gem_rbis],
number_of_workers: options[:workers],
Expand Down
5 changes: 4 additions & 1 deletion lib/tapioca/commands/abstract_gem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class AbstractGem < Command
#| include_doc: bool,
#| include_loc: bool,
#| include_exported_rbis: bool,
#| ?doc_exclude: Array[String],
#| ?number_of_workers: Integer?,
#| ?auto_strictness: bool,
#| ?dsl_dir: String,
Expand All @@ -40,6 +41,7 @@ def initialize(
include_doc:,
include_loc:,
include_exported_rbis:,
doc_exclude: [],
number_of_workers: nil,
auto_strictness: true,
dsl_dir: DEFAULT_DSL_DIR,
Expand Down Expand Up @@ -69,6 +71,7 @@ def initialize(
@existing_rbis = nil #: Hash[String, String]?
@expected_rbis = nil #: Hash[String, String]?
@include_doc = include_doc #: bool
@doc_exclude = doc_exclude #: Array[String]
@include_loc = include_loc #: bool
@include_exported_rbis = include_exported_rbis
@halt_upon_load_error = halt_upon_load_error
Expand All @@ -92,7 +95,7 @@ def compile_gem_rbi(gem)
rbi.root = Runtime.with_disabled_exits do
Tapioca::Gem::Pipeline.new(
gem,
include_doc: @include_doc,
include_doc: @include_doc && !@doc_exclude.include?(gem.name),
include_loc: @include_loc,
error_handler: ->(error) {
say_error(error, :bold, :red)
Expand Down
4 changes: 4 additions & 0 deletions lib/tapioca/commands/configure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ def create_tapioca_config
# exclude:
# - gem_name
# doc: true
# Or exclude documentation for specific gems:
# doc:
# exclude:
# - gem_name
# workers: 5
dsl:
# Add your `dsl` command parameters here:
Expand Down
18 changes: 17 additions & 1 deletion lib/tapioca/helpers/config_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,21 @@ def validate_config_options(command_options, config_key, config_options)
error_msg = "unknown option `#{config_option_key}` for key `#{config_key}`"
next build_error(error_msg) unless command_option

gem_doc_option = config_key.to_s == "gem" && config_option_key.to_s == "doc"
if gem_doc_option && config_option_value.is_a?(Hash)
unknown_key = config_option_value.keys.find { |key| key != "exclude" }
if unknown_key
next build_error("unknown option `#{unknown_key}` for option `doc` for key `#{config_key}`")
end

excluded_gems = config_option_value["exclude"]
next if excluded_gems.is_a?(Array) && excluded_gems.all? { |gem| gem.is_a?(String) }

error_msg = "invalid value for option `doc.exclude` for key `#{config_key}` - expected " \
"`Array[String]` but found `#{excluded_gems}`"
next build_error(error_msg)
end

config_option_value_type = case config_option_value
when FalseClass, TrueClass
:boolean
Expand All @@ -114,8 +129,9 @@ def validate_config_options(command_options, config_key, config_options)
:object
end

expected_type = gem_doc_option ? "Boolean or Hash" : command_option.type.capitalize
error_msg = "invalid value for option `#{config_option_key}` for key `#{config_key}` - expected " \
"`#{command_option.type.capitalize}` but found #{config_option_value_type.capitalize}"
"`#{expected_type}` but found #{config_option_value_type.capitalize}"
next build_error(error_msg) unless config_option_value_type == command_option.type

case config_option_value_type
Expand Down
43 changes: 42 additions & 1 deletion spec/tapioca/cli/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class ConfigTest < SpecWithProject

Configuration file sorbet/tapioca/config.yml has the following errors:

- invalid value for option doc for key gem - expected Boolean but found String
- invalid value for option doc for key gem - expected Boolean or Hash but found String
- invalid value for option typed_overrides for key gem - expected Hash but found Array
- invalid value for option workers for key gem - expected Numeric but found String
- invalid value for option exclude for key dsl - expected Array but found Boolean
Expand All @@ -96,6 +96,47 @@ class ConfigTest < SpecWithProject
refute_success_status(result)
end

it "validates invalid gem documentation exclusions" do
@project.write!("sorbet/tapioca/config.yml", <<~YAML)
gem:
doc:
exclude: irb
YAML

result = @project.tapioca("gem")

assert_stderr_equals(<<~ERR, result)

Configuration file sorbet/tapioca/config.yml has the following errors:

- invalid value for option doc.exclude for key gem - expected Array[String] but found irb
ERR

assert_empty_stdout(result)
refute_success_status(result)
end

it "validates unknown gem documentation options" do
@project.write!("sorbet/tapioca/config.yml", <<~YAML)
gem:
doc:
only:
- irb
YAML

result = @project.tapioca("gem")

assert_stderr_equals(<<~ERR, result)

Configuration file sorbet/tapioca/config.yml has the following errors:

- unknown option only for option doc for key gem
ERR

assert_empty_stdout(result)
refute_success_status(result)
end

it "validates invalid configuration option values inside arrays and hashes" do
@project.write!("sorbet/tapioca/config.yml", <<~YAML)
dsl:
Expand Down
42 changes: 42 additions & 0 deletions spec/tapioca/cli/gem_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ class GemSpec < SpecWithProject
include Tapioca::Helpers::Test::Template

FOO_RB = <<~RB
# Foo source documentation
module Foo
PI = 3.1415

# Foo method documentation
def self.foo(a = 1, b: 2, **opts)
number = opts[:number] || 0
39 + a + b + number
Expand Down Expand Up @@ -43,9 +45,11 @@ module Reopened; end
RBI

BAR_RB = <<~RB
# Bar source documentation
module Bar
PI = 3.1415

# Bar method documentation
def self.bar(a = 1, b: 2, **opts)
number = opts[:number] || 0
39 + a + b + number
Expand Down Expand Up @@ -270,6 +274,44 @@ def fizz; end
assert_success_status(result)
end

it "excludes source documentation for configured gems without excluding their RBIs" do
foo = mock_gem("foo", "0.0.1") do
write!("lib/foo.rb", FOO_RB)
end

bar = mock_gem("bar", "0.3.0") do
write!("lib/bar.rb", BAR_RB)
end

@project.require_mock_gem(foo)
@project.require_mock_gem(bar)
@project.bundle_install!
@project.write!("doc_config.yml", <<~YAML)
gem:
doc:
exclude:
- foo
YAML

result = @project.bundle_exec(
"tapioca gem foo bar --workers=1 --no-loc --config doc_config.yml",
{ "ENFORCE_TYPECHECKING" => "1" },
)

foo_rbi = @project.read("sorbet/rbi/gems/foo@0.0.1.rbi")
bar_rbi = @project.read("sorbet/rbi/gems/bar@0.3.0.rbi")

assert_includes(foo_rbi, "module Foo")
refute_includes(foo_rbi, "Foo source documentation")
refute_includes(foo_rbi, "Foo method documentation")
assert_includes(bar_rbi, "Bar source documentation")
assert_includes(bar_rbi, "Bar method documentation")
assert_empty_stderr(result)
assert_success_status(result)
ensure
@project.remove!("doc_config.yml")
end

it "must generate RBI for a default gem" do
gem_name = "singleton"
gem_top_level_constant = "module Singleton"
Expand Down
Loading