defmodule CollectableStreamer do @moduledoc ~S""" A module for accessing command output line by line. ## Example iex> import ExUnit.CaptureIO iex> callback = fn line -> IO.puts("Received line: #{line}") end iex> streamer = CollectableStreamer.new(callback) iex> capture_io(fn -> System.cmd("echo", ["Hello, World!"], into: streamer) end) "Received line: Hello, World!\n" """ @behaviour Collectable defstruct [:callback] def new(callback) when is_function(callback, 1) do %__MODULE__{callback: callback} end def into(streamer) do { streamer, fn streamer, {:cont, item} -> trimmed = String.replace_suffix(item, "\n", "") streamer.callback.(trimmed) streamer streamer, :done -> streamer _streamer, :halt -> :ok end } end defimpl Collectable do def into(streamer) do CollectableStreamer.into(streamer) end end end