Class: Toys::Utils::StandardUI
- Inherits:
-
Object
- Object
- Toys::Utils::StandardUI
- Defined in:
- lib/toys/utils/standard_ui.rb
Overview
An object that implements standard UI elements, such as error reports and
logging, as provided by the toys
command line. Specifically, it
implements pretty formatting of log entries and stack traces, and renders
using ANSI coloring where available via Terminal.
This object can be used to implement toys
-style behavior when creating
a CLI object. For example:
require "toys/utils/standard_ui"
ui = Toys::Utils::StandardUI.new
cli = Toys::CLI.new(**ui.cli_args)
Instance Attribute Summary collapse
-
#log_header_severity_styles ⇒ Hash{String => Array<Symbol>}
readonly
A hash that maps severities to styles recognized by Terminal.
-
#terminal ⇒ Toys::Utils::Terminal
readonly
The terminal underlying this UI.
Instance Method Summary collapse
-
#cli_args ⇒ Hash
Convenience method that returns a hash of arguments that can be passed to the CLI constructor.
-
#display_error_notice(error) ⇒ Object
Displays a default output for an error.
-
#display_signal_notice(error) ⇒ Object
Displays a default output for a signal received.
-
#error_handler ⇒ Proc
Returns an error handler conforming to the
:error_handler
argument to the CLI constructor. -
#error_handler_impl(error) ⇒ Integer
Implementation of the error handler.
-
#exit_code_for(error) ⇒ Integer
Returns an exit code appropriate for the given exception.
-
#initialize(output: nil) ⇒ StandardUI
constructor
Create a Standard UI.
-
#logger_factory ⇒ Proc
Returns a logger factory conforming to the
:logger_factory
argument to the CLI constructor. -
#logger_factory_impl(_tool) ⇒ Logger
Implementation of the logger factory.
-
#logger_formatter_impl(severity, time, _progname, msg) ⇒ String
Implementation of the formatter used by loggers created by this UI's logger factory.
Constructor Details
#initialize(output: nil) ⇒ StandardUI
Create a Standard UI.
By default, all output is written to $stderr
, and will share a single
Terminal object, allowing multiple tools and/or threads
to interleave messages without interrupting one another.
30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/toys/utils/standard_ui.rb', line 30 def initialize(output: nil) require "logger" require "toys/utils/terminal" @terminal = output || $stderr @terminal = Terminal.new(output: @terminal) unless @terminal.is_a?(Terminal) @log_header_severity_styles = { "FATAL" => [:bright_magenta, :bold, :underline], "ERROR" => [:bright_red, :bold], "WARN" => [:bright_yellow], "INFO" => [:bright_cyan], "DEBUG" => [:white], } end |
Instance Attribute Details
#log_header_severity_styles ⇒ Hash{String => Array<Symbol>} (readonly)
A hash that maps severities to styles recognized by Terminal. Used to style the header for each log entry. This hash can be modified in place to adjust the behavior of loggers created by this UI.
59 60 61 |
# File 'lib/toys/utils/standard_ui.rb', line 59 def log_header_severity_styles @log_header_severity_styles end |
#terminal ⇒ Toys::Utils::Terminal (readonly)
The terminal underlying this UI
49 50 51 |
# File 'lib/toys/utils/standard_ui.rb', line 49 def terminal @terminal end |
Instance Method Details
#cli_args ⇒ Hash
Convenience method that returns a hash of arguments that can be passed
to the CLI constructor. Includes the :error_handler
and
:logger_factory
arguments.
68 69 70 71 72 73 |
# File 'lib/toys/utils/standard_ui.rb', line 68 def cli_args { error_handler: error_handler, logger_factory: logger_factory, } end |
#display_error_notice(error) ⇒ Object
Displays a default output for an error. Displays the error, the backtrace, and contextual information regarding what tool was run and where in its code the error occurred.
This method is used by #error_handler_impl and can be overridden to change its behavior.
197 198 199 200 201 |
# File 'lib/toys/utils/standard_ui.rb', line 197 def display_error_notice(error) @terminal.puts @terminal.puts(cause_string(error.cause)) @terminal.puts(context_string(error), :bold) end |
#display_signal_notice(error) ⇒ Object
Displays a default output for a signal received.
This method is used by #error_handler_impl and can be overridden to change its behavior.
178 179 180 181 182 183 184 185 |
# File 'lib/toys/utils/standard_ui.rb', line 178 def display_signal_notice(error) @terminal.puts if error.is_a?(::Interrupt) @terminal.puts("INTERRUPTED", :bold) else @terminal.puts("SIGNAL RECEIVED: #{error.signm || error.signo}", :bold) end end |
#error_handler ⇒ Proc
Returns an error handler conforming to the :error_handler
argument to
the CLI constructor. Specifically, it returns the
#error_handler_impl method as a proc.
82 83 84 |
# File 'lib/toys/utils/standard_ui.rb', line 82 def error_handler @error_handler ||= method(:error_handler_impl).to_proc end |
#error_handler_impl(error) ⇒ Integer
Implementation of the error handler. As dictated by the error handler specification in CLI, this must take a ContextualError as an argument, and return an exit code.
The base implementation uses #display_error_notice and #display_signal_notice to print an appropriate message to the UI's terminal, and uses #exit_code_for to determine the correct exit code. Any of those methods can be overridden by a subclass to alter their behavior, or this main implementation method can be overridden to change the overall behavior.
112 113 114 115 116 117 118 119 120 |
# File 'lib/toys/utils/standard_ui.rb', line 112 def error_handler_impl(error) cause = error.cause if cause.is_a?(::SignalException) display_signal_notice(cause) else display_error_notice(error) end exit_code_for(cause) end |
#exit_code_for(error) ⇒ Integer
Returns an exit code appropriate for the given exception. Currently, the logic interprets signals (returning the convention of 128 + signo), usage errors (returning the conventional value of 2), and tool not runnable errors (returning the conventional value of 126), and defaults to 1 for all other error types.
This method is used by #error_handler_impl and can be overridden to change its behavior.
157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/toys/utils/standard_ui.rb', line 157 def exit_code_for(error) case error when ArgParsingError 2 when NotRunnableError 126 when ::SignalException error.signo + 128 else 1 end end |
#logger_factory ⇒ Proc
Returns a logger factory conforming to the :logger_factory
argument
to the CLI constructor. Specifically, it returns the
#logger_factory_impl method as a proc.
93 94 95 |
# File 'lib/toys/utils/standard_ui.rb', line 93 def logger_factory @logger_factory ||= method(:logger_factory_impl).to_proc end |
#logger_factory_impl(_tool) ⇒ Logger
Implementation of the logger factory. As dictated by the logger factory
specification in CLI, this must take a ToolDefinition
as an argument, and return a Logger
.
The base implementation returns a logger that writes to the UI's
terminal, using #logger_formatter_impl as the formatter. It sets the
level to Logger::WARN
by default. Either this method or the helper
methods can be overridden to change this behavior.
136 137 138 139 140 141 |
# File 'lib/toys/utils/standard_ui.rb', line 136 def logger_factory_impl(_tool) logger = ::Logger.new(@terminal) logger.formatter = method(:logger_formatter_impl).to_proc logger.level = ::Logger::WARN logger end |
#logger_formatter_impl(severity, time, _progname, msg) ⇒ String
Implementation of the formatter used by loggers created by this UI's
logger factory. This interface is defined by the standard Logger
class.
This method can be overridden to change the behavior of loggers created by this UI.
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/toys/utils/standard_ui.rb', line 217 def logger_formatter_impl(severity, time, _progname, msg) msg_str = case msg when ::String msg when ::Exception "#{msg.} (#{msg.class})\n" << (msg.backtrace || []).join("\n") else msg.inspect end timestr = time.strftime("%Y-%m-%d %H:%M:%S") header = format("[%<time>s %<sev>5s]", time: timestr, sev: severity) styles = log_header_severity_styles[severity] header = @terminal.apply_styles(header, *styles) if styles "#{header} #{msg_str}\n" end |