Module: MixinBot::CLIOutput
Overview
Structured and human-friendly stdout/stderr formatting for mixinbot.
Constant Summary collapse
- OUTPUT_FORMATS =
%w[pretty json yaml].freeze
Instance Method Summary collapse
- #abort_with_error(message, kind: nil, hint: nil, exception: nil) ⇒ Object
- #cli_options ⇒ Object
- #current_command_name ⇒ Object
- #emit_info(message) ⇒ Object
- #emit_list(items:, total:, limit:, offset:, command: 'list') ⇒ Object
- #emit_success(data, command: nil) ⇒ Object
- #log(obj) ⇒ Object
- #output_format ⇒ Object
- #paginate_items(items, limit:, offset:) ⇒ Object
- #print_result(obj, data_only: false, command: nil) ⇒ Object
- #select_fields(items, fields) ⇒ Object
- #structured_output? ⇒ Boolean
- #with_command_name(name) ⇒ Object
Instance Method Details
#abort_with_error(message, kind: nil, hint: nil, exception: nil) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/mixin_bot/cli/output.rb', line 74 def abort_with_error(, kind: nil, hint: nil, exception: nil) resolved_kind = kind || (exception && CLIErrors.kind_for_exception(exception)) || CLIErrors.() hint ||= default_error_hint if structured_output? error_body = { 'status' => 'error', 'error' => { 'kind' => resolved_kind.to_s, 'message' => .to_s } } error_body['error']['hint'] = hint if hint.present? warn(JSON.generate(error_body)) else warn(format_error()) end exit(1) end |
#cli_options ⇒ Object
13 14 15 16 17 |
# File 'lib/mixin_bot/cli/output.rb', line 13 def merged = .dup merged = .merge(merged) if respond_to?(:parent_options) && .present? merged end |
#current_command_name ⇒ Object
33 34 35 |
# File 'lib/mixin_bot/cli/output.rb', line 33 def current_command_name @current_command_name || self.class.name.split('::').last.sub(/CLI\z/, '').downcase end |
#emit_info(message) ⇒ Object
64 65 66 67 68 69 70 71 72 |
# File 'lib/mixin_bot/cli/output.rb', line 64 def emit_info() return if .blank? if structured_output? warn() else warn(format_info()) end end |
#emit_list(items:, total:, limit:, offset:, command: 'list') ⇒ Object
54 55 56 57 58 59 60 61 62 |
# File 'lib/mixin_bot/cli/output.rb', line 54 def emit_list(items:, total:, limit:, offset:, command: 'list') payload = { 'items' => items, 'total' => total, 'limit' => limit, 'offset' => offset } emit_success(payload, command:) end |
#emit_success(data, command: nil) ⇒ Object
45 46 47 48 49 50 51 52 |
# File 'lib/mixin_bot/cli/output.rb', line 45 def emit_success(data, command: nil) command_name = command || current_command_name if structured_output? write_stdout(encode_output(envelope('ok', command_name, data))) else write_pretty(data) end end |
#log(obj) ⇒ Object
108 109 110 |
# File 'lib/mixin_bot/cli/output.rb', line 108 def log(obj) emit_success(obj) end |
#output_format ⇒ Object
19 20 21 22 23 24 25 26 27 |
# File 'lib/mixin_bot/cli/output.rb', line 19 def output_format opts = explicit = opts[:output].to_s.downcase if opts[:output].present? return explicit if OUTPUT_FORMATS.include?(explicit) return 'json' if opts.key?(:pretty) && opts[:pretty] == false $stdout.tty? ? 'pretty' : 'json' end |
#paginate_items(items, limit:, offset:) ⇒ Object
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/mixin_bot/cli/output.rb', line 112 def paginate_items(items, limit:, offset:) limit = limit.to_i offset = offset.to_i limit = 100 if limit <= 0 offset = 0 if offset.negative? total = items.size slice = items.drop(offset).first(limit) [slice, total, limit, offset] end |
#print_result(obj, data_only: false, command: nil) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/mixin_bot/cli/output.rb', line 94 def print_result(obj, data_only: false, command: nil) out = case obj when MixinBot::Models::ApiEnvelope data_only ? (obj['data'] || obj.to_h) : obj.to_h when Hash data_only ? (obj['data'] || obj) : obj else obj end emit_success(out, command:) end |
#select_fields(items, fields) ⇒ Object
123 124 125 126 127 128 129 130 131 132 |
# File 'lib/mixin_bot/cli/output.rb', line 123 def select_fields(items, fields) return items if fields.blank? keys = fields.split(',').map(&:strip).reject(&:empty?) return items if keys.empty? items.map do |item| item.slice(*keys) end end |
#structured_output? ⇒ Boolean
29 30 31 |
# File 'lib/mixin_bot/cli/output.rb', line 29 def structured_output? %w[json yaml].include?(output_format) end |
#with_command_name(name) ⇒ Object
37 38 39 40 41 42 43 |
# File 'lib/mixin_bot/cli/output.rb', line 37 def with_command_name(name) previous = @current_command_name @current_command_name = name yield ensure @current_command_name = previous end |