module IPAddress::ToSWithNetmaskForNetworks refine IPAddress::IPv6 do def to_s 128 == prefix ? super() : to_string end end refine IPAddress::IPv4 do def to_s 32 == prefix ? super() : to_string end end end class Measured class V attr_reader :value, :length def initialize( value, length = nil) @value, @length = value, length || value.length end def inspect() "#" end alias :to_s :value alias :to_str :value end class < v %w[KiB MiBy GiByt TiByte ExiByte PetiByte].each_with_index do |m| v /= 1024 return units '%.1f ' % v, m if 512 > v end units '%d ' % v, :PetiByte end def bytes2 v r = (v.to_i / 1024 / 1024).to_s return '·' if 0 == r r. reverse. each_char. each_slice( 3). to_a. reverse. map {|a| a.reverse.join }. join " " end alias bytes bytes2 def units val, unit v = "#{val}\e[1;30m#{unit}\e[0m" V.new v, v.length - 11 end def seconds i i = i.to_i return V.new "\e[1;30m·\e[0m", 1 if 0 == i return units '%d ' % i, :s if 90 > i i /= 60 return units '%d ' % i, :mi if 90 > i i /= 60 return units '%d ' % i, :hou if 36 > i i /= 24 return units '%d ' % i, :days if 14 > i j = i / 7 return units '%d ' % j, :weeks if 8 > j j = i / 30 return units '%d ' % j, :months if 11 > j i /= 365.0 return units '%.2f ' % i, :years if 550 > i units '%d ' % i, :years end end end class ColoredString attr_reader :string, :color_codes def initialize string, color_codes @string, @color_codes = string, color_codes end def inspect "#" end def length() @string.length end alias size length def to_s() "\e[#{@color_codes}m#{@string}\e[0m" end alias to_str to_s include Comparable def <=>(o) @string <=> o.string end end class TablizedOutput def initialize header, stdout: nil, format: nil @header = header.map &:to_s @columnc = header.size @format = format || ['>']*@columnc @maxs = header.map &:length @stdout ||= STDOUT @lines = [] end class B include Comparable def <=>(o) @v <=> o.v end end class V < B attr_reader :v, :s def initialize( v, s=nil) @v, @s = v, s || "#{v}" end def to_s() @s.to_s end def length() @s.length end def inspect() "#" end end class Percentage < B attr_reader :v, :w def initialize( v, w=nil) @v, @w = v, w || 10 end def length() @w end def inspect() "#" end def to_s vw = v*w percent = (100*v).round vwi = vw.to_i rounded = (vw+0.5).to_i s = "%*s" % [w, 0==percent ? '·' : percent] pre = "\e[1;4;#{0.75>v ? 32 : 31}m" mid = (vw % 1) > 0.5 ? "\e[2m" : "\e[0m" "#{pre}#{s[0...vwi]}#{mid}#{s[vwi]}\e[0m#{s[(vwi+1)..-1]}" end end def push fields fields = fields.map do |x| case x when String, ColoredString, B then x else V.new x end end @maxs = @columnc.times.map {|i| [@maxs[i], fields[i].length].max } @lines.push fields end def pushs lines lines.each &method( :push) end def print order: nil ls = @lines if order eval <<-EOC, binding, __FILE__, 1+__LINE__ ls = ls.sort {|a,b| [#{order.map {|i| 0 < i ? "a[#{i-1}]" : "b[#{-i-1}]" }.join ', '}] <=> [#{order.map {|i| 0 < i ? "b[#{i-1}]" : "a[#{-i-1}]" }.join ', '}] } EOC end @stdout.puts \ @header.each_with_index.map {|s, i| "#{' ' * (@maxs[i] - s.length)}#{s}" }.join( ' | ') ls.each_with_index do |l, i| @stdout.puts \ l.each_with_index.map {|s, i| pad = ' ' * (@maxs[i] - s.length) case @format[i] when '<' "#{s}#{pad}" else "#{pad}#{s}" end }.join( "\e[3#{i.even? ? 6 : 3}m | \e[0m") end end end