Skip to content

Instantly share code, notes, and snippets.

@akoskovacs
Last active November 3, 2015 19:45
Show Gist options
  • Save akoskovacs/31578be903025169e022 to your computer and use it in GitHub Desktop.
Save akoskovacs/31578be903025169e022 to your computer and use it in GitHub Desktop.
Ruby on Rails style database interface for CSV files
class HeaderType
attr_reader :header
ATTRS = {string: :string, int: :int, number: :int, integer: :int }
def initialize
@header = []
end
# Define methods string, integer, etc.,
# for schema definition dynamically
class_eval do
ATTRS.each do |attr, type|
define_method attr do |name|
@header << [type, name]
end
end
end
end
class CSV
def self.create_table(name, &block)
# Generate the appropriate class for the schema
dync = Class.new do |k|
@@db = nil
@@table = []
@@header = []
@@rows = []
define_method :initialize do |row|
@new_row = row
row.each do |k,e|
define_singleton_method k do return @new_row[k] end
end
end
define_method :save do
return false if @new_row.empty? or @new_row.nil?
@@header.each do |t,e|
return false if (@new_row[e.to_sym] == nil)
end
@@rows << @new_row.values
@@table << @new_row
return true
end
define_singleton_method :create do |args|
k.new(args)
end
define_singleton_method :pretty_print do
max = []
@@rows.each_with_index do |row, i|
max[i] = 0
row.map do |col|
len = col.to_s.length
max[i] = len if (len > max[i])
end
max[i] += 2
end
sep_line = '+'
@@header.each_index do |i|
sep_line += ('-' * max[i]) + '+'
end
@@rows.each do |row|
puts sep_line
row.each_with_index do |c,i|
printf("| %-#{max[i]-2}s ", c)
end
puts '|'
end
puts sep_line
end
define_singleton_method :find do |col, e|
arr = []
@@table.each do |r|
arr << r if (r[col] == e)
end
return nil if arr.empty?
return arr
end
define_singleton_method :all do
return @@table
end
define_singleton_method :all_rows do
return @@rows
end
define_singleton_method :read_file do |fname|
if @@db.nil?
@@db = File.open(fname, 'r');
end
@@db.readline
@@db.each_line do |l|
r = l.chomp.split(/,/)
rh = {}
rl = []
@@header.each_with_index do |h,i|
if h[0] == :int
e = r[i].to_i
else
# remove the leading and closing quotes
if (r[i][0] == '"' and r[i][-1] == '"')
e = r[i][1..(-2)]
else
e = r[i]
end
end
rh[h[1]] = e
rl << e
end
@@rows << rl
@@table << rh
end
@@db.close
end
define_singleton_method :set_header do |hdr|
@@header = hdr
end
end
klass = Object.const_set(name.capitalize, dync)
h = HeaderType.new
block.call(h)
hdr = h.header
klass.set_header hdr
klass.read_file "#{name}.csv"
end
end
#
# END OF THE IMPLEMENTATION #
# Define csv schema for a person
# NOTICE: A person.csv file is mandatory
CSV.create_table 'person' do |t|
t.string :fname
t.string :sname
t.int :birth_year
t.int :postcode
end
puts "--- List all persons in the file ---"
puts Person.all # list all person from file
puts "--- Find someone from 1990 ---"
puts Person.find(:birth_year, 1990) # find
puts "--- Create a new person ---"
p = Person.create(fname: 'John', sname: 'Doe', birth_year: 1991, postcode: 2092)
puts p.inspect
puts "--- Save '#{p.fname} #{p.sname}' to the database ---"
p.save
puts "--- Pretty print the new table ---"
puts Person.pretty_print
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment