Class: Assistant::Service
- Inherits:
-
Object
- Object
- Assistant::Service
- Extended by:
- ExecuteCallbacks, InputBuilder
- Includes:
- LogList
- Defined in:
- lib/assistant/service.rb
Overview
Core Service base class. Subclasses declare inputs via the
InputBuilder DSL, optionally register before/after/around execute
hooks via ExecuteCallbacks, and implement #execute.
Constant Summary
Constants included from ExecuteCallbacks
Instance Attribute Summary collapse
-
#logs ⇒ Array<Assistant::LogItem>
readonly
Public reader for the full log timeline (info + warning + error), in insertion order.
Class Method Summary collapse
-
.input_snapshot_class ⇒ Class
M-S4: per-subclass
Dataclass whose members are the declared input names, in declaration order. -
.run ⇒ Hash
Convenience: build a service with the given keyword arguments and immediately invoke
#run, returning the result hash.
Instance Method Summary collapse
-
#call_service(klass, **inputs) ⇒ Assistant::Service
M-S2: instantiate
klass, run it, merge its log timeline into the current service, and return the inner service instance. -
#failure? ⇒ Boolean
True when at least one
:errorentry has been logged. -
#initialize(**args) ⇒ Service
constructor
A new instance of Service.
-
#input_snapshot ⇒ Data
M-S4: a read-only
Dataview over the declared inputs of this service, post-default:/ post-allow_nil:. -
#result ⇒ Object
Memoised return value of #execute, threaded through the registered before/around/after execute hooks (M-S1).
-
#run ⇒ Hash{Symbol => Object}
Execute the validation + execute pipeline once and return the result payload.
-
#status ⇒ Symbol
Terminal status for the success path.
-
#success? ⇒ Boolean
True when no
:errorentries have been logged.
Methods included from ExecuteCallbacks
after_execute, after_execute_hooks, around_execute, around_execute_hooks, before_execute, before_execute_hooks, inherited
Methods included from InputBuilder::Dsl
Methods included from InputBuilder::TypeValidator
#input_type_validator_meth, #type_mismatch_message_builder, #type_validator_body
Methods included from InputBuilder::RequireValidator
__reset_deprecation_warnings__, #input_require_conditional_meth, #input_require_validator_meth, warn_deprecated
Methods included from InputBuilder::Accessors
#input_checker_meth, #input_getter_meth
Methods included from InputBuilder::OptionalOption
#apply_optional_option, #process_optional_option, #validate_optional!
Methods included from InputBuilder::DefaultOption
#process_default_option, #validate_default!, #warn_on_mutable_default
Methods included from InputBuilder::Registry
#input_definitions, #register_input_definition
Methods included from LogList
#add_log, #log_item_error_initialize, #merge_logs
Constructor Details
#initialize(**args) ⇒ Service
Returns a new instance of Service.
63 64 65 66 67 |
# File 'lib/assistant/service.rb', line 63 def initialize(**args) @inputs = args apply_input_defaults @logs = [] end |
Instance Attribute Details
#logs ⇒ Array<Assistant::LogItem> (readonly)
Public reader for the full log timeline (info + warning + error), in insertion order. See docs/v1/02-features.md M4.
30 31 32 |
# File 'lib/assistant/service.rb', line 30 def logs @logs end |
Class Method Details
.input_snapshot_class ⇒ Class
M-S4: per-subclass Data class whose members are the declared
input names, in declaration order. Memoised on the subclass and
transparently rebuilt if input_definitions changes (e.g. a
late input :foo after the first snapshot call). Used by
Service#input_snapshot; users normally never touch it.
52 53 54 55 56 57 58 |
# File 'lib/assistant/service.rb', line 52 def input_snapshot_class keys = input_definitions.keys return @input_snapshot_class if @input_snapshot_class && @input_snapshot_class_keys == keys @input_snapshot_class_keys = keys @input_snapshot_class = Data.define(*keys) end |
.run ⇒ Hash
Convenience: build a service with the given keyword arguments
and immediately invoke #run, returning the result hash.
Equivalent to new(**inputs).run.
41 42 43 |
# File 'lib/assistant/service.rb', line 41 def run(**) new(**).run end |
Instance Method Details
#call_service(klass, **inputs) ⇒ Assistant::Service
M-S2: instantiate klass, run it, merge its log timeline into the
current service, and return the inner service instance.
The full log timeline of the inner service (info + warning +
error) is concatenated onto the outer service's @logs via
merge_logs. Because the outer service's errors, warnings,
and status are derived by filtering @logs, an inner error
automatically downgrades the outer terminal status to
:with_errors, and inner warnings surface as :with_warnings
when no errors are present — without any special handling in
the caller.
The returned inner instance exposes #result, #success?,
#failure?, etc. so the caller can branch on the inner outcome:
call_service does not rescue exceptions raised by the inner
service's #execute or by Assistant.notifier; those propagate
to the caller, matching the base Service#run contract. To run
an inner service that may raise, wrap the call in a begin/rescue
and use add_log(level: :error, …) to record the failure.
155 156 157 158 159 160 161 162 163 164 |
# File 'lib/assistant/service.rb', line 155 def call_service(klass, **inputs) unless klass.is_a?(Class) && klass <= Assistant::Service raise ArgumentError, "call_service expects an Assistant::Service subclass, got #{klass.inspect}" end inner = klass.new(**inputs) inner.run merge_logs(logs: inner.logs) inner end |
#failure? ⇒ Boolean
Returns true when at least one :error entry has been logged.
111 112 113 |
# File 'lib/assistant/service.rb', line 111 def failure? errors.any? end |
#input_snapshot ⇒ Data
M-S4: a read-only Data view over the declared inputs of this
service, post-default: / post-allow_nil:. Members are the
input names declared via Service.input / Service.inputs, in
declaration order; values are read from @inputs after
apply_input_defaults has run, so callers see the same values
the per-input getters expose.
The returned object is a Data instance, so it is structurally
immutable: no member can be reassigned. Member values that are
themselves mutable (e.g. an Array passed as an input) keep
their normal mutability — the snapshot does not deep-freeze.
Only declared inputs appear in the snapshot. Extra keyword
arguments accepted by #initialize (which live in @inputs
but have no input :foo declaration) are intentionally excluded
so the snapshot's shape matches the public DSL.
A declared input with no default and no caller-supplied value
appears with a nil member value, mirroring the behaviour of
the per-input getter.
197 198 199 200 |
# File 'lib/assistant/service.rb', line 197 def input_snapshot keys = self.class.input_definitions.keys self.class.input_snapshot_class.new(**keys.to_h { |name| [name, @inputs[name]] }) end |
#result ⇒ Object
Memoised return value of #execute, threaded through the registered before/around/after execute hooks (M-S1).
101 102 103 |
# File 'lib/assistant/service.rb', line 101 def result @result ||= run_execute_with_callbacks end |
#run ⇒ Hash{Symbol => Object}
Execute the validation + execute pipeline once and return the
result payload. Idempotent: calling #run a second time returns
an updated payload based on the memoised #result, but #execute
itself runs only once (M-S1 hook chain is gated by #result's
||=).
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/assistant/service.rb', line 80 def run @run_started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) notify(:service_started) validate_inputs validate notify(:service_validated) return failed_payload if errors.any? # Trigger `#execute` (through the M-S1 hook chain) eagerly so any # error logged by a `before_/after_/around_execute` hook influences # the terminal event and the payload's `:status` field. result errors.empty? ? executed_payload : failed_payload end |
#status ⇒ Symbol
Terminal status for the success path. Failure runs use
:with_errors directly in the result payload (see #run).
119 120 121 |
# File 'lib/assistant/service.rb', line 119 def status warnings.empty? ? :ok : :with_warnings end |
#success? ⇒ Boolean
Returns true when no :error entries have been logged.
106 107 108 |
# File 'lib/assistant/service.rb', line 106 def success? errors.empty? end |