Class: WavefrontDisplay::Base

Inherits:
Object
  • Object
show all
Includes:
WavefrontCli::Constants
Defined in:
lib/wavefront-cli/display/base.rb

Overview

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 terse_output() methods to solve standard formatting problems. To use them, define a do_() method but rather than printing the output, have it call the method.

Constant Summary

Constants included from WavefrontCli::Constants

WavefrontCli::Constants::DEFAULT_OPTS, WavefrontCli::Constants::HUMAN_TIME_FORMAT, WavefrontCli::Constants::HUMAN_TIME_FORMAT_MS

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, options = {}) ⇒ Base

Returns a new instance of Base.



29
30
31
32
33
34
35
# File 'lib/wavefront-cli/display/base.rb', line 29

def initialize(data, options = {})
  @data = data
  @options = options
  @indent = 0
  @indent_step = options[:indent_step] || 2
  @hide_blank = options[:hide_blank] || true
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



17
18
19
# File 'lib/wavefront-cli/display/base.rb', line 17

def data
  @data
end

#hide_blankObject (readonly)

Returns the value of attribute hide_blank.



17
18
19
# File 'lib/wavefront-cli/display/base.rb', line 17

def hide_blank
  @hide_blank
end

#indentObject (readonly)

Returns the value of attribute indent.



17
18
19
# File 'lib/wavefront-cli/display/base.rb', line 17

def indent
  @indent
end

#indent_stepObject (readonly)

Returns the value of attribute indent_step.



17
18
19
# File 'lib/wavefront-cli/display/base.rb', line 17

def indent_step
  @indent_step
end

#indent_strObject (readonly)

Returns the value of attribute indent_str.



17
18
19
# File 'lib/wavefront-cli/display/base.rb', line 17

def indent_str
  @indent_str
end

#kwObject (readonly)

Returns the value of attribute kw.



17
18
19
# File 'lib/wavefront-cli/display/base.rb', line 17

def kw
  @kw
end

#optionsObject (readonly)

Returns the value of attribute options.



17
18
19
# File 'lib/wavefront-cli/display/base.rb', line 17

def options
  @options
end

Instance Method Details

#_two_columns(data, kw = nil, fields = nil) ⇒ Object

A recursive function which displays a key-value hash in two columns. The key column width is automatically calculated. Multiple-value ‘v’s are printed one per line. Hashes are nested.

Parameters:

  • data (Array)

    and array of objects to display. Each object should be a hash.

  • indent (Integer)

    how many characters to indent the current data.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/wavefront-cli/display/base.rb', line 123

def _two_columns(data, kw = nil, fields = nil)
  [data].flatten.each do |row|
    row.keep_if { |k, _v| fields.include?(k) } unless fields.nil?
    kw = key_width(row) unless kw
    @kw = kw unless @kw
    set_indent(indent)

    row.each do |k, v|
      next if v.respond_to?(:empty?) && v.empty? && hide_blank

      if v.is_a?(String) && v.match(/<.*>/)
        v = v.gsub(%r{<\/?[^>]*>}, '').delete("\n")
      end

      if v.is_a?(Hash)
        print_line(k)
        @indent += indent_step
        @kw -= 2
        _two_columns([v], kw - indent_step)
      elsif v.is_a?(Array)
        print_array(k, v)
      else
        print_line(k, v)
      end
    end
    puts if indent.zero?
  end

  @indent -= indent_step if indent > 0
  @kw += 2
  set_indent(indent)
end

#do_deleteObject



226
227
228
# File 'lib/wavefront-cli/display/base.rb', line 226

def do_delete
  puts "Deleted #{friendly_name} '#{options[:'<id>']}'."
end

#do_importObject



221
222
223
224
# File 'lib/wavefront-cli/display/base.rb', line 221

def do_import
  puts "Imported #{friendly_name}."
  long_output
end

#do_listObject



213
214
215
# File 'lib/wavefront-cli/display/base.rb', line 213

def do_list
  long_output
end

#do_list_briefObject



217
218
219
# File 'lib/wavefront-cli/display/base.rb', line 217

def do_list_brief
  terse_output
end

#do_tag_addObject



234
235
236
# File 'lib/wavefront-cli/display/base.rb', line 234

def do_tag_add
  puts "Tagged #{friendly_name} '#{options[:'<id>']}'."
end

#do_tag_clearObject



242
243
244
# File 'lib/wavefront-cli/display/base.rb', line 242

def do_tag_clear
  puts "Cleared tags on #{friendly_name} '#{options[:'<id>']}'."
end

#do_tag_deleteObject



238
239
240
# File 'lib/wavefront-cli/display/base.rb', line 238

def do_tag_delete
  puts "Deleted tag from #{friendly_name} '#{options[:'<id>']}'."
end

#do_tag_setObject



246
247
248
# File 'lib/wavefront-cli/display/base.rb', line 246

def do_tag_set
  puts "Set tags on #{friendly_name} '#{options[:'<id>']}'."
end

#do_tagsObject



250
251
252
253
254
255
256
# File 'lib/wavefront-cli/display/base.rb', line 250

def do_tags
  if data.empty?
    puts "No tags set on #{friendly_name} '#{options[:'<id>']}'."
  else
    data.sort.each { |t| puts t }
  end
end

#do_undeleteObject



230
231
232
# File 'lib/wavefront-cli/display/base.rb', line 230

def do_undelete
  puts "Undeleted #{friendly_name} '#{options[:'<id>']}'."
end

#drop_fields(*keys) ⇒ Object

Modify, in-place, the data structure to remove fields which we deem not of interest to the user.

Parameters:

  • keys (Symbol)

    keys you do not wish to be shown.



