Morning,
I thought I’d create a more generalised thread as a way to start the discussion about some parts of the stdlib that could then be moved into their own thread/issue or be resolved quickly if there was something of a consensus.
Process
The Process
module provides a high-level API, but I wonder if it’s worth either clarifying the docs or standardising some of the methods. I was a bit hung up on trying to tee the contents of stdout & stderr (show in foreground and have access to it after completion) and get the exit code at the end.
While I realise it’s a bit of an edge case, I ended up with:
-
Process.new
,output
anderror
asIO::Memory
objects. - Tail the
IO::Memory
objects with awhile Process.exists?
loop. - Use
process.wait.exit_status
at the end (after I know the Process has already completed) to get the exit code.
(Some of this may be doable in a fiber but I didn’t know the blocking semantics for this kind of process and it wasn’t required in this simple example)
This was all totally workable, but since it’s a high-level API, I wondered if it would be worth tweaking so that:
- Provide a way of getting the
Process::Status
via. a property instead of relying onwait
, aswait
seemed a bit strange since I already knew the process had exited. - Standardise all of the main entrypoint methods (
.fork
,.run
,.new
) to return aProcess
- Currently, only.run
returns aProcess::Status
- Clarify docs/arguments of
.fork
as it seems to be impossible to get the contents ofoutput
anderror
as the process has forked?
IO
This one was kinda a mix bag - query, suggestion, request for input.
Does the current IO implementation - or child implementations, like File
- provide a way to ‘stream’ (lazy-load) at a high level? Methods like .each_line
would be a great candidate, or perhaps another abstraction that provides a Stream
object which acts like a generator instead of loading in the entire contents into memory.
I’ve looked at the IO::Buffered
docs and it looks like it should be doable with the current tools, but I’m not experienced in this kind of process - what’s a normal amount of bytes to read, do we rely on file encodings to determine when to break, etc.?
Just kinda wondering the current state and if anyone has any input in how we can get this implemented?
Path
Currently I find Path
a useful module, coming from using Python’s pathlib, I feel like it gives a load of great, high-level abstractions.
I had a gripe with the syntax (Path[root].join(foo, bar)
) but just realised that if I’d RTFM, I can use Path.new(root, foo, bar)
However, it seems a little odd that the likes of Dir
do not accept a Path
object. This is only a minor objection because the .to_s
method fixes this issue, but it seems like a bit of a disconnect when the Path
module is so useful, and it usually means going String -> Path -> String -> Dir
- Is there any cause for a bit tighter integration? Or is it fine the way it is?
Now, I don’t want this to come across as negative in any way. So far, Crystal has been a pleasure to write.
But I am trying to start a meaningful discussion on parts of the stdlib that I think could be improved upon (rough edges), and I’m willing to contribute code and docs to so.
Looking forward to any feedback.