4
\$\begingroup\$

GOAL:

  • Accept DSV strings where the delimiter may consist of more than one character
  • Accept DSV strings where there are no embedded delimiters
  • Output text with no modification to the source string other than aligning custom delimiter with optional padding

QUESTION:

  • Anyone have a re-factor or stylistic enhancement or two?

CODE:

module DreftymacAddon
  module String
    ### <region-fdef ddef="dsvpretty ;; lineup delims pretty print dsv text with lined up delimiters ">
    def dsvpretty(delim=';;',padd='')
      sout    =   ""
      asizes  =   []
      alines  =   self.to_s.split(/[\x0a\x0d]/)
      alines.each{|currline|
        currline.split(delim).each_with_index{|currfld,icc|
          asizes[icc] = [asizes[icc].to_i,currfld.length].max()
        }
      }
      alines.each{|currline|
        next if currline.strip == ''
        atemp   = []
        currline.split(delim).each_with_index{|currfld,icc|
          atemp << sprintf("%-#{asizes[icc]}s", currfld)
        }
        sout += atemp.join([padd , delim , padd].join(''))
        sout += "\n"
      }
      sout
    end
    alias :dsv_pretty :dsvpretty
    ### </region-fdef>
  end
end

class String
  include DreftymacAddon::String
end


### String.new().dsvpretty ;; example usage
##{
if(1000!=0);
  vout   = %Q[
    LNAME|FNAME|AMOUNT|AGE|NATION|PLATFORM
    Rodriguez|Johan|30.00|58|uk|windows_xp
    Raynor|Coty|40.00|14|uk|redhat
    Bruen|Jackie|30.00|17|uk|ubuntu
    Breitenberg|Waldo|20.00|14|canada|mac_osx
    Collier|Lucy|30.00|22|canada|windows_vista
    Blick|Emmett|30.00|59|canada|knoppix
    Schroeder|Myrtis|10.00|29|uk|knoppix
    Rodriguez|Ashtyn|20.00|22|uk|mac_osx
    Leuschke|Sigmund|40.00|21|france|redhat
    Fahey|Cassidy|40.00|29|canada|knoppix    
  ]

  puts vout.dsvpretty('|','')
=begin
    LNAME      |FNAME  |AMOUNT|AGE|NATION|PLATFORM     
    Rodriguez  |Johan  |30.00 |58 |uk    |windows_xp   
    Raynor     |Coty   |40.00 |14 |uk    |redhat       
    Bruen      |Jackie |30.00 |17 |uk    |ubuntu       
    Breitenberg|Waldo  |20.00 |14 |canada|mac_osx      
    Collier    |Lucy   |30.00 |22 |canada|windows_vista
    Blick      |Emmett |30.00 |59 |canada|knoppix      
    Schroeder  |Myrtis |10.00 |29 |uk    |knoppix      
    Rodriguez  |Ashtyn |20.00 |22 |uk    |mac_osx      
    Leuschke   |Sigmund|40.00 |21 |france|redhat       
    Fahey      |Cassidy|40.00 |29 |canada|knoppix
=end  

  puts vout.dsvpretty('|',' ')
=begin
    LNAME       | FNAME   | AMOUNT | AGE | NATION | PLATFORM     
    Rodriguez   | Johan   | 30.00  | 58  | uk     | windows_xp   
    Raynor      | Coty    | 40.00  | 14  | uk     | redhat       
    Bruen       | Jackie  | 30.00  | 17  | uk     | ubuntu       
    Breitenberg | Waldo   | 20.00  | 14  | canada | mac_osx      
    Collier     | Lucy    | 30.00  | 22  | canada | windows_vista
    Blick       | Emmett  | 30.00  | 59  | canada | knoppix      
    Schroeder   | Myrtis  | 10.00  | 29  | uk     | knoppix      
    Rodriguez   | Ashtyn  | 20.00  | 22  | uk     | mac_osx      
    Leuschke    | Sigmund | 40.00  | 21  | france | redhat       
    Fahey       | Cassidy | 40.00  | 29  | canada | knoppix
=end    

end
##} 
\$\endgroup\$
  • 1
    \$\begingroup\$ As usual I'd recommend re-writing it in functional style, code with side-effects is harder to understand. Are you insterested in how it'd look? \$\endgroup\$ – tokland May 9 '13 at 15:14
  • \$\begingroup\$ @tokland Yes, definitely. If and when you have a moment, if you could provide a quick sketch or demonstration link(s), that would be most appreciated. \$\endgroup\$ – dreftymac May 9 '13 at 15:19
5
\$\begingroup\$

Some notes:

  • include DreftymacAddon::String. Monkeypatching common classes is always controversial, but in this case I wouldn't do it, it's not a general enough abstraction.
  • As always, I'd recommend using functional style with Ruby (if you check my other answers in this site, it's all I do ;-)) unless you have a very good reason not to. No sout = "", asize = [], each, array[key] = value, += and other statements, use expressions.
  • dsvpretty(delim=';;',padd=''). This kind of signature is problematic, if you want to set padd you are forced to set also delim when you wanted to keep the default value. Use an options hash instead. Note that finally Ruby 2.0 provides keyword arguments.
  • each_with_index{|currfld,icc|. Let the block breathe, and don't forget spaces after commas: each_with_index { |currfld, icc|. More on idiomatic Ruby.

I'd write:

module DreftymacAddon
  def self.dsv_pretty(string, options = {})
    options = {:delim => ";", :padding => ""}.merge(options)
    rows = string.strip.split(/\n/).map { |line| line.strip.split(options[:delim]) }
    columns_max_width = rows.map { |row| row.map(&:size) }.transpose.map(&:max)
    columns_separator = options[:padding] + options[:delim] + options[:padding]

    rows.map do |row|
      row.zip(columns_max_width).map do |cell, column_max_width|
        cell.ljust(column_max_width)
      end.join(columns_separator)
    end.join("\n")
  end
end

puts DreftymacAddon::dsv_pretty(vout, :delim => '|', :padding => " ")
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Very nice, well-explained and well-substantiated refactoring, thanks for the links. Will have to upvote some of your other posts since it is not possible to multiple-upvote this one ;-) \$\endgroup\$ – dreftymac May 9 '13 at 18:57
  • \$\begingroup\$ @dreftymac: glad to help, thanks for the other upvotes :-) \$\endgroup\$ – tokland May 10 '13 at 8:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.