Handling Failure
After some back and forth I have found a practical way to handle error conditions in Shell::Piping
. The practical way is to have more then one way. A process does have an exitinteger (called a code, because it can be quite cryptic) and text output to STDERR to indicate something went wrong. Sometimes we need sloppy error handling, sometimes we need to look into the textual output and react to it.
I found a really nice way to use a Junction and Rakus type system to remove some boilerplate from error handling. Combining both allows us to create a flexible type.
class Exitcode {
has $.value;
has $.command;
method Numeric { $.value }
method Str { $.command }
}
So this class produces objects that are both a number and a text. What is actually looked at depends on who is looking. We can use infix:<~~>
to make the decision which comparison operator to use.
say $ex ~~ 42 && $ex ~~ ‚find‘; # OUTPUT: True
That’s still quite wordy. We can use a Junction because it binds tighter then ~~
.
say $ex ~~ 42 & ‚find‘; # OUTPUT: True
Now we can CATCH
an Exception and narrow done the command in a pipe that failed easily.
CATCH {
when X::Shell::NonZeroExitcode {
given .exitcode {
when 42 & ‚find‘ {
warn ‚Oh now! We found the answer!‘;
}
}
}
}
Not all users of a module might like to use Exceptions. So we use a construct in a Shell::Pipe
object to create a Failure
to return from .sink
. If the method Shell::Pipe.exitcode
is called, we assume the user is dealing with them by hand. We can then call .handled
to “abort” the Exception. This has to be easy or it might get skipped. Hence the unusual usage of the coercer methods in the class Exitcode
.
-
July 27, 2020 at 22:472020.30 Almost On Time – Rakudo Weekly News