override<T, S extends Step<T> > method
Override step
with value
, ensuring that step
evaluates to value
when run is called in this Runner.
Overriding a Step is a useful technique for injecting input that steps depend on, as illstrated in the example below. It can also be useful for injecting mock objects or fakes when writing tests.
Overriding a step
after it has been evaluated or overriden once is not
allowed.
Example overriding a step to provide input
/// A step that provides a message, this is a _virtual step_ because it
/// doesn't have an implementation instead it throws an error. Hence, to
/// evaluate a step that depends on [messageStep] it is necessary to
/// override this step, by injecting a value to replace it.
final Step<String> messageStep = Step.define('message').build(
() => throw UnimplementedError('message must be overriden with input'),
);
/// A step that provides date and time
final dateTimeStep =
Step.define('date-time').build(() => DateTime.now().toString());
/// A step which has side effects.
final Step<void> printStep = Step.define('print')
// Dependencies:
.dep(messageStep)
.dep(dateTimeStep)
.build((
msg, // result from evaluation of messageStep
time, // result from evaluation of dateTimeStep
) {
print('$msg at $time');
});
Future<void> main() async {
final r = Runner();
// Override [messageStep] to provide an input value.
r.override(messageStep, 'hello world');
// Evaluate [printStep] which in turn evaluates [dateTimeStep], and re-uses
// the overridden value for [messageStep].
await r.run(printStep);
}
Implementation
void override<T, S extends Step<T>>(S step, FutureOr<T> value) {
if (_cache.containsKey(step)) {
throw StateError('Value for $step is already cached');
}
_cache[step] = Future.value(value);
}