view 1-Ruby/acts_as_csv_module.rb @ 103:98be775c533c default tip

An odd "non-determinism" example from StackOverflow It is clever, but doesn't make much sense as to how it gets its results
author IBBoard <dev@ibboard.co.uk>
date Sun, 14 Jul 2019 13:44:13 +0100
parents 2ea3b5e9b41b
children
line wrap: on
line source

#---
# Excerpted from "Seven Languages in Seven Weeks",
# published by The Pragmatic Bookshelf.
# Copyrights apply to this code. It may not be used to create training material, 
# courses, books, articles, and the like. Contact us if you are in doubt.
# We make no guarantees that this code is fit for any purpose. 
# Visit http://www.pragmaticprogrammer.com/titles/btlang for more book information.
#---
module ActsAsCsv
  def self.included(base)
    base.extend ClassMethods
    # The book doesn't do this, but it is possible to add the methods
    # without having the inheriting class call a second function to do it
    base.acts_as_csv
  end
  
  module ClassMethods
    def acts_as_csv
      include InstanceMethods
    end
  end
  
  module InstanceMethods  
    def read
      @csv_contents = []
      filename = self.class.to_s.downcase + '.txt'
      file = File.new(filename)
      @headers = file.gets.chomp.split(', ')

      file.each do |row|
        csv_row = CsvRow.new(headers, row.chomp.split(', '))
        @csv_contents << csv_row
      end
    end
    
    attr_accessor :headers, :csv_contents
    def initialize
      read
    end

    def each(&block)
      @csv_contents.each { |row| block.call row }
    end
  end
end

class RubyCsv  # no inheritance! You can mix it in
  include ActsAsCsv
  # Also, nothing to do beyond the "include" - it automatically defines the methods!
end

class CsvRow
  attr_reader :values

  def initialize(headers, values)
    @values = Hash[headers.zip(values)]
  end

  def method_missing(methId, *args)
    str = methId.id2name
    if @values.key?(str)
      return @values[str]
    else
      super.method_missing(methId)
    end
  end
end

m = RubyCsv.new
puts m.headers.inspect
puts m.csv_contents.inspect
# Show the "each" method
m.each { |row| puts row.inspect }
# Use method_missing to implement heading-as-a-method
puts m.csv_contents[0].country
# And show that we still get normal failure behaviour
puts m.csv_contents[0].Country