Class: Aspera::Cli::Formatter
- Inherits:
-
Object
- Object
- Aspera::Cli::Formatter
- Defined in:
- lib/aspera/cli/formatter.rb
Overview
Take care of output
Instance Attribute Summary collapse
-
#option_display ⇒ Object
Returns the value of attribute option_display.
-
#option_fields ⇒ Object
Returns the value of attribute option_fields.
-
#option_flat_hash ⇒ Object
Returns the value of attribute option_flat_hash.
-
#option_format ⇒ Object
Returns the value of attribute option_format.
-
#option_select ⇒ Object
Returns the value of attribute option_select.
-
#option_show_secrets ⇒ Object
Returns the value of attribute option_show_secrets.
-
#option_table_style ⇒ Object
Returns the value of attribute option_table_style.
-
#option_transpose_single ⇒ Object
Returns the value of attribute option_transpose_single.
Class Method Summary collapse
- .flatten_config_overview(hash_array_conf) ⇒ Object
-
.flatten_name_value_list(hash) ⇒ Object
special for Aspera on Cloud display node => [{“name”=>“foo”,“value”=>“bar”]} will be expanded to : “bar”.
-
.flattened_object(source, result: {}, prefix: '', expand_last: false) ⇒ Object
recursive function to modify a hash.
- .simple_hash?(h) ⇒ Boolean
Instance Method Summary collapse
- #display_item_count(number, total) ⇒ Object
-
#display_message(message_level, message) ⇒ Object
main output method data: for requested data, not displayed if level==error info: additional info, displayed if level==info error: always displayed on stderr.
-
#display_results(results) ⇒ Object
this method displays the results, especially the table format.
- #display_status(status) ⇒ Object
-
#initialize(opt_mgr) ⇒ Formatter
constructor
adds options but does not parse.
- #result_all_fields(_results, table_rows_hash_val) ⇒ Object
- #result_default_fields(results, table_rows_hash_val) ⇒ Object
Constructor Details
#initialize(opt_mgr) ⇒ Formatter
adds options but does not parse
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/aspera/cli/formatter.rb', line 76 def initialize(opt_mgr) @option_format = :table @option_display = :info @option_fields = FIELDS_DEFAULT @option_select = nil @option_table_style = ':.:' @option_flat_hash = true @option_transpose_single = true @option_show_secrets = false opt_mgr.declare(:format, 'Output format', values: DISPLAY_FORMATS, handler: {o: self, m: :option_format}) opt_mgr.declare(:display, 'Output only some information', values: DISPLAY_LEVELS, handler: {o: self, m: :option_display}) opt_mgr.declare(:fields, "Comma separated list of fields, or #{FIELDS_ALL}, or #{FIELDS_DEFAULT}", handler: {o: self, m: :option_fields}) opt_mgr.declare(:select, 'Select only some items in lists: column, value', types: Hash, handler: {o: self, m: :option_select}) opt_mgr.declare(:table_style, 'Table display style', handler: {o: self, m: :option_table_style}) opt_mgr.declare(:flat_hash, 'Display deep values as additional keys', values: :bool, handler: {o: self, m: :option_flat_hash}) opt_mgr.declare(:transpose_single, 'Single object fields output vertically', values: :bool, handler: {o: self, m: :option_transpose_single}) opt_mgr.declare(:show_secrets, 'Show secrets on command output', values: :bool, handler: {o: self, m: :option_show_secrets}) end |
Instance Attribute Details
#option_display ⇒ Object
Returns the value of attribute option_display.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_display @option_display end |
#option_fields ⇒ Object
Returns the value of attribute option_fields.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_fields @option_fields end |
#option_flat_hash ⇒ Object
Returns the value of attribute option_flat_hash.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_flat_hash @option_flat_hash end |
#option_format ⇒ Object
Returns the value of attribute option_format.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_format @option_format end |
#option_select ⇒ Object
Returns the value of attribute option_select.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_select @option_select end |
#option_show_secrets ⇒ Object
Returns the value of attribute option_show_secrets.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_show_secrets @option_show_secrets end |
#option_table_style ⇒ Object
Returns the value of attribute option_table_style.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_table_style @option_table_style end |
#option_transpose_single ⇒ Object
Returns the value of attribute option_transpose_single.
72 73 74 |
# File 'lib/aspera/cli/formatter.rb', line 72 def option_transpose_single @option_transpose_single end |
Class Method Details
.flatten_config_overview(hash_array_conf) ⇒ Object
40 41 42 43 44 45 46 47 48 |
# File 'lib/aspera/cli/formatter.rb', line 40 def flatten_config_overview(hash_array_conf) r = [] hash_array_conf.each do |config, preset| preset.each do |parameter, value| r.push(CONF_OVERVIEW_KEYS.zip([config, parameter, SecretHider.deep_remove_secret(value).to_s]).to_h) end end return r end |
.flatten_name_value_list(hash) ⇒ Object
special for Aspera on Cloud display node => [{“name”=>“foo”,“value”=>“bar”]} will be expanded to : “bar”
29 30 31 32 33 34 35 36 37 38 |
# File 'lib/aspera/cli/formatter.rb', line 29 def flatten_name_value_list(hash) hash.keys.each do |k| # rubocop:disable Style/HashEachMethods v = hash[k] next unless v.is_a?(Array) && v.map(&:class).uniq.eql?([Hash]) && v.map(&:keys).flatten.sort.uniq.eql?(%w[name value]) v.each do |pair| hash["#{k}.#{pair['name']}"] = pair['value'] end hash.delete(k) end end |
.flattened_object(source, result: {}, prefix: '', expand_last: false) ⇒ Object
recursive function to modify a hash
59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/aspera/cli/formatter.rb', line 59 def flattened_object(source, result: {}, prefix: '', expand_last: false) Log.log.debug{"(#{expand_last})[#{simple_hash?(source)}] -#{source.values}- \n-#{source}-"} source.each do |k, v| if v.is_a?(Hash) && !( && simple_hash?(v)) flattened_object(v, result: result, prefix: prefix + k.to_s + '.', expand_last: ) else result[prefix + k.to_s] = v end end return result end |
.simple_hash?(h) ⇒ Boolean
50 51 52 |
# File 'lib/aspera/cli/formatter.rb', line 50 def simple_hash?(h) !(h.values.any?{|v|[Hash, Array].any?{|c|v.is_a?(c)}}) end |
Instance Method Details
#display_item_count(number, total) ⇒ Object
112 113 114 115 116 |
# File 'lib/aspera/cli/formatter.rb', line 112 def display_item_count(number, total) count_msg = "Items: #{number}/#{total}" count_msg = count_msg.bg_red unless number.to_i.eql?(total.to_i) display_status(count_msg) end |
#display_message(message_level, message) ⇒ Object
main output method data: for requested data, not displayed if level==error info: additional info, displayed if level==info error: always displayed on stderr
99 100 101 102 103 104 105 106 |
# File 'lib/aspera/cli/formatter.rb', line 99 def (, ) case when :data then $stdout.puts() unless @option_display.eql?(:error) when :info then $stdout.puts() if @option_display.eql?(:info) when :error then $stderr.puts() else raise "wrong message_level:#{message_level}" end end |
#display_results(results) ⇒ Object
this method displays the results, especially the table format
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/aspera/cli/formatter.rb', line 138 def display_results(results) raise "INTERNAL ERROR, result must be Hash (got: #{results.class}: #{results})" unless results.is_a?(Hash) raise 'INTERNAL ERROR, result must have type' unless results.key?(:type) raise 'INTERNAL ERROR, result must have data' unless results.key?(:data) || i[empty nothing].include?(results[:type]) res_data = results[:data] # for config overview, it is name and value is_config_overview = res_data.is_a?(Array) && !res_data.empty? && res_data.first.is_a?(Hash) && res_data.first.keys.sort.eql?(CONF_OVERVIEW_KEYS) SecretHider.deep_remove_secret(res_data, is_name_value: is_config_overview) unless @option_show_secrets || @option_display.eql?(:data) # comma separated list in string format user_asked_fields_list_str = @option_fields case @option_format when :text (:data, res_data.to_s) when :nagios Nagios.process(res_data) when :ruby (:data, PP.pp(res_data, +'')) when :json (:data, JSON.generate(res_data)) when :jsonpp (:data, JSON.pretty_generate(res_data)) when :yaml (:data, res_data.to_yaml) when :table, :csv if !@option_transpose_single && results[:type].eql?(:single_object) results[:type] = :object_list res_data = [res_data] end case results[:type] when :object_list # goes to table display raise "internal error: unexpected type: #{res_data.class}, expecting Array" unless res_data.is_a?(Array) # :object_list is an array of hash tables, where key=colum name table_rows_hash_val = res_data final_table_columns = nil if @option_flat_hash table_rows_hash_val.map!{|obj|self.class.flattened_object(obj, expand_last: results[:option_expand_last])} end final_table_columns = case user_asked_fields_list_str when FIELDS_DEFAULT then result_default_fields(results, table_rows_hash_val) when FIELDS_ALL then result_all_fields(results, table_rows_hash_val) else if user_asked_fields_list_str.start_with?('+') result_default_fields(results, table_rows_hash_val).push(*user_asked_fields_list_str.gsub(/^\+/, '').split(',')) elsif user_asked_fields_list_str.start_with?('-') result_default_fields(results, table_rows_hash_val).reject{|i| user_asked_fields_list_str.gsub(/^-/, '').split(',').include?(i)} else user_asked_fields_list_str.split(',') end end when :single_object # goes to table display # :single_object is a simple hash table (can be nested) raise "internal error: expecting Hash: got #{res_data.class}: #{res_data}" unless res_data.is_a?(Hash) final_table_columns = results[:columns] || KEY_VALUE if @option_flat_hash res_data = self.class.flattened_object(res_data, expand_last: results[:option_expand_last]) self.class.flatten_name_value_list(res_data) end asked_fields = case user_asked_fields_list_str when FIELDS_DEFAULT then results[:fields] || res_data.keys when FIELDS_ALL then res_data.keys else user_asked_fields_list_str.split(',') end table_rows_hash_val = asked_fields.map { |i| { final_table_columns.first => i, final_table_columns.last => res_data[i] } } # if only one row, and columns are key/value, then display the value only if table_rows_hash_val.length == 1 && final_table_columns.eql?(KEY_VALUE) (:data, res_data.values.first) return end when :value_list # goes to table display # :value_list is a simple array of values, name of column provided in the :name final_table_columns = [results[:name]] table_rows_hash_val = res_data.map { |i| { results[:name] => i } } when :empty # no table (:info, 'empty') return when :nothing # no result expected Log.log.debug('no result expected') return when :status # no table # :status displays a simple message (:info, res_data) return when :text # no table # :status displays a simple message (:data, res_data) return when :other_struct # no table # :other_struct is any other type of structure (:data, PP.pp(res_data, +'')) return else raise "unknown data type: #{results[:type]}" end # here we expect: table_rows_hash_val and final_table_columns raise 'no field specified' if final_table_columns.nil? if table_rows_hash_val.empty? (:info, 'empty'.gray) if @option_format.eql?(:table) return end # convert to string with special function. here table_rows_hash_val is an array of hash table_rows_hash_val = results[:textify].call(table_rows_hash_val) if results.key?(:textify) unless @option_select.nil? || (@option_select.respond_to?(:empty?) && @option_select.empty?) raise CliBadArgument, "expecting hash for select, have #{@option_select.class}: #{@option_select}" unless @option_select.is_a?(Hash) @option_select.each{|k, v|table_rows_hash_val.select!{|i|i[k].eql?(v)}} end # convert data to string, and keep only display fields final_table_rows = table_rows_hash_val.map { |r| final_table_columns.map { |c| r[c].to_s } } # here : final_table_columns : list of column names # here: final_table_rows : array of list of value case @option_format when :table style = @option_table_style.chars # display the table ! (:data, Terminal::Table.new( headings: final_table_columns, rows: final_table_rows, border_x: style[0], border_y: style[1], border_i: style[2])) when :csv (:data, final_table_rows.map{|t| t.join(CSV_FIELD_SEPARATOR)}.join(CSV_RECORD_SEPARATOR)) end end end |
#display_status(status) ⇒ Object
108 109 110 |
# File 'lib/aspera/cli/formatter.rb', line 108 def display_status(status) (:info, status) end |
#result_all_fields(_results, table_rows_hash_val) ⇒ Object
131 132 133 134 135 |
# File 'lib/aspera/cli/formatter.rb', line 131 def result_all_fields(_results, table_rows_hash_val) raise 'internal error: must be array' unless table_rows_hash_val.is_a?(Array) # get the list of all column names used in all lines, not just first one, as all lines may have different columns return table_rows_hash_val.each_with_object({}){|v, m|v.each_key{|c|m[c] = true}; }.keys end |
#result_default_fields(results, table_rows_hash_val) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/aspera/cli/formatter.rb', line 118 def result_default_fields(results, table_rows_hash_val) unless results[:fields].nil? raise "internal error: [fields] must be Array, not #{results[:fields].class}" unless results[:fields].is_a?(Array) if results[:fields].first.eql?(:all_but) && !table_rows_hash_val.empty? filter = results[:fields][1..-1] return table_rows_hash_val.first.keys.reject{|i|filter.include?(i)} end return results[:fields] end return ['empty'] if table_rows_hash_val.empty? return table_rows_hash_val.first.keys end |