From 88629001d4c44e0ede356d75ef9969980b4565f2 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Thu, 31 Mar 2016 00:58:26 -0500 Subject: [PATCH] Refactor exception handling; cleanup --- README.md | 3 ++- lib/kgrader/cli.rb | 12 +++--------- lib/kgrader/course.rb | 9 +++------ lib/kgrader/errors.rb | 12 ++++++++++++ lib/kgrader/filesystem.rb | 4 ++-- lib/kgrader/roster.rb | 4 ++++ lib/kgrader/task.rb | 17 +++++++++++++---- lib/kgrader/util.rb | 30 ++++++++++++++++++------------ rakefile | 26 +++++++++++++++++--------- 9 files changed, 74 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 2ee95a8..be6695d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,8 @@ To show all known classes, semesters, and assignments: rake list -To load a roster for a specific semester: +To load a roster (a newline-delimited list of student identifiers) for a +specific semester: rake roster cs123 myroster.csv semester=sp16 diff --git a/lib/kgrader/cli.rb b/lib/kgrader/cli.rb index 0227ade..b385e0c 100644 --- a/lib/kgrader/cli.rb +++ b/lib/kgrader/cli.rb @@ -26,19 +26,19 @@ module KGrader end def roster(course, semester, rosterfile) - course = fetch_course course + course = Course.new(@fs, course) semester ||= course.current_semester course.roster(semester).load rosterfile end def grade(course, semester, assignment, options = {}) - course = fetch_course course + course = Course.new(@fs, course) semester ||= course.current_semester course.task(semester, assignment).grade options end def commit(course, semester, assignment, options = {}) - course = fetch_course course + course = Course.new(@fs, course) semester ||= course.current_semester course.task(semester, assignment).commit options end @@ -58,12 +58,6 @@ module KGrader end private - def fetch_course(course) - Course.new(@fs, course) - rescue FilesystemError - KGrader::die "unknown course" - end - def reset_jail FileUtils.rm_rf @fs.jail FileUtils.mkdir @fs.jail diff --git a/lib/kgrader/course.rb b/lib/kgrader/course.rb index b42f1da..eb79d43 100644 --- a/lib/kgrader/course.rb +++ b/lib/kgrader/course.rb @@ -11,6 +11,8 @@ module KGrader @config = @fs.load @fs.course_config(@name) @rosters = {} + rescue FilesystemError + raise CourseError, "unknown or invalid course: #{name}" end def roster(semester) @@ -30,12 +32,7 @@ module KGrader end def current_semester - case @config['semesters'] - when 'faspYY' - KGrader::season + DateTime.now.strftime('%y') - when 'faspYYYY' - KGrader::season + DateTime.now.strftime('%Y') - end + KGrader::current_semester @config['semesters'] end end end diff --git a/lib/kgrader/errors.rb b/lib/kgrader/errors.rb index 77df351..edb1598 100644 --- a/lib/kgrader/errors.rb +++ b/lib/kgrader/errors.rb @@ -2,6 +2,18 @@ module KGrader class KGraderError < StandardError end + class ArgumentError < KGraderError + end + class FilesystemError < KGraderError end + + class ConfigError < KGraderError + end + + class CourseError < KGraderError + end + + class RosterError < KGraderError + end end diff --git a/lib/kgrader/filesystem.rb b/lib/kgrader/filesystem.rb index 071b48b..e8effa4 100644 --- a/lib/kgrader/filesystem.rb +++ b/lib/kgrader/filesystem.rb @@ -52,10 +52,10 @@ module KGrader when '.csv' File.read(path).split("\n").map! { |line| line.split "," } else - raise FilesystemError, "unknown file type" + raise FilesystemError, "unknown file type: #{path}" end rescue SystemCallError # Errno::ENOENT, etc. - raise FilesystemError, "can't read file" + raise FilesystemError, "can't read file: #{path}" end end end diff --git a/lib/kgrader/roster.rb b/lib/kgrader/roster.rb index d59003d..81a601f 100644 --- a/lib/kgrader/roster.rb +++ b/lib/kgrader/roster.rb @@ -13,10 +13,14 @@ module KGrader @students = @fs.load(filename).map! { |item| item.first } FileUtils.mkdir_p File.dirname(rosterfile) File.write rosterfile, @students.join("\n") + rescue FilesystemError => err + raise RosterError, err end def students @students ||= @fs.load(rosterfile).map! { |item| item.first } + rescue FilesystemError + raise RosterError, "unknown semester: #{semester}" end private diff --git a/lib/kgrader/task.rb b/lib/kgrader/task.rb index 9863250..4dc6e2b 100644 --- a/lib/kgrader/task.rb +++ b/lib/kgrader/task.rb @@ -6,23 +6,32 @@ module KGrader @course = course @semester = semester @assignment = assignment - @roster = @course.roster @semester + @students = @course.roster(@semester).students end def grade(options = {}) - students = @roster.students + students = @students students &= options[:students] unless options[:students].nil? + due = options.fetch(:due, Time.now) + fetch = options.fetch(:fetch, true) + regrade = options.fetch(:regrade, false) + # TODO puts "Grading #{@course.name}:#{@semester} assignment #{@assignment}..." - puts "- options: #{options}" puts "- students: #{students.inspect}" + puts "- due: #{due}" + puts "- fetch: #{fetch}" + puts "- regrade: #{regrade}" end def commit(options = {}) + students = @students + students &= options[:students] unless options[:students].nil? + # TODO puts "Committing #{@course.name}:#{@semester} assignment #{@assignment}..." - puts "- options: #{options}" + puts "- students: #{students.inspect}" end end end diff --git a/lib/kgrader/util.rb b/lib/kgrader/util.rb index 4113e12..1f86683 100644 --- a/lib/kgrader/util.rb +++ b/lib/kgrader/util.rb @@ -1,10 +1,6 @@ -require 'date' +require 'time' module KGrader - def self.die(error) - Kernel::abort "fatal: #{error}" - end - def self.parse_args(raw, num, keywords) args = [] options = {} @@ -13,7 +9,9 @@ module KGrader if arg.include? '=' key, val = arg.split('=', 2) key = key.to_sym - die "unknown keyword #{key}" unless keywords.include? key + unless keywords.include? key + raise ArgumentError, "unknown keyword: #{key}" + end options[key] = case keywords[key] when :string val @@ -21,20 +19,28 @@ module KGrader %w(true yes 1 t y).include? val.downcase when :array val.split(",").map! { |x| x.strip.downcase } - when :datetime - DateTime.parse(val) + when :time + Time.parse(val) end else args << arg end end - die "too few arguments" if args.size < num - die "too many arguments" if args.size > num + raise ArgumentError, "too few arguments" if args.size < num + raise ArgumentError, "too many arguments" if args.size > num return args, options end - def self.season - DateTime.now.strftime('%m').to_i <= 6 ? 'sp' : 'fa' + def self.current_semester(format) + season = Time.now.strftime('%m').to_i <= 6 ? 'sp' : 'fa' + case format + when 'faspYY' + season + Time.now.strftime('%y') + when 'faspYYYY' + season + Time.now.strftime('%Y') + else + raise ConfigError, "unknown semester format: #{format}" + end end end diff --git a/rakefile b/rakefile index b071f5c..dd4af74 100644 --- a/rakefile +++ b/rakefile @@ -1,13 +1,21 @@ require_relative 'lib/kgrader' -def cli - KGrader::CLI.new Rake.application.original_dir +def die(error) + abort "fatal: [#{error.class}] #{error}" +end + +def run + yield KGrader::CLI.new Rake.application.original_dir +rescue KGrader::KGraderError => err + die err end def parse_args(num, keywords = {}) args, options = KGrader::parse_args ARGV.drop(1), num, keywords args.each { |arg| task arg.to_sym {} } args + [options] +rescue KGrader::KGraderError => err + die err end task :default => :help do ; end @@ -24,31 +32,31 @@ task :help do end task :list do - cli.list + run { |cli| cli.list } end task :roster do course, rosterfile, options = parse_args 2, { :semester => :string } - cli.roster course, options[:semester], rosterfile + run { |cli| cli.roster course, options[:semester], rosterfile } end task :grade do course, assignment, options = parse_args 2, - { :semester => :string, :students => :array, :due => :datetime, + { :semester => :string, :students => :array, :due => :time, :fetch => :bool, :regrade => :bool } - cli.grade course, options[:semester], assignment, options + run { |cli| cli.grade course, options[:semester], assignment, options } end task :commit do course, assignment, options = parse_args 2, { :semester => :string, :students => :array } - cli.commit course, options[:semester], assignment, options + run { |cli| cli.commit course, options[:semester], assignment, options } end task :clean do - cli.clean + run { |cli| cli.clean } end task :clobber do - cli.clobber + run { |cli| cli.clobber } end