Class: Raif::Evals::ConsoleWriter

Inherits:
Object
  • Object
show all
Defined in:
lib/raif/evals/console_writer.rb

Overview

Serializes a run's console output onto one IO.

Concurrent evals each produce several lines - a case summary and the failing expectations beneath it, or an error and its backtrace - that only make sense together. Buffered mode collects one execution's lines and emits them as a single block, so two executions finishing at once cannot interleave their lines.

Headers (the eval set name, the eval description) are handed to #capture rather than printed up front: under concurrency, results arrive in completion order, so the first moment a header is known to describe the lines beneath it is when the first of those lines is ready to print.

Instance Method Summary collapse

Constructor Details

#initialize(output, buffered: false) ⇒ ConsoleWriter

Returns a new instance of ConsoleWriter.

Parameters:

  • output (IO)

    where lines are ultimately written.

  • buffered (Boolean) (defaults to: false)

    when false, blocks write straight through to output. A serial run has nothing to interleave with, and writing through keeps a slow eval's output appearing as it happens rather than only once the eval finishes.



21
22
23
24
25
26
# File 'lib/raif/evals/console_writer.rb', line 21

def initialize(output, buffered: false)
  @output = output
  @buffered = buffered
  @mutex = Mutex.new
  @printed_headers = Set.new
end

Instance Method Details

#capture(headers: []) ⇒ Object

Yields the IO the caller should write to, then emits everything written as one block, preceded by whichever of headers has not been printed yet.

Parameters:

  • headers (Array<Array(Object, String)>) (defaults to: [])

    [key, line] pairs, each printed at most once per writer.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/raif/evals/console_writer.rb', line 33

def capture(headers: [])
  unless @buffered
    print_with_headers(headers)
    return yield(@output)
  end

  buffer = StringIO.new

  begin
    yield(buffer)
  ensure
    # In an ensure so an execution killed part way through still gets the lines it
    # managed to produce onto the console.
    flush(headers, buffer.string)
  end
end

Headers and lines in one acquisition of the lock, for a caller whose lines are only attributable underneath its own header. Two calls would let another execution's flush land between the two.

Parameters:

  • headers (Array<Array(Object, String)>)

    [key, line] pairs, each printed at most once per writer.



56
57
58
59
60
61
# File 'lib/raif/evals/console_writer.rb', line 56

def print_with_headers(headers, *lines)
  @mutex.synchronize do
    write_headers(headers)
    @output.puts(*lines) if lines.any?
  end
end