Add canonical interface checker#2
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new “canonical interface” comparison mode to DuckTyper, enabling N implementations to be checked directly against a single authoritative reference, with aggregated failures for easier diagnosis. This also refactors shared checker setup logic to reduce duplication between checkers.
Changes:
- Introduces
DuckTyper::CanonicalInterfaceChecker(+ aggregatedResult) and wires it into the main gem entrypoint. - Adds Minitest (
assert_canonical_interface_match) and RSpec (implement_canonical_interface) integrations for canonical checks. - Extracts shared initialization logic into
InterfaceSetupand factors common result-message helpers intoResultFormatting.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/duck_typer/canonical_interface_checker_test.rb | Adds unit tests for canonical checker behavior and messaging. |
| test/duck_typer/bulk_interface_checker_test.rb | Updates expected argument-validation error messages after refactor. |
| lib/duck_typer/rspec.rb | Adds implement_canonical_interface matcher. |
| lib/duck_typer/result_formatting.rb | Extracts shared failure-message helpers (interface_label, strict_note). |
| lib/duck_typer/objects_resolver.rb | Adds an objects/namespace resolution helper module. |
| lib/duck_typer/minitest.rb | Adds assert_canonical_interface_match helper. |
| lib/duck_typer/interface_setup.rb | Centralizes checker argument validation, object resolution, name inference, checker construction. |
| lib/duck_typer/interface_checker/result.rb | Reuses ResultFormatting and exposes diff_message for aggregation. |
| lib/duck_typer/canonical_interface_checker/result.rb | Implements aggregated failure message for canonical comparisons. |
| lib/duck_typer/canonical_interface_checker.rb | Implements canonical comparison loop against a reference class/module. |
| lib/duck_typer/bulk_interface_checker.rb | Refactors to use InterfaceSetup. |
| lib/duck_typer.rb | Requires canonical checker so it’s available when requiring duck_typer. |
| README.md | Documents canonical interface usage for Minitest and RSpec. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
122c1ad to
48389ac
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
MatheusRich
approved these changes
Apr 24, 2026
a31e411 to
d49d839
Compare
Pairwise comparison verifies that every adjacent pair of classes in a list agree with each other, which works well when all classes are peers with no single authoritative definition. Canonical interface comparison takes a different approach: one class is designated as the reference, and every other class is checked against it directly. This is useful when the interface already has a clear owner — an abstract base, a well-established implementation, or a purpose-built interface class — and you want to confirm that all other implementations conform to that definition. Because all comparisons share the same right-hand side, failures from multiple classes are aggregated into a single result, making it easier to see the full picture at a glance. - Adds `CanonicalInterfaceChecker`, which compares every class in a list against a single canonical reference rather than in consecutive pairs. All failures are aggregated into one result, so a single assertion reports every non-conforming class at once. - Exposes `assert_canonical_interface_match(canonical, objects, **opts)` in the Minitest integration and `implement_canonical_interface(canonical, **opts)` in the RSpec integration. All existing options (`type:`, `methods:`, `strict:`, `name:`, `namespace:`) are supported. - Extracts shared checker initialization (argument validation, object resolution, name inference, checker construction) into `InterfaceSetup`, eliminating duplication between `BulkInterfaceChecker` and `CanonicalInterfaceChecker`.
d49d839 to
096fd49
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pairwise comparison verifies that every adjacent pair of classes in a list agree with each other, which works well when all classes are peers with no single authoritative definition. Canonical interface comparison takes a different approach: one class is designated as the reference, and every other class is checked against it directly. This is useful when the interface already has a clear owner — an abstract base, a well-established implementation, or a purpose-built interface class — and you want to confirm that all other implementations conform to that definition. Because all comparisons share the same right-hand side, failures from multiple classes are aggregated into a single result, making it easier to see the full picture at a glance.
Adds
CanonicalInterfaceChecker, which compares every class in a list against a single canonical reference rather than in consecutive pairs. All failures are aggregated into one result, so a single assertion reports every non-conforming class at once.Exposes
assert_canonical_interface_match(canonical, objects, **opts)in the Minitest integration andimplement_canonical_interface(canonical, **opts)in the RSpec integration. All existing options (type:,methods:,strict:,name:,namespace:) are supported.Extracts shared checker initialization (argument validation, object resolution, name inference, checker construction) into
InterfaceSetup, eliminating duplication betweenBulkInterfaceCheckerandCanonicalInterfaceChecker.