################################################################################ # # Author: Zachary Patten <zachary@jovelabs.net> # Copyright: Copyright (c) Jove Labs # License: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ################################################################################ require 'socket' require 'timeout' module ZTK # ZTK::Report Error Class # # @author Zachary Patten <zachary@jovelabs.net> class ReportError < Error; end # ZTK Report Class # # This class contains tools for generating spreadsheet or key-value list # styled output. Report methods are currently meant to be interchangeable; # that is one should be able to just switch which method they are calling # to change the output type. # # The idea here is that everything is auto-sized and simply displayed. # # @author Zachary Patten <zachary@jovelabs.net> class Report < ZTK::Base # @param [Hash] configuration Configuration options hash. def initialize(configuration={}) super({ }.merge(configuration)) config.ui.logger.debug { "config=#{config.send(:table).inspect}" } end # Displays data in a spreadsheet style. # # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+ # | NAME | ALIVE | ARCH | DISTRO | IP | MAC | CHEF VERSION | PERSIST | # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+ # | sudo | false | amd64 | ubuntu | 192.168.99.110 | 00:00:5e:34:d6:aa | N/A | true | # | timezone | false | amd64 | ubuntu | 192.168.122.47 | 00:00:5e:92:d7:f6 | N/A | true | # | chef-client | false | amd64 | ubuntu | 192.168.159.98 | 00:00:5e:c7:ce:26 | N/A | true | # | users | false | amd64 | ubuntu | 192.168.7.78 | 00:00:5e:89:f9:50 | N/A | true | # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+ # # @param [Array] dataset An array of items for which we want to generate a # report # @param [Array] headers An array of headers used for ordering the output. # @return [OpenStruct] def spreadsheet(dataset, headers, &block) !block_given? and log_and_raise(ReportError, "You must supply a block!") headers.nil? and log_and_raise(ReportError, "Headers can not be nil!") dataset.nil? and log_and_raise(ReportError, "Dataset can not be nil!") rows = Array.new max_lengths = OpenStruct.new headers = headers.map(&:downcase).map(&:to_sym) dataset.each do |data| rows << block.call(data) end headers.each do |header| maximum = [header, rows.collect{ |r| r.send(header) }].flatten.map(&:to_s).map(&:length).max max_lengths.send("#{header}=", maximum) end header_line = headers.collect do |header| "%-#{max_lengths.send(header)}s" % header.to_s.upcase end header_line = format_row(header_line) config.ui.stdout.puts(format_header(headers, max_lengths)) config.ui.stdout.puts(header_line) config.ui.stdout.puts(format_header(headers, max_lengths)) rows.each do |row| row_line = headers.collect do |header| "%-#{max_lengths.send(header)}s" % row.send(header) end row_line = format_row(row_line) config.ui.stdout.puts(row_line) end config.ui.stdout.puts(format_header(headers, max_lengths)) width = (2 + max_lengths.send(:table).values.reduce(:+) + ((headers.count * 3) - 3) + 2) OpenStruct.new(:rows => rows, :max_lengths => max_lengths, :width => width) end # Displays data in a key-value list style. # # +-------------------------------------------------------------------+ # | PROVIDER: Cucumber::Chef::Provider::Vagrant | # | ID: default | # | STATE: aborted | # | USERNAME: vagrant | # | IP ADDRESS: 127.0.0.1 | # | PORT: 2222 | # | CHEF-SERVER API: http://127.0.0.1:4000 | # | CHEF-SERVER WEBUI: http://127.0.0.1:4040 | # | CHEF-SERVER DEFAULT USER: admin | # | CHEF-SERVER DEFAULT PASSWORD: p@ssw0rd1 | # +-------------------------------------------------------------------+ # # @param [Array] dataset An array of items for which we want to generate a # report # @param [Array] headers An array of headers used for ordering the output. # @return [OpenStruct] def list(dataset, headers, &block) !block_given? and log_and_raise(ReportError, "You must supply a block!") headers.nil? and log_and_raise(ReportError, "Headers can not be nil!") dataset.nil? and log_and_raise(ReportError, "Dataset can not be nil!") rows = Array.new max_lengths = OpenStruct.new headers = headers.map(&:downcase).map(&:to_sym) dataset.each do |data| rows << block.call(data) end max_key_length = headers.collect{ |header| header.length }.max max_value_length = rows.collect{ |row| headers.collect{ |header| row.send(header).to_s.length }.max }.max width = (max_key_length + max_value_length + 2 + 2 + 2) rows.each do |row| config.ui.stdout.puts("+#{"-" * width}+") headers.each do |header| entry_line = format_entry(header, max_key_length, row.send(header), max_value_length) config.ui.stdout.puts(entry_line) end end config.ui.stdout.puts("+#{"-" * width}+") OpenStruct.new(:rows => rows, :max_key_length => max_key_length, :max_value_length => max_value_length, :width => width) end private def format_header(headers, lengths) line = headers.collect do |header| "-" * lengths.send(header) end ["+-", line.join("-+-"), "-+"].join.strip end def format_row(*args) spacer = " " [spacer, args, spacer].flatten.join(" | ").strip end def format_entry(key, key_length, value, value_length) "| %#{key_length}s: %-#{value_length}s |" % [key.to_s.upcase, value.to_s] end end end