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)
Defined Under Namespace
Classes: VerbosityLogger
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.
-
#create_logger(_tool) ⇒ Logger
Implementation of a logger factory.
-
#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 ⇒ Proc
Convenience method that returns the error handler proc implemented by this UI (in the #handle_error method).
-
#exit_code_for(error) ⇒ Integer
Returns an exit code appropriate for the given exception.
-
#format_log_entry(severity, time, progname, msg) ⇒ String
deprecated
Deprecated.
Override #format_simple_log_entry and #format_verbose_log_entry instead.
-
#format_simple_log_entry(severity, _time, _progname, msg) ⇒ String
Implementation of the formatter used by loggers created by this UI's logger factory when the simple format is in effect.
-
#format_verbose_log_entry(severity, time, _progname, msg) ⇒ String
Implementation of the formatter used by loggers created by this UI's logger factory when the verbose format is in effect.
-
#handle_error(error) ⇒ Integer
Implementation of an error handler.
-
#initialize(output: nil, backtrace_omit_prefixes: nil, incomplete_backtrace_message: nil) ⇒ StandardUI
constructor
Create a Standard UI.
-
#logger_factory_proc ⇒ Proc
Convenience method that returns the logger factory proc implemented by this UI (in the #create_logger method).
-
#verbose_log_format?(verbosity) ⇒ boolean
Determines whether loggers created by this UI's logger factory use the verbose format, #format_verbose_log_entry, rather than the simple format, #format_simple_log_entry, for the given verbosity.
Constructor Details
#initialize(output: nil, backtrace_omit_prefixes: nil, incomplete_backtrace_message: 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.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/toys/utils/standard_ui.rb', line 63 def initialize(output: nil, backtrace_omit_prefixes: nil, incomplete_backtrace_message: nil) require "toys/utils/terminal" @terminal = output || $stderr @terminal = Terminal.new(output: @terminal) unless @terminal.is_a?(Terminal) @backtrace_omit_prefixes = backtrace_omit_prefixes&.map do |dir| dir.end_with?(::File::SEPARATOR) ? dir : "#{dir}#{::File::SEPARATOR}" end @incomplete_backtrace_message = @log_header_severity_styles = { "FATAL" => [:bright_magenta, :bold, :underline], "ERROR" => [:bright_red, :bold], "WARN" => [:bright_yellow], "INFO" => [:bright_cyan], "DEBUG" => [], } 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.
95 96 97 |
# File 'lib/toys/utils/standard_ui.rb', line 95 def log_header_severity_styles @log_header_severity_styles end |
#terminal ⇒ Toys::Utils::Terminal (readonly)
The terminal underlying this UI
85 86 87 |
# File 'lib/toys/utils/standard_ui.rb', line 85 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.
104 105 106 107 108 109 |
# File 'lib/toys/utils/standard_ui.rb', line 104 def cli_args { error_handler: error_handler_proc, logger_factory: logger_factory_proc, } end |
#create_logger(_tool) ⇒ Logger
Implementation of a logger factory. As dictated by the logger factory
specification in Runner, this must take a ToolDefinition
as an argument, and return a Logger.
The base implementation returns a
VerbosityLogger, which receives the
verbosity of the run from the Runner. The logger writes to the
UI's terminal. It formats each entry using #format_verbose_log_entry
if #verbose_log_format? returns true for the verbosity, or
#format_simple_log_entry otherwise. It sets the level to
Logger::WARN by default. Either this method or the helper methods can
be overridden to change this behavior.
If #format_log_entry is overridden, however, the override formats every entry regardless of verbosity. That behavior is deprecated.
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/toys/utils/standard_ui.rb', line 186 def create_logger(_tool) logger = VerbosityLogger.new(@terminal) format_log_entry_method = method(:format_log_entry) logger.formatter = if format_log_entry_method.owner == StandardUI proc do |severity, time, progname, msg| if verbose_log_format?(logger.verbosity) format_verbose_log_entry(severity, time, progname, msg) else format_simple_log_entry(severity, time, progname, msg) end end else = "Overriding StandardUI#format_log_entry is deprecated. Override " \ "format_verbose_log_entry and/or format_simple_log_entry instead." source_loc = format_log_entry_method.source_location = "#{source_loc[0]}:#{source_loc[1]}: #{}" if source_loc Warnings.warn(:format_log_entry_deprecated, ) format_log_entry_method.to_proc end logger.level = ::Logger::WARN logger end |
#display_error_notice(error) ⇒ Object
Displays a default output for an error.
The output format includes the error message itself, a backtrace (possibly with some entries omitted), and the stack of tool calls if available (i.e. if the error is a ContextualError).
This method is used by #handle_error and can be overridden to change the rendering.
268 269 270 271 272 273 274 275 276 |
# File 'lib/toys/utils/standard_ui.rb', line 268 def display_error_notice(error) @terminal.puts origin, , frames = error_frames(error) render_backtrace(origin) () frames.each do |frame| render_tool_line(frame) end end |
#display_signal_notice(error) ⇒ Object
Displays a default output for a signal received.
This method is used by #handle_error and can be overridden to change its behavior.
245 246 247 248 249 250 251 252 |
# File 'lib/toys/utils/standard_ui.rb', line 245 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 ⇒ Proc
Convenience method that returns the error handler proc implemented by
this UI (in the #handle_error method). This proc can be passed to
the :error_handler argument in the CLI constructor.
118 119 120 |
# File 'lib/toys/utils/standard_ui.rb', line 118 def error_handler_proc method(:handle_error).to_proc 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 #handle_error and can be overridden to change its behavior.
224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/toys/utils/standard_ui.rb', line 224 def exit_code_for(error) case error when ArgParsingError 2 when NotRunnableError 126 when ::SignalException error.signo + 128 else 1 end end |
#format_log_entry(severity, time, progname, msg) ⇒ String
Override #format_simple_log_entry and #format_verbose_log_entry instead.
A legacy formatter for loggers created by this UI's logger factory.
This interface is defined by the standard Logger class.
The base implementation calls #format_verbose_log_entry, and is not
used by loggers created by this UI's logger factory unless it is
overridden. If a subclass overrides this method, the override is used
to format every entry regardless of verbosity, and
#verbose_log_format?, #format_verbose_log_entry, and
#format_simple_log_entry are not called by the logger. The override
may call super to get the verbose format.
364 365 366 |
# File 'lib/toys/utils/standard_ui.rb', line 364 def format_log_entry(severity, time, progname, msg) format_verbose_log_entry(severity, time, progname, msg) end |
#format_simple_log_entry(severity, _time, _progname, msg) ⇒ String
Implementation of the formatter used by loggers created by this UI's
logger factory when the simple format is in effect. This interface is
defined by the standard Logger class.
The base implementation prefixes the first line of the message with the severity, styled using #log_header_severity_styles. If the message is an exception, it includes the exception message and class, but omits the backtrace.
This method can be overridden to change the behavior of loggers created by this UI.
313 314 315 316 |
# File 'lib/toys/utils/standard_ui.rb', line 313 def format_simple_log_entry(severity, _time, _progname, msg) header = style_log_header("#{severity}:", severity) "#{header} #{(msg, backtrace: false)}\n" end |
#format_verbose_log_entry(severity, time, _progname, msg) ⇒ String
Implementation of the formatter used by loggers created by this UI's
logger factory when the verbose format is in effect. This interface is
defined by the standard Logger class.
The base implementation prefixes the message with a header containing the timestamp and severity, styled using #log_header_severity_styles. If the message is an exception, it includes the exception message and class, followed by the backtrace.
This method can be overridden to change the behavior of loggers created by this UI.
337 338 339 340 341 |
# File 'lib/toys/utils/standard_ui.rb', line 337 def format_verbose_log_entry(severity, time, _progname, msg) timestr = time.strftime("%Y-%m-%d %H:%M:%S") header = style_log_header(format("[%<time>s %<sev>5s]", time: timestr, sev: severity), severity) "#{header} #{(msg, backtrace: true)}\n" end |
#handle_error(error) ⇒ Integer
Implementation of an error handler. As dictated by the error handler specification in Runner, this takes the error as its argument, and returns an exit code or raises an exception.
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.
151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/toys/utils/standard_ui.rb', line 151 def handle_error(error) case error when ::SignalException display_signal_notice(error) exit_code_for(error) when ContextualError display_error_notice(error) exit_code_for(error.root_cause) else display_error_notice(error) exit_code_for(error) end end |
#logger_factory_proc ⇒ Proc
Convenience method that returns the logger factory proc implemented by
this UI (in the #create_logger method). This proc can be passed to
the :logger_factory argument in the CLI constructor.
129 130 131 |
# File 'lib/toys/utils/standard_ui.rb', line 129 def logger_factory_proc method(:create_logger).to_proc end |
#verbose_log_format?(verbosity) ⇒ boolean
Determines whether loggers created by this UI's logger factory use the verbose format, #format_verbose_log_entry, rather than the simple format, #format_simple_log_entry, for the given verbosity.
The base implementation returns true if the verbosity is positive. This method can be overridden to change the behavior of loggers created by this UI.
290 291 292 |
# File 'lib/toys/utils/standard_ui.rb', line 290 def verbose_log_format?(verbosity) verbosity.positive? end |