Skip to content

Add Cordis::Service base class and class plugins - #4

Merged
ryudoawaru merged 1 commit into
mainfrom
feat/service-base-class
Aug 16, 2026
Merged

ryudoawaru merged 1 commit into
mainfrom
feat/service-base-class

Conversation

@ryudoawaru

Copy link
Copy Markdown
Member

Round 4: Cordis::Service base class, aligned with upstream packages/core/src/service.ts (4.0.0-rc.8).

What

  • Cordis::Service — class-style plugin that provides itself as a service:
    • provide :name / inject :dep (or inject dep: {config}) class DSL replaces upstream's super(ctx, name) and static inject (Ruby class ivars don't need the prototype dance).
    • #initialize(ctx, config) calls ctx.provide(name, self) — the instance is the service value.
    • #init maps to upstream Service.init: it runs while the fiber is still loading, so blocking inside keeps the service invisible to dependents (pending inject).
  • Class plugins in the registry (upstream isConstructor): ctx.plugin(SomeClass) — runtime keyed by the class (new Runtime#key), callback wraps plugin.new(ctx, config) + instance.init; a callable #init return is collected as a disposer like any plugin return.
  • demo.rb — new act: AuditLog < Cordis::Service with ctx.intercept carrying per-caller config through resolve_config (the intercept showcase deferred from round 3).

Deliberately skipped (ponytail)

  • Traceable-proxy machinery (ctx rebinding per caller, Service[filter] isolated events, [extend] callable services). Without proxies, per-caller config is resolved by passing the caller ctx explicitly to service methods.
  • Provider-side check predicate (untested upstream in service.spec; add when needed).
  • Inherited provide/inject across subclass chains (class ivars don't inherit).

Tests

spec/cordis/service_base_spec.rb mirrors upstream tests/service.spec.ts (minus proxy cases): provide-self + init-as-load-body, missing provide declaration → failed fiber, pending inject, dependency-ordered chained services, Hash inject config via resolve_config.

58 examples, 0 failures. examples/demo.rb output verified.

🤖 Generated with Claude Code

Mirrors upstream service.ts, adapted to Ruby idiom:

- Cordis::Service: class DSL `provide :name` / `inject :dep` (or
  `inject dep: {config}`) replaces upstream's `super(ctx, name)` and
  `static inject`; #initialize provides the instance as the service,
  and #init runs as the plugin load body (blocking there keeps the
  service invisible to dependents — pending inject via Service.init).
- Registry: Class plugins (upstream isConstructor) — runtime keyed by
  the class itself (new Runtime#key field), callback wraps
  `plugin.new(ctx, config)` + `instance.init`.
- Skipped (traceable-proxy machinery is out of scope): ctx rebinding,
  Service[filter] isolated events, [extend] callable services, and the
  provider-side check predicate. Without proxies, per-caller config is
  resolved by passing the caller ctx explicitly (see demo.rb AuditLog).
- demo.rb: new act — Service class providing itself, with
  ctx.intercept carrying per-caller config through resolve_config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ryudoawaru
ryudoawaru merged commit f480a6e into main Aug 16, 2026
1 check passed
@ryudoawaru
ryudoawaru deleted the feat/service-base-class branch August 16, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant