Skip to content

Commit 3ecfba8

Browse files
omarqureshiclaude
andcommitted
test(compliance): closure-to-single-method-interface coercion case
Languages with native closure-to-interface conversion (Java lambdas, and now Ruby via Jsii::Utils.coerce_callable) can accept a bare closure where a behavioral single-method interface is expected. Adds the suite case, the Ruby spec exercising lambda / named-hash / static-call-site forms end-to-end through the kernel, and the regenerated matrix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a430463 commit 3ecfba8

3 files changed

Lines changed: 26 additions & 6 deletions

File tree

gh-pages/content/specification/6-compliance-report.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
This section details the current state of each language binding with respect to our standard compliance suite.
66

77

8-
| number | test | java (97.56%) | golang (78.86%) | dotnet (n/a) | python (n/a) | ruby (100.00%) |
8+
| number | test | java (96.77%) | golang (78.23%) | dotnet (n/a) | python (n/a) | ruby (100.00%) |
99
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -------------------------------------------- | ------------ | ------------ | -------------- |
1010
| 1 | asyncOverrides_overrideCallsSuper | 🟢 | [🔴](https://github.com/aws/jsii/issues/2670) | n/a | n/a | 🟢 |
1111
| 2 | [arrayReturnedByMethodCanBeRead]("Array created in the kernel can be queried for its elements") | 🟢 | 🟢 | n/a | n/a | 🟢 |
@@ -125,8 +125,9 @@ This section details the current state of each language binding with respect to
125125
| 116 | subclassing | 🟢 | 🟢 | n/a | n/a | 🟢 |
126126
| 117 | testInterfaces | 🟢 | 🟢 | n/a | n/a | 🟢 |
127127
| 118 | [callbackParameterIsInterface]("Validates pure interfaces can be passed to callbacks") || 🟢 | n/a | n/a | 🟢 |
128-
| 119 | [classCanBeUsedWhenNotExpressedlyLoaded]("Validates that types not explicitly loaded by the user can safely be returned by JS code") | 🟢 | 🟢 | n/a | n/a | 🟢 |
129-
| 120 | [downcasting]("Ensures unsafe-cast features work as expected") || 🟢 | n/a | n/a | 🟢 |
130-
| 121 | [strippedDeprecatedMemberCanBeReceived]("Ensures --strip-deprecated does not cause odd runtime errors") | 🟢 | 🟢 | n/a | n/a | 🟢 |
131-
| 122 | [exceptionMessage]("Verifies that custom exception names are correctly forwarded") | 🟢 | 🟢 | n/a | n/a | 🟢 |
132-
| 123 | [voidReturningAsync]("Verifies that returning Promise<void> is correctly handled") ||| n/a | n/a | 🟢 |
128+
| 119 | [closureImplementsSingleMethodInterface]("Language-native closures/lambdas can be passed where a behavioral single-method interface is expected") ||| n/a | n/a | 🟢 |
129+
| 120 | [classCanBeUsedWhenNotExpressedlyLoaded]("Validates that types not explicitly loaded by the user can safely be returned by JS code") | 🟢 | 🟢 | n/a | n/a | 🟢 |
130+
| 121 | [downcasting]("Ensures unsafe-cast features work as expected") || 🟢 | n/a | n/a | 🟢 |
131+
| 122 | [strippedDeprecatedMemberCanBeReceived]("Ensures --strip-deprecated does not cause odd runtime errors") | 🟢 | 🟢 | n/a | n/a | 🟢 |
132+
| 123 | [exceptionMessage]("Verifies that custom exception names are correctly forwarded") | 🟢 | 🟢 | n/a | n/a | 🟢 |
133+
| 124 | [voidReturningAsync]("Verifies that returning Promise<void> is correctly handled") ||| n/a | n/a | 🟢 |

packages/@jsii/ruby-runtime-test/spec/compliance/interfaces_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,20 @@ def your_turn(bell)
238238
expect(consumer.when_typed_as_class(concrete_bell_ringer)).to be true
239239
end
240240

241+
it 'coerces closures into single-method interfaces', compliance: 'closureImplementsSingleMethodInterface' do
242+
consumer = JsiiCalc::ConsumerCanRingBell.new
243+
244+
# Bare lambda where IBellRinger (single abstract method) is expected;
245+
# the JS side calls back into it via the ordinary overrides path.
246+
expect(consumer.implemented_by_object_literal(->(bell) { bell.ring })).to be true
247+
248+
# Named single-entry hash form, equivalent to the lambda.
249+
expect(consumer.implemented_by_object_literal({ your_turn: ->(bell) { bell.ring } })).to be true
250+
251+
# Static call sites coerce the same way.
252+
expect(JsiiCalc::ConsumerCanRingBell.static_implemented_by_object_literal(->(bell) { bell.ring })).to be true
253+
end
254+
241255
it 'builds guest objects implementing interface properties', compliance: 'interfaceBuilder' do
242256
klass = Class.new do
243257
include JsiiCalc::IInterfaceWithProperties

tools/jsii-compliance/suite.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,11 @@ export const suite: schema.Suite = {
510510
name: 'callbackParameterIsInterface',
511511
description: 'Validates pure interfaces can be passed to callbacks',
512512
},
513+
{
514+
name: 'closureImplementsSingleMethodInterface',
515+
description:
516+
'Language-native closures/lambdas can be passed where a behavioral single-method interface is expected',
517+
},
513518
{
514519
name: 'classCanBeUsedWhenNotExpressedlyLoaded',
515520
description:

0 commit comments

Comments
 (0)