From b827ee5d9aa5562d316443164e4368a803bb0185 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 28 Sep 2026 21:21:09 +0900 Subject: [PATCH] docs: document typing policies and test conventions in CONTRIBUTING.md and stdlib.md --- docs/CONTRIBUTING.md | 12 ++++++++++++ docs/stdlib.md | 35 +++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index a6d970ea1..8dbdb3a05 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -101,7 +101,19 @@ end You are correct. We want to move to their repos. We haven't started the migration yet. +However, bundled gems listed in `ALUMNI_STDLIBS` in `lib/rbs/collection/config/lockfile_generator.rb` (such as `abbrev`, `benchmark`, `bigdecimal`, `csv`, and `logger`) maintain their RBS definitions in their upstream repositories (e.g., `ruby/csv`). Submit type improvements for those libraries to their respective repositories instead of `ruby/rbs`. + ### How can we handle incompatibilities of core APIs and standard libraries between Rubies We ignore the incompatibilities for now. We focus on the latest version of core APIs and standard libraries. + +* **Do not use union types to bridge Ruby versions**: Avoid patterns like `URI::RFC2396_Parser | URI::RFC3986_Parser`. Match the signature to the latest supported Ruby release. + +### Should we use `void` or `untyped` for method return values? + +Use `void` when callers should ignore or discard the return value. Use `untyped` only when the method returns an arbitrary object intended for use. (See [syntax guide](syntax.md#void-boolish-or-top)). + +### How do we avoid duplicate documentation when importing RDoc? + +When an extension library extends a core class (such as `time` extending `Time` or `random-formatter` extending `Random::Formatter`), `rbs annotate` can duplicate core class documentation. Add `%a{annotate:rdoc:skip}` to the module or class declaration to skip the duplicate docs. diff --git a/docs/stdlib.md b/docs/stdlib.md index ce974c200..ab86da2cd 100644 --- a/docs/stdlib.md +++ b/docs/stdlib.md @@ -124,7 +124,7 @@ It's clear having type aliases makes sense. #### 📣 Constant type assertions -We also have `assert_const_type` method, to test the type of constant is correct with respect to RBS type definition. +Use `assert_const_type` to test that a constant matches its RBS definition. ```ruby class FloatConstantTest < Test::Unit::TestCase @@ -138,12 +138,35 @@ end It confirms: -1. The type of constant `Float::INFINITY` is `Float` -2. The type of constant `Float::INFINITY` is correct with respect to RBS definition +1. The constant `Float::INFINITY` is a `Float` at runtime. +2. The type matches its RBS definition. -We don't have any strong recommendation about where the constants test should be written in. -The `FloatConstantTest` example defines a test case only for the constant tests. -You may write the tests inside `FloatInstanceTest` or `FloatSingletonTest`. +When testing class and exception constants, assert that their type is `"Class"`: + +* **Good:** `assert_const_type "Class", "StringScanner::Error"` +* **Bad:** `assert_const_type "singleton(::StringScanner::Error)", "StringScanner::Error"` + +You can place constant tests inside existing `*SingletonTest` or `*InstanceTest` classes, or define a `*ConstantTest` class. + +#### 📣 Write Type Tests, Not Behavior Tests + +Stdlib tests verify that RBS signatures match runtime method types. Do not test Ruby implementation behavior. + +* **Use `assert_send_type` and `assert_const_type`**: Verify arguments, return values, and constants through type assertions. +* **Skip behavior assertions**: Drop `assert_equal`, `assert_instance_of`, and `assert` for return values, superclasses, and constant contents: + * **Bad:** `assert_equal StandardError, StringScanner::Error.superclass` + * **Bad:** `assert_equal "A", Random::Formatter::ALPHANUMERIC.first` + * **Good:** `assert_const_type "Array[String]", "Random::Formatter::ALPHANUMERIC"` + Reserve `assert_equal` and `assert` for test setup. +* **Ignore untestable behavior**: If a method behavior has no corresponding type check (such as `Singleton.instance` object identity), test only the method signature and return type. + +#### 📣 Extending Existing Tests + +When updating existing library tests: + +1. **Check existing tests first**: Open `test/stdlib/_test.rb`. +2. **Add to existing test classes**: Put new tests in `*InstanceTest`, `*SingletonTest`, or `*ConstantTest`. Do not create duplicate test classes. +3. **Preserve existing coverage**: Keep existing test cases intact. ### Running tests