Skip to content

Commit

Permalink
Merge pull request #854 from p8/refactor/extract-printers
Browse files Browse the repository at this point in the history
Extract print methods to seperate classes
  • Loading branch information
rafaelfranca authored Aug 22, 2023
2 parents f98f4a9 + 580234a commit 9c9ab52
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 144 deletions.
152 changes: 11 additions & 141 deletions lib/thor/shell/basic.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
require_relative "column_printer"
require_relative "table_printer"
require_relative "wrapped_printer"

class Thor
module Shell
class Basic
DEFAULT_TERMINAL_WIDTH = 80

attr_accessor :base
attr_reader :padding

Expand Down Expand Up @@ -161,16 +163,8 @@ def no?(statement, color = nil)
# Array[String, String, ...]
#
def print_in_columns(array)
return if array.empty?
colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
array.each_with_index do |value, index|
# Don't output trailing spaces when printing the last column
if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
stdout.puts value
else
stdout.printf("%-#{colwidth}s", value)
end
end
printer = ColumnPrinter.new(stdout)
printer.print(array)
end

# Prints a table.
Expand All @@ -183,56 +177,8 @@ def print_in_columns(array)
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
#
def print_table(array, options = {}) # rubocop:disable Metrics/MethodLength
return if array.empty?

formats = []
indent = options[:indent].to_i
colwidth = options[:colwidth]
options[:truncate] = terminal_width if options[:truncate] == true

formats << "%-#{colwidth + 2}s".dup if colwidth
start = colwidth ? 1 : 0

colcount = array.max { |a, b| a.size <=> b.size }.size

maximas = []

start.upto(colcount - 1) do |index|
maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
maximas << maxima
formats << if index == colcount - 1
# Don't output 2 trailing spaces when printing the last column
"%-s".dup
else
"%-#{maxima + 2}s".dup
end
end

formats[0] = formats[0].insert(0, " " * indent)
formats << "%s"

array.each do |row|
sentence = "".dup

row.each_with_index do |column, index|
maxima = maximas[index]

f = if column.is_a?(Numeric)
if index == row.size - 1
# Don't output 2 trailing spaces when printing the last column
"%#{maxima}s"
else
"%#{maxima}s "
end
else
formats[index]
end
sentence << f % column.to_s
end

sentence = truncate(sentence, options[:truncate]) if options[:truncate]
stdout.puts sentence
end
printer = TablePrinter.new(stdout, options)
printer.print(array)
end

# Prints a long string, word-wrapping the text to the current width of the
Expand All @@ -245,33 +191,8 @@ def print_table(array, options = {}) # rubocop:disable Metrics/MethodLength
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
#
def print_wrapped(message, options = {})
indent = options[:indent] || 0
width = terminal_width - indent
paras = message.split("\n\n")

paras.map! do |unwrapped|
words = unwrapped.split(" ")
counter = words.first.length
words.inject do |memo, word|
word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
counter = 0 if word.include? "\n"
if (counter + word.length + 1) < width
memo = "#{memo} #{word}"
counter += (word.length + 1)
else
memo = "#{memo}\n#{word}"
counter = word.length
end
memo
end
end.compact!

paras.each do |para|
para.split("\n").each do |line|
stdout.puts line.insert(0, " " * indent)
end
stdout.puts unless para == paras.last
end
printer = WrappedPrinter.new(stdout, options)
printer.print(message)
end

# Deals with file collision and returns true if the file should be
Expand Down Expand Up @@ -321,19 +242,6 @@ def file_collision(destination)
end
end

# This code was copied from Rake, available under MIT-LICENSE
# Copyright (c) 2003, 2004 Jim Weirich
def terminal_width
result = if ENV["THOR_COLUMNS"]
ENV["THOR_COLUMNS"].to_i
else
unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
end
result < 10 ? DEFAULT_TERMINAL_WIDTH : result
rescue
DEFAULT_TERMINAL_WIDTH
end

# Called if something goes wrong during the execution. This is used by Thor
# internally and should not be used inside your scripts. If something went
# wrong, you can always raise an exception. If you raise a Thor::Error, it
Expand Down Expand Up @@ -416,46 +324,8 @@ def quiet? #:nodoc:
mute? || (base && base.options[:quiet])
end

