#!/usr/bin/env ruby # -*- coding: utf-8 -*- require 'csv' require 'sequel' require 'etc' user = ENV["QEUSER"] || Etc.getlogin gecos = "" tbl = "exam" cls="" timeout=30 hostname=(`hostname`||"local").sub(/\..*/, "").chomp showrank = false mailto = false while /^-([a-z])/i =~ ARGV[0] ARGV.shift case $1 when "m" # -m email@add.ress.domain mailto = ARGV.shift when "M" # Send Email to $0:h/MAILTO mailto = IO.readlines(File.expand_path("MAILTO", File.dirname($0))).join mailto.gsub!("\n", " ").strip! when "c" cls = ARGV.shift.gsub(/\D/, "") when "t" timeout = ARGV.shift.to_i when "T" tbl = ARGV.shift.gsub(/[^a-zA-Z0-9_]/, "") when "r" showrank = true end end files = ARGV[0]&&ARGV[0]>"" ? ARGV : ["html", "css"] point = tp = 0 mydir=File.dirname($0) stime = Time.now File.umask(2) # Setup Database # db = Sequel.connect("postgres://ruby_qexam@broy/ruby_qexam") db = Sequel.connect("sqlite://./score.sq3") sctbl, gtbl = db.from(tbl), db[:gecos] db.transaction do db.create_table?(tbl) { String :user Timestamp :time String :host Integer :score Integer :mistake Numeric :elapse } db.create_table?(:gecos) { String :user String :gecos unique [:user] } begin gecos = Etc.getpwnam(user).gecos.to_s rescue gecos = user end gtbl.where(user: user).delete gtbl.insert(user: user, gecos: (gecos>'' ? gecos : user)) if showrank && tbl i = 0 if cls > "" # cls cannot have non-digit (cls.gsub(/\D/, "") was done) mems = "(SELECT \"user\" FROM lects WHERE scode LIKE \"#{cls}%\")" else mems = "(SELECT DISTINCT \"user\" from #{tbl})" end if false then r = db["SELECT c.user,gecos,coalesce(mine,9999) scr,coalesce(cnt,0) FROM (SELECT a.user,mine,cnt FROM #{mems} a LEFT JOIN (SELECT \"user\", min(elapse) mine, count(elapse) cnt FROM #{tbl} GROUP BY user) b ON a.user=b.user ORDER by mine) c JOIN gecos g ON c.user=g.user ORDER BY scr"] else migi = sctbl.select(Sequel.as(:user, :muser), Sequel.as(Sequel.function(:min, :elapse), :mine), Sequel.as(Sequel.function(:count, :elapse), :cnt)).group(:user) hidari = sctbl.select(:user).distinct # r = sctbl.select(:user).distinct.join_table(:left, :exam) # p migi.all, hidari.all # p hidari.join(migi) # Cannot use aliasing on lefter side of join r = hidari.left_join(migi, :muser => :user).natural_join(gtbl). select(:user, :gecos, Sequel.as(Sequel.function(:coalesce, :mine, 9999), :scr), Sequel.as(Sequel.function(:coalesce, :cnt, 0), :cnt)).order(:scr) end r.each do |row| u=row[:user] user==u and print("\e[33m") printf("%3d %-10s|%-32s%8.2f%8d\n", i+=1, *row.values) user==u and print("\e[m") end exit 0 end end miss = 0 for f in files pt = 0 printf("====> %sに関する問題です <====\n", f) qf = File.expand_path(f, mydir) d = CSV.read(qf+".txt", :col_sep => ":", :quote_char => "'", :encoding => 'utf-8') d = d.shuffle nQ = d.length start = Time.now limit = start + timeout*nQ tp += nQ while d[0] q = d[0][0] printf("[%d/%d] %s\n==> ", pt, nQ, d[0][1]) a = STDIN.gets.strip ## ptn = %r,^/, =~ a ? a : Regexp.quote(a) ptn = Regexp.quote(a.gsub(/\s/, "")) if Regexp.new("^"+ ptn +"$", true) =~ q.gsub(/\s/, "") then puts "正解!" d.shift pt += 1 sleep 1 else miss += 1 printf("不正解です。\n正解は %s です。\n(Enterで次に進む)", q) STDIN.gets end if Time.now > limit then puts("時間切れです。") break end print("\e[2J\e[1;1H") d.shuffle! end point += pt end etime = Time.now now = Time.at(etime.to_i) elapse = etime-stime el2 = elapse.round(2) sctbl.insert({ user: user, time: now, host: hostname, score: point, mistake: miss, elapse: el2}) trial = sctbl.where(user: user).count rank = sctbl.where(user: user).where(Sequel.expr(:elapse) < el2).count # or .where{elapse() < el2} # or .where{self.elapse < el2} qname = files.join("+") printf("問題: %s - ", qname) printf("%d回中 %d番目の記録\n", trial, rank+1) printf("得点: %d/%d\n", point, tp) printf("時間: %.2f杪\n", elapse) printf("ミス: %d回\n", miss) db.disconnect if mailto open("| mail -s \"quiz-record of #{qname} by #{gecos}\" #{mailto}", "w") do |m| m.print(<<~EOF) #{user},#{point},#{elapse} EOF end end