Skip to content

Commit

Permalink
Minor refactoring of error handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Nov 6, 2024
1 parent 719a069 commit 7aba335
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 37 deletions.
3 changes: 2 additions & 1 deletion lib/console/capture.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Copyright, 2019-2024, by Samuel Williams.

require_relative "filter"
require_relative "output/failure"

module Console
# A general sink which captures all events into a buffer.
Expand Down Expand Up @@ -58,7 +59,7 @@ def verbose?
@verbose
end

def call(subject = nil, *arguments, severity: UNKNOWN, event: nil, **options, &block)
def call(subject = nil, *arguments, severity: UNKNOWN, event: nil, **options, &block)
record = {
time: ::Time.now.iso8601,
severity: severity,
Expand Down
4 changes: 2 additions & 2 deletions lib/console/event/failure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ def self.for(exception)
def self.log(subject, exception, **options)
Console.error(subject, **self.for(exception).to_hash, **options)
end

attr_reader :exception

def initialize(exception, root = Dir.getwd)
@exception = exception
@root = root
Expand Down
21 changes: 6 additions & 15 deletions lib/console/logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# Copyright, 2021, by Robert Schulze.

require_relative "output"
require_relative "output/failure"

require_relative "filter"
require_relative "event"
require_relative "resolver"
Expand Down Expand Up @@ -47,6 +49,7 @@ def self.default_logger(output = $stderr, env = ENV, **options)
end

output = Output.new(output, env, **options)

logger = self.new(output, **options)

Resolver.default_resolver(logger)
Expand All @@ -61,6 +64,9 @@ def self.local
DEFAULT_LEVEL = 1

def initialize(output, **options)
# This is the expected default behaviour, but it may be nice to have a way to override it.
output = Output::Failure.new(output, **options)

super(output, **options)
end

Expand All @@ -69,20 +75,5 @@ def progress(subject, total, **options)

Progress.new(subject, total, **options)
end

def error(subject, *arguments, **options, &block)
# This is a special case where we want to create a failure event from an exception.
# It's common to see `Console.error(self, exception)` in code.
if arguments.first.is_a?(Exception)
exception = arguments.shift
options[:event] = Event::Failure.for(exception)
end

super
end

def failure(subject, exception, **options)
error(subject, event: Event::Failure.for(exception), **options)
end
end
end
7 changes: 5 additions & 2 deletions lib/console/output/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

require_relative "terminal"
require_relative "serialized"
require_relative "failure"

module Console
module Output
Expand All @@ -13,10 +14,12 @@ def self.new(output, **options)
output ||= $stderr

if output.tty?
Terminal.new(output, **options)
output = Terminal.new(output, **options)
else
Serialized.new(output, **options)
output = Serialized.new(output, **options)
end

return output
end
end
end
Expand Down
32 changes: 32 additions & 0 deletions lib/console/output/failure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2021-2024, by Samuel Williams.

require_relative "wrapper"
require_relative "../event/failure"

module Console
module Output
# A wrapper for outputting failure messages, which can include exceptions.
class Failure < Wrapper
def initialize(output, **options)
super(output, **options)
end

# The exception must be either the last argument or passed as an option.
def call(subject = nil, *arguments, exception: nil, **options, &block)
if exception.nil?
last = arguments.last
if last.is_a?(Exception)
options[:event] = Event::Failure.for(last)
end
else
options[:event] = Event::Failure.for(exception)
end

super(subject, *arguments, **options)
end
end
end
end
4 changes: 4 additions & 0 deletions lib/console/output/null.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ class Null
def initialize(...)
end

def last_output
self
end

def call(...)
# Do nothing.
end
Expand Down
9 changes: 7 additions & 2 deletions lib/console/output/serialized.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@
module Console
module Output
class Serialized
def initialize(output, format: Format.default, **options)
@io = output
def initialize(io, format: Format.default, **options)
@io = io
@format = format
end

# This a final output that then writes to an IO object.
def last_output
self
end

attr :io
attr :format

Expand Down
5 changes: 5 additions & 0 deletions lib/console/output/terminal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ def initialize(output, verbose: nil, start_at: Terminal.start_at!, format: nil,
self.register_formatters
end

# This a final output that then writes to an IO object.
def last_output
self
end

attr :io

attr_accessor :verbose
Expand Down
6 changes: 6 additions & 0 deletions lib/console/output/wrapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ def initialize(delegate, **options)
@delegate = delegate
end

attr :delegate

def last_output
@delegate.last_output
end

def verbose!(value = true)
@delegate.verbose!(value)
end
Expand Down
16 changes: 16 additions & 0 deletions releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
## Unreleased

- Don't make `Kernel#warn` redirection to `Console.warn` the default behavior, you must `require 'console/warn'` to enable it.
- Remove deprecated `Console::Logger#failure`.

### Consistent Handling of Exceptions

`Console.call` and all wrapper methods will now consistently handle exceptions that are the last positional argument or keyword argument. This means that the following code will work as expected:

```ruby
begin
rescue => error
# Last positional argument:
Console.warn(self, "There may be an issue", error)

# Keyword argument (preferable):
Console.error(self, "There is an issue", exception: error)
end
```

## v1.28.0

Expand Down
2 changes: 1 addition & 1 deletion test/console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
event: have_keys(
type: be == :failure,
message: be == "It failed!",
),
)
)
end

Expand Down
6 changes: 3 additions & 3 deletions test/console/output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
let(:capture) {File.open("/tmp/console.log", "w")}

it "should use a serialized format" do
expect(output).to be_a(Console::Output::Serialized)
expect(output.last_output).to be_a(Console::Output::Serialized)
end
end

Expand All @@ -27,13 +27,13 @@
it "should use a terminal format" do
expect($stderr).to receive(:tty?).twice.and_return(true)

expect(output).to be_a Console::Output::Terminal
expect(output.last_output).to be_a Console::Output::Terminal
end
end

with env: {"CONSOLE_OUTPUT" => "JSON"} do
it "can set output to Serialized and format to JSON" do
expect(output).to be_a Console::Output::Serialized
expect(output.last_output).to be_a Console::Output::Serialized
expect(output.format).to be_a(Console::Format::Safe)
end
end
Expand Down
14 changes: 3 additions & 11 deletions test/console/output/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@
require "console/capture"

describe Console::Output::Default do
let(:output) {nil}
let(:logger) {subject.new(output)}

def final_output(output)
if output.respond_to?(:output)
final_output(output.output)
else
output
end
end
let(:io) {nil}
let(:output) {subject.new(io)}

it "should output to $stderr by default" do
expect(final_output(logger).io).to be == $stderr
expect(output.last_output.io).to be == $stderr
end
end

0 comments on commit 7aba335

Please sign in to comment.