# Calculate the dynamic width of the terminal
def dynamic_width
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
end

def dynamic_width_stty
`stty size 2>/dev/null`.split[1].to_i
end

def dynamic_width_tput
`tput cols 2>/dev/null`.to_i
end

def unix?
RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
end

def truncate(string, width)
as_unicode do
chars = string.chars.to_a
if chars.length <= width
chars.join
else
chars[0, width - 3].join + "..."
end
end
end

if "".respond_to?(:encode)
def as_unicode
yield
end
else
def as_unicode
old = $KCODE
$KCODE = "U"
yield
ensure
$KCODE = old
end
Terminal.unix?
end

def ask_simply(statement, color, options)
Expand Down
29 changes: 29 additions & 0 deletions lib/thor/shell/column_printer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require_relative "terminal"

class Thor
module Shell
class ColumnPrinter
attr_reader :stdout, :options

def initialize(stdout, options = {})
@stdout = stdout
@options = options
@indent = options[:indent].to_i
end

def print(array)
return if array.empty?
colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
array.each_with_index do |value, index|
# Don't output trailing spaces when printing the last column
if ((((index + 1) % (Terminal.terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
stdout.puts value
else
stdout.printf("%-#{colwidth}s", value)
end
end
end
end
end
end

95 changes: 95 additions & 0 deletions lib/thor/shell/table_printer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
require_relative "column_printer"
require_relative "terminal"

class Thor
module Shell
class TablePrinter < ColumnPrinter
def initialize(stdout, options = {})
super
@formats = []
@maximas = []
@colwidth = options[:colwidth]
@truncate = options[:truncate] == true ? Terminal.terminal_width : options[:truncate]
end

def print(array)
return if array.empty?

prepare(array)

array.each do |row|
sentence = "".dup

row.each_with_index do |column, index|
maxima = @maximas[index]

f = if column.is_a?(Numeric)
if index == row.size - 1
# Don't output 2 trailing spaces when printing the last column
"%#{maxima}s"
else
"%#{maxima}s "
end
else
@formats[index]
end
sentence << f % column.to_s
end

sentence = truncate(sentence)
stdout.puts sentence
end
end

private

def prepare(array)
@formats << "%-#{@colwidth + 2}s".dup if @colwidth
start = @colwidth ? 1 : 0

colcount = array.max { |a, b| a.size <=> b.size }.size

start.upto(colcount - 1) do |index|
maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
@maximas << maxima
@formats << if index == colcount - 1
# Don't output 2 trailing spaces when printing the last column
"%-s".dup
else
"%-#{maxima + 2}s".dup
end
end

@formats[0] = @formats[0].insert(0, " " * @indent)
@formats << "%s"
end

def truncate(string)
return string unless @truncate
as_unicode do
chars = string.chars.to_a
if chars.length <= @truncate
chars.join
else
chars[0, @truncate - 3].join + "..."
end
end
end

if "".respond_to?(:encode)
def as_unicode
yield
end
else
def as_unicode
old = $KCODE # rubocop:disable Style/GlobalVars
$KCODE = "U" # rubocop:disable Style/GlobalVars
yield
ensure
$KCODE = old # rubocop:disable Style/GlobalVars
end
end
end
end
end

42 changes: 42 additions & 0 deletions lib/thor/shell/terminal.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
class Thor
module Shell
module Terminal
DEFAULT_TERMINAL_WIDTH = 80

class << self
# This code was copied from Rake, available under MIT-LICENSE
# Copyright (c) 2003, 2004 Jim Weirich
def terminal_width
result = if ENV["THOR_COLUMNS"]
ENV["THOR_COLUMNS"].to_i
else
unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
end
result < 10 ? DEFAULT_TERMINAL_WIDTH : result
rescue
DEFAULT_TERMINAL_WIDTH
end

def unix?
RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
end

private

# Calculate the dynamic width of the terminal
def dynamic_width
@dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
end

def dynamic_width_stty
`stty size 2>/dev/null`.split[1].to_i
end

def dynamic_width_tput
`tput cols 2>/dev/null`.to_i
end

end
end
end
end
Loading

0 comments on commit 9c9ab52

Please sign in to comment.