263
264
265
# File 'lib/wavefront-cli/display/base.rb', line 263

def drop_fields(*keys)
  data.delete_if { |k, _v| keys.include?(k.to_sym) }
end

#friendly_nameObject



208
209
210
211
# File 'lib/wavefront-cli/display/base.rb', line 208

def friendly_name
  self.class.name.split('::').last.gsub(/([a-z])([A-Z])/, '\\1 \\2')
      .downcase
end

#human_time(t) ⇒ Object



278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/wavefront-cli/display/base.rb', line 278

def human_time(t)
  str = t.to_s

  if str.length == 13
    fmt = '%Q'
    out_fmt = HUMAN_TIME_FORMAT_MS
  else
    fmt = '%s'
    out_fmt = HUMAN_TIME_FORMAT
  end

  DateTime.strptime(str, fmt).strftime(out_fmt)
end

#indent_wrap(line, cols = 78, offset = 22) ⇒ Object



199
200
201
202
203
204
205
206
# File 'lib/wavefront-cli/display/base.rb', line 199

def indent_wrap(line, cols = 78, offset = 22)
  #
  # hanging indent long lines to fit in an 80-column terminal
  #
  return unless line
  line.gsub(/(.{1,#{cols - offset}})(\s+|\Z)/, "\\1\n#{' ' *
          offset}").rstrip
end

#key_width(hash, pad = 2) ⇒ Integer

Give it a key-value hash, and it will return the size of the first column to use when formatting that data.

Parameters:

  • hash (Hash)

    the data for which you need a column width

  • pad (Integer) (defaults to: 2)

    the number of spaces you want between columns

Returns:

  • (Integer)

    length of longest key + pad



194
195
196
197
# 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

#long_output(fields = nil, modified_data = nil) ⇒ Object



57
58
59
# File 'lib/wavefront-cli/display/base.rb', line 57

def long_output(fields = nil, modified_data = nil)
  _two_columns(modified_data || data, nil, fields)
end

#multicolumn(*keys) ⇒ Object

Print multiple column output. Currently this method does no word wrapping.

Parameters:

  • keys (Symbol)

    the keys you want in the output. They will be printed in the order given.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/wavefront-cli/display/base.rb', line 86

def multicolumn(*keys)
  len = Hash[*keys.map {|k| [k, 0]}.flatten]

  keys.each do |k|
    data.each do |obj|
      val = obj[k]
      val = val.join(', ') if val.is_a?(Array)
      len[k] = val.size if val.size > len[k]
    end
  end

  fmt = keys.each_with_object('') { |k, out| out.<< "%-#{len[k]}s  " }

  data.each do |obj|
    args = keys.map do |k|
      obj[k].is_a?(Array) ? obj[k].join(', ') : obj[k]
    end

    puts format(fmt, *args)
  end
end


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/wavefront-cli/display/base.rb', line 156

def print_array(k, v)
  v.each_with_index do |w, i|
    if w.is_a?(Hash)
      print_line(k) if i.zero?
      @indent += indent_step
      @kw -= 2
      _two_columns([w], kw - indent_step)
      print_line('', '---') unless i == v.size - 1
    else
      if i.zero?
        print_line(k, v.shift)
      else
        print_line('', w)
      end
    end
  end
end

Print a single line of output

Parameters:

  • key (String)

    what to print in the first (key) column

  • val (String, Numeric)

    what to print in the second column

  • indent (Integer)

    number of leading spaces on line



179
180
181
182
183
184
185
# File 'lib/wavefront-cli/display/base.rb', line 179

def print_line(key, value = '')
  if key.empty?
    puts ' ' * kw + value
  else
    puts indent_str + format("%-#{kw}s%s", key, value).fold(TW, kw)
  end
end

#readable_time(*keys) ⇒ Object

Modify, in-place, the data structure to make times human-readable. Automatically handles second and millisecond epoch times.



271
272
273
274
275
276
# File 'lib/wavefront-cli/display/base.rb', line 271

def readable_time(*keys)
  keys.each do |k|
    next unless data.key?(k)
    data[k] = human_time(data[k])
  end
end

#run(method) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/wavefront-cli/display/base.rb', line 37

def run(method)
  if method == 'do_list'
    if options[:long]
      do_list
    else
      do_list_brief
    end

    return
  end

  if respond_to?("#{method}_brief")
    send("#{method}_brief")
  elsif respond_to?(method)
    send(method)
  else
    long_output
  end
end

#run_error(method) ⇒ Object

Display classes can provide a do_method_code() method, which handles <code> errors when running do_method()



23
24
25
26
27
# File 'lib/wavefront-cli/display/base.rb', line 23

def run_error(method)
  return unless respond_to?(method)
  send(method)
  exit 1
end

#set_indent(indent) ⇒ Object



108
109
110
# File 'lib/wavefront-cli/display/base.rb', line 108

def set_indent(indent)
  @indent_str = ' ' * indent
end

#terse_output(col1 = :id, col2 = :name, modified_data = nil) ⇒ Nil

Extract two fields from a hash and print a list of them as pairs.

Parameters:

  • col1 (String) (defaults to: :id)

    the field to use in the first column

  • col2 (String) (defaults to: :name)

    the field to use in the second column

Returns:

  • (Nil)


68
69
70
71
72
73
74
75
76
77
78
# File 'lib/wavefront-cli/display/base.rb', line 68

def terse_output(col1 = :id, col2 = :name, modified_data = nil)
  d = modified_data || data
  want = d.each_with_object({}) { |r, a| a[r[col1]] = r[col2] }
  @indent_str = ''
  @kw = key_width(want)

  want.each do |k, v|
    v = v.join(', ') if v.is_a?(Array)
    print_line(k, v)
  end
end