Index: shell/commands/describe.rb =================================================================== --- shell/commands/describe.rb (revision 1590572) +++ shell/commands/describe.rb (working copy) @@ -17,6 +17,9 @@ # limitations under the License. # +# Uses terminal_table from https://github.com/visionmedia/terminal-table +require 'terminal-table' + module Shell module Commands class Describe < Command @@ -32,10 +35,12 @@ now = Time.now desc = admin.describe(table) - - formatter.header([ "DESCRIPTION", "ENABLED" ], [ 64 ]) - formatter.row([ desc, admin.enabled?(table).to_s ], true, [ 64 ]) - formatter.footer(now) + + rows = [] + rows << [desc, admin.enabled?(table).to_s] + + table = Terminal::Table.new :headings => ['DESCRIPTION', 'ENABLED'], :rows => rows, :style => {:width => 60, :padding_left => 3, :border_x => "=", :border_i => "+", :alignment => :center} + end end end Index: terminal-table/cell.rb =================================================================== --- terminal-table/cell.rb (revision 0) +++ terminal-table/cell.rb (working copy) @@ -0,0 +1,94 @@ + +module Terminal + class Table + class Cell + + ## + # Cell width. + + attr_reader :width + + ## + # Cell value. + + attr_reader :value + + ## + # Column span. + + attr_reader :colspan + + ## + # Initialize with _options_. + + def initialize options = nil + @value, options = options, {} unless Hash === options + @value = options.fetch :value, value + @alignment = options.fetch :alignment, nil + @colspan = options.fetch :colspan, 1 + @width = options.fetch :width, @value.to_s.size + @index = options.fetch :index + @table = options.fetch :table + end + + def alignment? + !@alignment.nil? + end + + def alignment + @alignment || @table.style.alignment || :left + end + + def alignment=(val) + supported = %w(left center right) + if supported.include?(val.to_s) + @alignment = val + else + raise "Aligment must be one of: #{supported.join(' ')}" + end + end + + def lines + @value.to_s.split(/\n/) + end + + ## + # Render the cell. + + def render(line = 0) + left = " " * @table.style.padding_left + right = " " * @table.style.padding_right + render_width = lines[line].to_s.size - escape(lines[line]).size + width + "#{left}#{lines[line]}#{right}".align(alignment, render_width + @table.cell_padding) + end + alias :to_s :render + + ## + # Returns the longest line in the cell and + # removes all ANSI escape sequences (e.g. color) + + def value_for_column_width_recalc + lines.map{ |s| escape(s) }.max_by{ |s| s.size } + end + + ## + # Returns the width of this cell + + def width + padding = (colspan - 1) * @table.cell_spacing + inner_width = (1..@colspan).to_a.inject(0) do |w, counter| + w + @table.column_width(@index + counter - 1) + end + inner_width + padding + end + + ## + # removes all ANSI escape sequences (e.g. color) + def escape(line) + line.to_s.gsub(/\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]/, ''). + gsub(/\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]/, ''). + gsub(/(\x03|\x1a)/, '') + end + end + end +end Index: terminal-table/core_ext.rb =================================================================== --- terminal-table/core_ext.rb (revision 0) +++ terminal-table/core_ext.rb (working copy) @@ -0,0 +1,8 @@ + +class String + def align position, length + self.__send__ position, length + end + alias_method :left, :ljust + alias_method :right, :rjust +end \ No newline at end of file Index: terminal-table/import.rb =================================================================== --- terminal-table/import.rb (revision 0) +++ terminal-table/import.rb (working copy) @@ -0,0 +1,4 @@ + +require 'terminal-table' + +include Terminal::Table::TableHelper Index: terminal-table/row.rb =================================================================== --- terminal-table/row.rb (revision 0) +++ terminal-table/row.rb (working copy) @@ -0,0 +1,48 @@ +module Terminal + class Table + class Row + + ## + # Row cells + + attr_reader :cells + + attr_reader :table + + ## + # Initialize with _width_ and _options_. + + def initialize table, array = [] + @cell_index = 0 + @table = table + @cells = [] + array.each { |item| self << item } + end + + def add_cell item + options = item.is_a?(Hash) ? item : {:value => item} + cell = Cell.new(options.merge(:index => @cell_index, :table => @table)) + @cell_index += cell.colspan + @cells << cell + end + alias << add_cell + + def [] index + cells[index] + end + + def height + cells.map { |c| c.lines.count }.max + end + + def render + y = @table.style.border_y + (0...height).to_a.map do |line| + y + cells.map do |cell| + cell.render(line) + end.join(y) + y + end.join("\n") + end + end + end +end \ No newline at end of file Index: terminal-table/separator.rb =================================================================== --- terminal-table/separator.rb (revision 0) +++ terminal-table/separator.rb (working copy) @@ -0,0 +1,14 @@ +module Terminal + class Table + class Separator < Row + + def render + arr_x = (0...@table.number_of_columns).to_a.map do |i| + @table.style.border_x * (@table.column_width(i) + @table.cell_padding) + end + border_i = @table.style.border_i + border_i + arr_x.join(border_i) + border_i + end + end + end +end \ No newline at end of file Index: terminal-table/style.rb =================================================================== --- terminal-table/style.rb (revision 0) +++ terminal-table/style.rb (working copy) @@ -0,0 +1,62 @@ + +module Terminal + class Table + # A Style object holds all the formatting information for a Table object + # + # To create a table with a certain style, use either the constructor + # option :style, the Table#style object or the Table#style= method + # + # All these examples have the same effect: + # + # # by constructor + # @table = Table.new(:style => {:padding_left => 2, :width => 40}) + # + # # by object + # @table.style.padding_left = 2 + # @table.style.width = 40 + # + # # by method + # @table.style = {:padding_left => 2, :width => 40} + # + # To set a default style for all tables created afterwards use Style.defaults= + # + # Terminal::Table::Style.defaults = {:width => 80} + # + class Style + @@defaults = { + :border_x => "-", :border_y => "|", :border_i => "+", + :padding_left => 1, :padding_right => 1, + :width => nil, :alignment => nil + } + + attr_accessor :border_x + attr_accessor :border_y + attr_accessor :border_i + + attr_accessor :padding_left + attr_accessor :padding_right + + attr_accessor :width + attr_accessor :alignment + + + def initialize options = {} + apply self.class.defaults.merge(options) + end + + def apply options + options.each { |m, v| __send__ "#{m}=", v } + end + + class << self + def defaults + @@defaults + end + + def defaults= options + @@defaults = defaults.merge(options) + end + end + end + end +end Index: terminal-table/table.rb =================================================================== --- terminal-table/table.rb (revision 0) +++ terminal-table/table.rb (working copy) @@ -0,0 +1,220 @@ + +module Terminal + class Table + + attr_reader :title + attr_reader :headings + + ## + # Generates a ASCII table with the given _options_. + + def initialize options = {}, &block + @column_widths = [] + self.style = options.fetch :style, {} + self.headings = options.fetch :headings, [] + self.rows = options.fetch :rows, [] + self.title = options.fetch :title, nil + yield_or_eval(&block) if block + end + + ## + # Align column _n_ to the given _alignment_ of :center, :left, or :right. + + def align_column n, alignment + r = rows + column(n).each_with_index do |col, i| + cell = r[i][n] + cell.alignment = alignment unless cell.alignment? + end + end + + ## + # Add a row. + + def add_row array + row = array == :separator ? Separator.new(self) : Row.new(self, array) + @rows << row + recalc_column_widths row + end + alias :<< :add_row + + ## + # Add a separator. + + def add_separator + self << :separator + end + + def cell_spacing + cell_padding + style.border_y.length + end + + def cell_padding + style.padding_left + style.padding_right + end + + ## + # Return column _n_. + + def column n, method = :value, array = rows + array.map { |row| + cell = row[n] + cell && method ? cell.__send__(method) : cell + }.compact + end + + ## + # Return _n_ column including headings. + + def column_with_headings n, method = :value + column n, method, headings_with_rows + end + + ## + # Return columns. + + def columns + (0...number_of_columns).map { |n| column n } + end + + ## + # Return length of column _n_. + + def column_width n + width = @column_widths[n] || 0 + width + additional_column_widths[n].to_i + end + alias length_of_column column_width # for legacy support + + ## + # Return total number of columns available. + + def number_of_columns + headings_with_rows.map { |r| r.cells.size }.max + end + + ## + # Set the headings + + def headings= array + @headings = Row.new(self, array) + recalc_column_widths @headings + end + + ## + # Render the table. + + def render + separator = Separator.new(self) + buffer = [separator] + unless @title.nil? + buffer << Row.new(self, [title_cell_options]) + buffer << separator + end + unless @headings.cells.empty? + buffer << @headings + buffer << separator + end + buffer += @rows + buffer << separator + buffer.map { |r| r.render }.join("\n") + end + alias :to_s :render + + ## + # Return rows without separator rows. + + def rows + @rows.reject { |row| row.is_a? Separator } + end + + def rows= array + @rows = [] + array.each { |arr| self << arr } + end + + def style=(options) + style.apply options + end + + def style + @style ||= Style.new + end + + def title=(title) + @title = title + recalc_column_widths Row.new(self, [title_cell_options]) + end + + ## + # Check if _other_ is equal to self. _other_ is considered equal + # if it contains the same headings and rows. + + def == other + if other.respond_to? :render and other.respond_to? :rows + self.headings == other.headings and self.rows == other.rows + end + end + + private + + def columns_width + @column_widths.inject(0) { |s, i| s + i + cell_spacing } + style.border_y.length + end + + def additional_column_widths + return [] if style.width.nil? + spacing = style.width - columns_width + if spacing < 0 + raise "Table width exceeds wanted width of #{wanted} characters." + else + per_col = spacing / number_of_columns + arr = (1...number_of_columns).to_a.map { |i| per_col } + other_cols = arr.inject(0) { |s, i| s + i } + arr << spacing - other_cols + arr + end + end + + def recalc_column_widths row + return if row.is_a? Separator + i = 0 + row.cells.each do |cell| + colspan = cell.colspan + cell_value = cell.value_for_column_width_recalc + colspan.downto(1) do |j| + cell_length = cell_value.to_s.length + if colspan > 1 + spacing_length = cell_spacing * (colspan - 1) + length_in_columns = (cell_length - spacing_length) + cell_length = (length_in_columns.to_f / colspan).ceil + end + if @column_widths[i].to_i < cell_length + @column_widths[i] = cell_length + end + i = i + 1 + end + end + end + + ## + # Return headings combined with rows. + + def headings_with_rows + [@headings] + rows + end + + def yield_or_eval &block + return unless block + if block.arity > 0 + yield self + else + self.instance_eval(&block) + end + end + + def title_cell_options + {:value => @title, :alignment => :center, :colspan => number_of_columns} + end + end +end Property changes on: terminal-table/table.rb ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: terminal-table/table_helper.rb =================================================================== --- terminal-table/table_helper.rb (revision 0) +++ terminal-table/table_helper.rb (working copy) @@ -0,0 +1,9 @@ +module Terminal + class Table + module TableHelper + def table headings = [], *rows, &block + Terminal::Table.new :headings => headings.to_a, :rows => rows, &block + end + end + end +end Index: terminal-table/version.rb =================================================================== --- terminal-table/version.rb (revision 0) +++ terminal-table/version.rb (working copy) @@ -0,0 +1,6 @@ + +module Terminal + class Table + VERSION = '1.4.3' + end +end Index: terminal-table.rb =================================================================== --- terminal-table.rb (revision 0) +++ terminal-table.rb (working copy) @@ -0,0 +1,27 @@ +#-- +# Copyright (c) 2008-2009 TJ Holowaychuk +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#++ + +$:.unshift File.dirname(__FILE__) +%w(version core_ext table cell row separator style table_helper).each do |file| + require "terminal-table/#{file}" +end \ No newline at end of file