Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hammer_cli.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ EOF

s.add_dependency 'clamp', '~> 1.0'
s.add_dependency 'logging'
s.add_dependency 'unicode-display_width'
s.add_dependency 'awesome_print'
s.add_dependency 'table_print'
s.add_dependency 'highline'
Expand Down
2 changes: 2 additions & 0 deletions lib/hammer_cli/output/adapter/table.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'table_print'
require File.join(File.dirname(__FILE__), 'wrapper_formatter')
require 'hammer_cli/table_print/formatter'
require 'hammer_cli/table_print/column'

module HammerCLI::Output::Adapter

Expand Down
43 changes: 43 additions & 0 deletions lib/hammer_cli/output/utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require 'unicode/display_width'

module HammerCLI
module Output
module Utils
def self.real_length(value)
decolorized = value.gsub(/\033\[[^m]*m/, '')
Unicode::DisplayWidth.of(decolorized)
end

def self.real_char_length(ch)
Unicode::DisplayWidth.of(ch)
end

def self.real_truncate(value, required_size)
size = 0
index = 0
has_colors = false
in_color = false
value.each_char do |ch|
if in_color
in_color = false if ch == "m"
elsif ch == "\e"
has_colors = in_color = true
else
increment = real_char_length(ch)
if size + increment > required_size
if has_colors
return value[0..index-1] + "\e[0m", size
else
return value[0..index-1], size
end
else
size += increment
end
end
index += 1
end
return value, size
end
end
end
end
19 changes: 19 additions & 0 deletions lib/hammer_cli/table_print/column.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'hammer_cli/output/utils'

module TablePrint
class Column
def data_width
if multibyte_count
[
HammerCLI::Output::Utils.real_length(name),
Array(data).compact.collect(&:to_s).collect{|m| HammerCLI::Output::Utils.real_length(m) }.max
].compact.max || 0
else
[
name.length,
Array(data).compact.collect(&:to_s).collect(&:length).max
].compact.max || 0
end
end
end
end
18 changes: 18 additions & 0 deletions lib/hammer_cli/table_print/formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'hammer_cli/output/utils'

module TablePrint
class FixedWidthFormatter
def format(value)
value = value.to_s
padding = width - HammerCLI::Output::Utils.real_length(value)
if padding >= 0
value += (" " * padding)
else
value, real_length = HammerCLI::Output::Utils.real_truncate(value, width-3)
value += '...'
value += ' ' if real_length < (width - 3)
end
value
end
end
end
114 changes: 101 additions & 13 deletions test/unit/output/adapter/table_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@
[field_name]
}

let(:red) { "\e[1;31m" }
let(:reset) { "\e[0m" }

let(:record) { {
:id => 1,
:firstname => "John",
:lastname => "Doe",
:two_column_chars => "文字漢字",
:czech_chars => "žluťoučký kůň",
:colorized_name => "#{red}John#{reset}",
:fullname => "John Doe",
:long => "SomeVeryLongString"
:long => "SomeVeryLongString",
:colorized_long => "#{red}SomeVeryLongString#{reset}",
:two_column_long => "文字-Kanji-漢字-Hanja-漢字"
} }
let(:data) { HammerCLI::Output::RecordCollection.new [record] }
let(:empty_data) { HammerCLI::Output::RecordCollection.new [] }
Expand Down Expand Up @@ -90,6 +98,86 @@

context "column width" do

it "calculates correct width of two-column characters" do
first_field = Fields::Field.new(:path => [:two_column_chars], :label => "Some characters")
fields = [first_field, field_lastname]

expected_output = [
"----------------|---------",
"SOME CHARACTERS | LASTNAME",
"----------------|---------",
"文字漢字 | Doe ",
"----------------|---------",
""
].join("\n")

proc { adapter.print_collection(fields, data) }.must_output(expected_output)
end

it "calculates correct width of czech characters" do
first_field = Fields::Field.new(:path => [:czech_chars], :label => "Some characters")
fields = [first_field, field_lastname]

expected_output = [
"----------------|---------",
"SOME CHARACTERS | LASTNAME",
"----------------|---------",
"žluťoučký kůň | Doe ",
"----------------|---------",
""
].join("\n")

proc { adapter.print_collection(fields, data) }.must_output(expected_output)
end

it "calculates correct width of colorized strings" do
first_field = Fields::Field.new(:path => [:colorized_name], :label => "Colorized name")
fields = [first_field, field_lastname]

expected_output = [
"---------------|---------",
"COLORIZED NAME | LASTNAME",
"---------------|---------",
"John | Doe ",
"---------------|---------",
""
].join("\n").gsub('John', "#{red}John#{reset}")

proc { adapter.print_collection(fields, data) }.must_output(expected_output)
end

it "truncates two-column characters when it exceeds maximum width" do
first_field = Fields::Field.new(:path => [:two_column_long], :label => "Some characters", :max_width => 16)
fields = [first_field, field_lastname]

expected_output = [
"-----------------|---------",
"SOME CHARACTERS | LASTNAME",
"-----------------|---------",
"文字-Kanji-漢... | Doe ",
"-----------------|---------",
""
].join("\n")

proc { adapter.print_collection(fields, data) }.must_output(expected_output)
end

it "truncates colorized string string when it exceeds maximum width" do
first_field = Fields::Field.new(:path => [:colorized_long], :label => "Long", :max_width => 10)
fields = [first_field, field_lastname]

expected_output = [
"-----------|---------",
"LONG | LASTNAME",
"-----------|---------",
"SomeVer... | Doe ",
"-----------|---------",
""
].join("\n").gsub('SomeVer', "#{red}SomeVer#{reset}")

proc { adapter.print_collection(fields, data) }.must_output(expected_output)
end

it "truncates string when it exceeds maximum width" do
first_field = Fields::Field.new(:path => [:long], :label => "Long", :max_width => 10)
fields = [first_field, field_lastname]
Expand Down Expand Up @@ -122,18 +210,18 @@
proc { adapter.print_collection(fields, data) }.must_output(expected_output)
end

it "sets width to the longest column name when no data" do
first_field = Fields::Field.new(:path => [:long], :label => "VeryLongTableHeaderName")
fields = [first_field, field_lastname]

expected_output = [
"------------------------|---------",
"VERYLONGTABLEHEADERNAME | LASTNAME",
"------------------------|---------",
""
].join("\n")
proc { adapter.print_collection(fields, empty_data) }.must_output(expected_output)
end
it "sets width to the longest column name when no data" do
first_field = Fields::Field.new(:path => [:long], :label => "VeryLongTableHeaderName")
fields = [first_field, field_lastname]

expected_output = [
"------------------------|---------",
"VERYLONGTABLEHEADERNAME | LASTNAME",
"------------------------|---------",
""
].join("\n")
proc { adapter.print_collection(fields, empty_data) }.must_output(expected_output)
end

it "sets certain width" do
first_field = Fields::Field.new(:path => [:long], :label => "Long", :width => 25)
Expand Down