I also have trouble with the Process syntax because the defaults require a lot of arguments and it is not always clear whether is is blocking or not.
In all my projects I write some kind of helper method that wraps Process
because of that.
Clarify blocking v. non-blocking
I’m not sure why Process by default would be non-blocking, but either way I think we could clarify this by calling the methods what they are so it is always Crystal clear what is going on
Process.sync(...args)
Process.async(...args)
I think that makes it incredibly easy to tell what it is doing. You don’t need to pull up the docs to know what these 2 are doing.
Not totally sold on the names, but the principles stand I think. The API could be Process.async
and Process.wait
or something. But in general if there are two ways to do something giving them clear names is a good way to go IMO.
Capturing output
I love the idea of making working without output easier. I think rather than returning output and error, it could return a ProcessResult
object that had an #output
and #error
. This way you don’t have to remember which position output
is. Instead you have a nice object with documentation and that can be enhanced with additional methods in the future if helpful:
result = Process.sync "echo hello"
puts result.output.to_s #=> hello
It could also have #status
that returns a Process::Status
for example. I think returning a ProcessResult
would be super helpful and flexible
Shell true
Another part that is confusing to me is when to use shell: true
. It is not clear from the documentation when to use it or not. I don’t think this is a problem with the API, but maybe some more .examples/clarification around this would be helpful.
I’d be happy to contribute but I honestly don’t know the difference between shell: true/false
Error Handling
Right now by default a failed process does not raise an error. This has generated a number of bugs for me when I forget to handle errors. It takes awhile to figure out where the problem is when there is no error.
My suggestion here is to make them raise an error by default and have ?
versions that don’t raise. Or if we don’t want a breaking change (or just don’t like the ?
version), introduce a !
version so that it is at least super easy raise when there is an issue, e.g. Process.sync