Outputs¶
Outputs declare keys the task is expected to write to context. Every declared output is implicitly required: after work succeeds, the runtime checks each declared key on task.context, applies a default when the value is absent or nil, and fails the task if the key is still missing. Outputs are intentionally minimal — for coercion, transformation, validation, or nested resolution use Inputs (or post-work code).
Declaration¶
Use output (singular) or outputs (they're aliases) to declare one or more keys:
class AuthenticateUser < CMDx::Task
required :email, :password
output :source
output :user, :token
def work
context.source = email.include?("@mycompany.com") ? :admin_portal : :user_portal
context.user = User.authenticate(email, password)
context.token = JwtService.encode(user_id: context.user.id)
end
end
Options¶
| Option | Default | Description |
|---|---|---|
default: |
— | Fallback value, Symbol, Proc, or #call(task)-able; applied when context[name] is nil or the key is absent |
if: / unless: |
— | Skip verification entirely when the predicate isn't satisfied |
description: (alias desc:) |
— | Documentation surfaced via outputs_schema |
output :report_path
output :exported_at, if: -> { context.persist? } # Proc/Lambda is instance_exec'd (no args)
output :tracked, if: :persist? # Symbol calls task.persist?
Defaults¶
Defaults let you declare constants or derived values alongside the output instead of computing them inside work. A default fires during verification whenever the resolved value is nil — both "key absent" and "task wrote nil" — and satisfies the implicit required check.
class ComputeRecommendations < CMDx::Task
output :version, default: "v2" # literal
output :source, default: :default_source # Symbol → task#default_source
output :generated_at, default: -> { Time.now } # Proc → instance_exec on task
output :tenant, default: TenantDefaults # anything responding to #call(task)
def work
# Defaults are applied during verification (after work). Assign in work
# to override a default; leave absent or nil to let the default fill in.
end
private
def default_source = self.class.name
end
See Inputs - Defaults for the long-form treatment of each shape — the resolution rules are identical.
Removals¶
Outputs inherit through subclasses. Remove inherited declarations with deregister — pass one or more keys per call:
class ApplicationTask < CMDx::Task
output :audit_log
output :request_id
end
class LightweightTask < ApplicationTask
deregister :output, :audit_log, :request_id
def work
# No longer required to set context.audit_log or context.request_id
end
end
Verification Behavior¶
Verification runs after work completes successfully. If work threw a skip!, fail!, or throw! signal, outputs are not verified.
flowchart LR
W[work] --> R{signal thrown?}
R -->|skip! / fail! / throw!| Done[Skip output verification]
R -->|no| V[Verify each output]
V --> E{errors?}
E -->|no| S[Signal.success]
E -->|yes| F[Signal.failed reason=errors.to_s]
For each output, in declaration order: if :if/:unless excludes it, skip entirely; otherwise read context[name], fall back to :default when nil, fail with cmdx.outputs.missing when the key was never written and no default produced a value, otherwise write the resolved value back to context[name].
Verification errors fold into the same failed signal that input/validation failures use — result.reason is task.errors.to_s and result.errors exposes the structured map. Under execute!, the same failure raises CMDx::Fault.
Missing Output¶
class CreateUser < CMDx::Task
output :user
def work
# Forgot to set context.user
end
end
result = CreateUser.execute
result.failed? #=> true
result.reason #=> "user must be set in the context"
result.errors.to_h #=> { user: ["must be set in the context"] }
With Bang Execution¶
A failing output verification raises CMDx::Fault:
begin
CreateUser.execute!
rescue CMDx::Fault => e
e.message #=> "user must be set in the context"
e.result.errors[:user] #=> ["must be set in the context"]
e.task #=> CreateUser (the failing task class)
end
Schema Introspection¶
Task.outputs_schema returns a serialized definition of every declared output, useful for documentation generation or runtime introspection: