tags:

views:

111

answers:

2

I've tried and tried, but I can't make this less ugly/more ruby-like. It seems like there just must be a better way. Help me learn.

class Df
  attr_accessor :thresh
  attr_reader :dfo

  def initialize
      @dfo    = []
      @df     = '/opt/TWWfsw/bin/gdf'

      case RUBY_PLATFORM
      when /hpux/i
          @fstyp = 'vxfs'
      when /solaris/i
          # fix: need /tmp too
          @fstyp = 'ufs'
      when /linux/i
          @df = '/bin/df'
          @fstyp = 'ext3'
      end
      @dfo  = parsedf
  end
  def parsedf
      ldf = []
      [" "," -i"] .each do |arg|
          fields = %w{device size used avail capp mount}
          fields = %w{device inodes inodesused inodesavail iusep mount} if arg == ' -i'
          ldf.push %x{#{@df} -P -t #{@fstyp}#{arg}}.split(/\n/)[1..-1].collect{|line| Hash[*fields.zip(line.split).flatten]}
      end
      out = []
      # surely there must be an easier way
      ldf[0].each do |x|
          ldf[1].select { |y|
              if y['device'] == x['device']
                  out.push x.merge(y)
              end
          }
      end
      out
  end
end
+1  A: 

In my machine, your ldf array after the df calls yields the following:

irb(main):011:0> ldf
=> [[{"device"=>"/dev/sda5", "size"=>"49399372", "mount"=>"/", "avail"=>"22728988", "used"=>"24161036", "capp"=>"52%"}], [{"device"=>"/dev/sda5", "inodes"=>"3137536", "mount"=>"/", "iusep"=>"13%", "inodesavail"=>"2752040", "inodesused"=>"385496"}]]

The most flexible approach to merging such a structure is probably something along these lines:

irb(main):013:0> ldf.flatten.inject {|a,b| a.merge(b)}
=> {"device"=>"/dev/sda5", "inodes"=>"3137536", "size"=>"49399372", "mount"=>"/", "avail"=>"22728988", "inodesavail"=>"2752040", "iusep"=>"13%", "used"=>"24161036", "capp"=>"52%", "inodesused"=>"385496"}

Some ruby programmers frown on this use of inject, but I like it, so your mileage may vary.

As for helping making your code more ruby like, I suggest you talk to some experienced rubyist you might know over your code to help you rewriting it in a way that follows good style and best practices. Probably that would the preferable than to just have someone rewrite it for you here.

Best of Luck!

Marcos Toledo
Your code will not work if there is more than 1 device...
Marc-André Lafortune
Ouch, that's right, sorry for the oversight
Marcos Toledo
+1  A: 

Didn't test the code, but here goes:

ARGUMENTS = {
  " "   => %w{size used avail capp mount},
  " -i" => %w{inodes inodesused inodesavail iusep mount}
}

def parsedf
  # Store resulting info in a hash:
  device_info = Hash.new do |h, dev|
    h[dev] = {} # Each value will be a empty hash by default
  end

  ARGUMENTS.each do |arg, fields|
    %x{#{@df} -P -t #{@fstyp}#{arg}}.split(/\n/)[1..-1].each do |line|
      device, *data = line.split
      device_info[device].merge! Hash[fields.zip(data)]
    end
  end
  device_info
end

Notes: returns something a bit different than what you had:

{ "/dev/sda5" => {"inodes" => "...", ...},
  "other device" => {...}
}

Also, I'm assuming Ruby 1.8.7 or better for Hash[key_value_pairs], otherwise you can resort to the Hash[*key_value_pairs.flatten] form you had

Depending on your needs, you should consider switch the fields from string to symbols; they are the best type of keys.

Finally, I'd recommend using http://refactormycode.com or similar for that type of question, since it's unlikely to help many people.

Marc-André Lafortune
Worked great! Thanks for the pointer to the other site. I'd not heard of it.
sam