# encoding: UTF-8 =begin Copyright 2012 Saverio Miroddi saverio.pub2 <a-hat!> gmail.com This file is part of SpreadBase. SpreadBase is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SpreadBase is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SpreadBase. If not, see <http://www.gnu.org/licenses/>. =end module SpreadBase # :nodoc: # Currently generic helper class # module Helpers # Safe alternative to "[ instance ] * repeats", which returns an array filled with the same instance, which is a recipe for a disaster # # The instance is duplicated Object#clone, when necessary - note that this method is not meant to do a deep copy. # def make_array_from_repetitions( instance, repetitions ) ( 1 .. repetitions ).inject( [] ) do | cumulative_result, i | case instance when Fixnum, Float, BigDecimal, Date, Time, TrueClass, FalseClass, NilClass #, DateTime is a Date cumulative_result << instance when String, Array cumulative_result << instance.clone else raise "Unsupported class: #{ }" end end end # Prints the 2d-array in a nice, fixed-space table # # _params_: # # +rows+:: 2d-array of values. # Empty arrays generate empty strings. # Entries can be of different sizes; nils are used as filling values to normalize the rows to the same length. # # _options_: # # +row_prefix+:: Prefix this string to each row. # +with_header+:: First row will be separated from the remaining ones. # # +formatting_block+:: If passed, values will be formatted by the block. # If no block is passed, or it returns nil or :standard, the standard formatting is used. # def pretty_print_rows( rows, options={}, &formatting_block ) row_prefix = options[ :row_prefix ] || '' with_headers = options[ :with_headers ] output = "" formatting_block = lambda { | value | value.to_s } if ! block_given? if rows.size > 0 max_column_sizes = [ 0 ] * rows.map( &:size ).max # Compute maximum widths rows.each do | values | values.each_with_index do | value, i | formatted_value = pretty_print_value( value, &formatting_block ) formatted_value_width = formatted_value.chars.to_a.size max_column_sizes[ i ] = formatted_value_width if formatted_value_width > max_column_sizes[ i ] end end # Print! output << row_prefix << '+-' + max_column_sizes.map { | size | '-' * size }.join( '-+-' ) + '-+' << "\n" print_pattern = '| ' + max_column_sizes.map { | size | "%-#{ size }s" }.join( ' | ' ) + ' |' rows.each_with_index do | row, row_index | # Ensure that we always have a number of values equal to the max width # formatted_row_values = ( 0 ... max_column_sizes.size ).map do | column_index | value = row[ column_index ] pretty_print_value( value, &formatting_block ) end output << row_prefix << print_pattern % formatted_row_values << "\n" if with_headers && row_index == 0 output << row_prefix << '+-' + max_column_sizes.map { | size | '-' * size }.join( '-+-' ) + '-+' << "\n" end end output << row_prefix << '+-' + max_column_sizes.map { | size | '-' * size }.join( '-+-' ) + '-+' << "\n" end output end private def pretty_print_value( value, &formatting_block ) custom_result = block_given? && yield( value ) if custom_result && custom_result != :standard custom_result else case value when BigDecimal value.to_s( 'F' ) when Time, DateTime # Time#to_s renders differently between 1.8.7 and 1.9.3; 1.8.7's rendering is bizarrely # inconsistent with the Date and DateTime ones. # value.strftime( '%Y-%m-%d %H:%M:%S %z' ) when String, Date, Numeric, TrueClass, FalseClass value.to_s when nil "NIL" else value.inspect end end end end end