Main Content

Separating detailed data code from the main application - Ruby example

Archive - Originally posted on "The Horse's Mouth" - 2016-05-16 23:08:51 - Graham Ellis

In almost every appication, you'll be writing a number of pieces of code that use the same data type. It's tempting initially to write all the detail of the individual fields and attributes of the data into a main program - especially if the application's not very long and you're in a hurry:

  fh = File.new "ac_20160516"
  
  counter = {}
  
  fh.each do |record|
    parts = record.split " "
    if parts[1] == "option247.uk"
      page = parts[6]
  
      if counter[page].nil?
        counter[page] = 1
      else
        counter[page] += 1
      end
      end
    end
  
  pages = counter.keys
  pages.sort!  {|this,that| this.length <=> that.length}
  
  pages.each do |page|
    puts "#{page} #{counter[page]}"
    end
  


Which works well enough, but ties the program down to a specific data format and implements the algorithms individually. If your data records are sometime available in a different way, you need to rewrite all the code, and if you want to use the counter technique elsewhere, you'll have to recode that too. Better to write the code a little longer and clearer and abstact the algorithms and data formats into separate classes.


  class Counter
    def initialize()
      @internal = {}
    end
  
    def count(item)
      @internal[item] = @internal[item].nil? ? 1 : @internal[item]+1
    end
  
    def getKeys()
      return @internal.keys.sort { |this,that| @internal[this] <=> @internal[that]}
    end
  
    def getKey(which)
      return @internal[which]
    end
  end
  class Hit
    def initialize(record)
      @fields = record.chomp.split(" ")
    end
    def issite?(which)
      return @fields[1] == which
    end
    def url
      return @fields[6]
    end
  end
  # ----------------------
  
  if __FILE__ == %body%
    fh = File.new "ac_20160516"
    counter = Counter.new
  
    fh.each do |record|
      hit = Hit.new(record)
      parts = record.split " "
      if hit.issite?("option247.uk")
        counter.count(hit.url)
        end
      end
  
    pages = counter.getKeys
    pages.each do |page|
      puts "#{page} #{counter.getKey(page)}"
      end
  
    end


Complete source code of this example - the before [here] and the after [here]. From the Ruby Course I am presenting this week. The datafile is available [here].