class WavefrontDisplay::Base
Print human-friendly output. If a command requires a dedicated handler to format its output, define a method with the same name as that which fetches the data, in a WavefrontDisplay
class, extending this one.
We provide long_output()
and multicolumn()
methods to solve standard formatting problems. To use them, define a do_() method but rather than printing the output, have it call the method.
Attributes
Public Class Methods
@param raw_response [Map, Hash, Array] the data returned by the SDK
response.
@param options [Hash] options from docopt
# File lib/wavefront-cli/display/base.rb, line 25 def initialize(raw_response, options = {}) @raw = raw_response data = if raw_response.respond_to?(:items) raw_response.items else raw_response end @data = prioritize_keys(data, priority_keys) @options = options @printer_opts = {} end
Public Instance Methods
Move the given fields to the start of a Hash or Map @param data [Hash, Map] @param keys [Array] keys to float @return [Hash, Map]
# File lib/wavefront-cli/display/base.rb, line 130 def _prioritize_keys(data, keys) keys.each.with_object(data.is_a?(Map) ? Map.new : {}) do |k, a| next unless data.key?(k) a[k] = data[k] data.delete(k) end.merge(data) rescue NoMethodError data end
For freetext searches, we just display the matching fields in “brief” mode.
# File lib/wavefront-cli/display/base.rb, line 263 def display_brief_freetext_results search_keys = freetext_keys data.map! do |d| mf = d.select do |_k, v| search_keys.any? { |s| v.to_s.include?(s) } end { id: d[:id], matching_fields: mf.to_h.keys } end multicolumn(:id, :matching_fields) end
# File lib/wavefront-cli/display/base.rb, line 236 def do_delete puts "Deleted #{friendly_name} '#{options[:'<id>']}'." end
# File lib/wavefront-cli/display/base.rb, line 231 def do_import puts "Imported #{friendly_name}." long_output end
The following do_ methods are default handlers called following their namesake operation in the corresponding WavefrontCli
class. They can be overriden in the inheriting class.
# File lib/wavefront-cli/display/base.rb, line 219 def do_list long_output end
# File lib/wavefront-cli/display/base.rb, line 227 def do_list_brief multicolumn(:id, :name) end
# File lib/wavefront-cli/display/base.rb, line 223 def do_list_fields multicolumn(*filter_fields_as_arr.map(&:to_sym)) end
# File lib/wavefront-cli/display/base.rb, line 332 def do_queries if options[:brief] multicolumn(:condition) else multicolumn(:id, :condition) end end
# File lib/wavefront-cli/display/base.rb, line 294 def do_search long_output end
# File lib/wavefront-cli/display/base.rb, line 244 def do_search_brief search_keys = search_display_keys if search_keys.include?(:freetext) display_brief_freetext_results else multicolumn(*search_keys) end rescue KeyError raise WavefrontCli::Exception::ImpossibleSearch end
# File lib/wavefront-cli/display/base.rb, line 256 def do_search_fields do_list_fields end
# File lib/wavefront-cli/display/base.rb, line 298 def do_tag_add puts "Tagged #{friendly_name} '#{options[:'<id>']}'." end
# File lib/wavefront-cli/display/base.rb, line 306 def do_tag_clear puts "Cleared tags on #{friendly_name} '#{options[:'<id>']}'." end
# File lib/wavefront-cli/display/base.rb, line 302 def do_tag_delete puts "Deleted tag from #{friendly_name} '#{options[:'<id>']}'." end
# File lib/wavefront-cli/display/base.rb, line 322 def do_tag_pathsearch if data.empty? puts 'No matches.' elsif options[:long] long_output else multicolumn(:id, :name) end end
# File lib/wavefront-cli/display/base.rb, line 310 def do_tag_set puts "Set tags on #{friendly_name} '#{options[:'<id>']}'." end
# File lib/wavefront-cli/display/base.rb, line 240 def do_undelete puts "Undeleted #{friendly_name} '#{options[:'<id>']}'." end
Modify, in-place, the data structure to remove fields which we deem not of interest to the user.
@param keys [Symbol] keys you do not wish to be shown. @return [Nil]
# File lib/wavefront-cli/display/base.rb, line 346 def drop_fields(*keys) if data.is_a?(Array) data.each { |i| i.delete_if { |k, _v| keys.include?(k.to_sym) } } else data.delete_if { |k, _v| keys.include?(k.to_sym) } end end
@return [Array] modified version of data. Each hash will
contain only the fields given in `fields`, in the given order
@param data [Array] @param fields [Array]
# File lib/wavefront-cli/display/base.rb, line 78 def filter_data(data, fields) data.map! do |d| fields.each_with_object({}) { |f, a| a[f] = d[f] if d.key?(f) } end end
@return [Array] filter fields from -O option
# File lib/wavefront-cli/display/base.rb, line 210 def filter_fields_as_arr options[:fields].split(',') end
# File lib/wavefront-cli/display/base.rb, line 277 def freetext_keys options[:'<condition>'].map { |c| c.split(SEARCH_SPLIT, 2).last } end
return [String] the name of the thing we're operating on, like
'alert' or 'dashboard'.
# File lib/wavefront-cli/display/base.rb, line 203 def friendly_name self.class.name.split('::').last.gsub(/([a-z])([A-Z])/, '\\1 \\2') .downcase end
Make a time human-readable. Automatically deals with epoch seconds and epoch milliseconds
param t [Integer, String] a timestamp. If it's a string, it is
converted to an int.
param force_utc [Boolean] force output in UTC. Currently only
used for unit tests.
return [String] a human-readable timestamp
# File lib/wavefront-cli/display/base.rb, line 384 def human_time(time, force_utc = false) raise ArgumentError unless time.is_a?(Numeric) || time.is_a?(String) return 'FOREVER' if time == -1 str = time.to_s fmt, out_fmt = time_formats(str) ret = DateTime.strptime(str, fmt).to_time ret = force_utc ? ret.utc : ret.localtime ret.strftime(out_fmt) end
Return the offset of the final item in view.
# File lib/wavefront-cli/display/base.rb, line 183 def index_of_final_item raw.limit.positive? ? raw.offset + raw.limit - 1 : 0 end
Give it a key-value hash, and it will return the size of the first column to use when formatting that data.
@param hash [Hash] the data for which you need a column width @param pad [Integer] the number of spaces you want between columns @return [Integer] length of longest key + pad
# File lib/wavefront-cli/display/base.rb, line 194 def key_width(hash = {}, pad = 2) return 0 if hash.keys.empty? hash.keys.map(&:size).max + pad end
Default display method for 'describe' and long-list methods. Wraps around #_two_columns() giving you the chance to modify @data on the fly
@param fields [Array] a list of fields you wish to
display. If this is nil, all fields are displayed.
@param modified_data [Hash, Array] lets you modify @data
in-line. If this is truthy, it is used. Passing modified_data means that any fields parameter is ignored.
# File lib/wavefront-cli/display/base.rb, line 151 def long_output(fields = nil, modified_data = nil) if data.empty? || modified_data&.empty? puts 'No data.' else require_relative 'printer/long' puts WavefrontDisplayPrinter::Long.new(data, fields, modified_data, @printer_opts) pagination_line end end
# File lib/wavefront-cli/display/base.rb, line 162 def multicolumn(*columns) require_relative 'printer/terse' puts WavefrontDisplayPrinter::Terse.new(data, columns) pagination_line end
if this is a section of a larger dataset, say so
# File lib/wavefront-cli/display/base.rb, line 170 def pagination_line return unless raw.respond_to?(:moreItems) && raw.moreItems == true puts format('List shows items %<first>d to %<last>d. ' \ 'Use -o and -L for more.', first: raw.offset, last: index_of_final_item) rescue StandardError puts 'List shows paginated output. Use -o and -L for more.' end
# File lib/wavefront-cli/display/base.rb, line 119 def prioritize_keys(data, keys) return _prioritize_keys(data, keys) unless data.is_a?(Array) data.map { |e| _prioritize_keys(e, keys) } end
Keys which we wish to float to the top of descriptions and long listing objects. Subclasses may define their own.
# File lib/wavefront-cli/display/base.rb, line 115 def priority_keys %i[id name identifier] end
@param things [Array] @return [String] all “things”, strong-quoted and comma-separated
# File lib/wavefront-cli/display/base.rb, line 415 def quoted(things) things.map { |item| "'#{item}'" }.join(', ') end
Modify, in-place, the @data structure to make times human-readable. Automatically handles second and millisecond epoch times. Currently only operates on top-level keys.
param keys [Symbol, Array] the keys you wish to be
turned into readable times.
return [Nil]
# File lib/wavefront-cli/display/base.rb, line 362 def readable_time(*keys) keys.each { |k| data[k] = human_time(data[k]) if data.key?(k) } end
As for readable_time
, but when @data is an array. For instance in “firing” alerts
# File lib/wavefront-cli/display/base.rb, line 369 def readable_time_arr(*keys) data.map do |row| keys.each { |k| row[k] = human_time(row[k]) if row.key?(k) } end end
find the correct method to deal with the output of the user's command.
rubocop:disable Metrics/MethodLength
# File lib/wavefront-cli/display/base.rb, line 43 def run(method) if method == 'do_list' run_list elsif method == 'do_search' run_search elsif respond_to?("#{method}_brief") && !options[:long] send("#{method}_brief") elsif respond_to?(method) send(method) else long_output end end
Display classes can provide a do_method_code() method, which handles <code> errors when running do_method(). (Code is 404 etc.)
@param method [Symbol] the error method we wish to call
# File lib/wavefront-cli/display/base.rb, line 105 def run_error(method) return unless respond_to?(method) send(method) exit 1 end
Choose the correct list handler. The user can specifiy a long listing with the –long options.
# File lib/wavefront-cli/display/base.rb, line 61 def run_list if options[:long] @data = filter_data(data, filter_fields_as_arr) if options[:fields] do_list elsif options[:fields] do_list_fields else do_list_brief end end
Choose the correct search handler. The user can specifiy a long listing with the –long options.
# File lib/wavefront-cli/display/base.rb, line 87 def run_search if data.empty? puts 'No matches.' elsif options[:long] do_search elsif options[:fields] do_search_fields else do_search_brief end end
# File lib/wavefront-cli/display/base.rb, line 281 def search_display_keys ([search_identifier_key] + options[:'<condition>'].map do |c| c.split(SEARCH_SPLIT, 2).first.to_sym end).uniq end
Most objects refer to themselves by 'id'. Some, like accounts, don't. Override here.
# File lib/wavefront-cli/display/base.rb, line 290 def search_identifier_key :id end
How do we format a timestamp? @param str [String] an epoch timestamp, as a string @return [String, String] DateTime formatter, strptime formatter
# File lib/wavefront-cli/display/base.rb, line 401 def time_formats(str) case str when /^\d{13}$/ ['%Q', HUMAN_TIME_FORMAT_MS] when /^\d{10}$/ ['%s', HUMAN_TIME_FORMAT] else raise ArgumentError end end