diff --git a/README.md b/README.md index 846b88e..2873c02 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,13 @@ It is written in Ruby. Installation ------------ +kgrader was developed using Ruby 2.2, though it should work with any recent +version of Ruby. + +Install dependencies with gem: + + gem install ruby-progressbar + Download kgrader over git: git clone https://github.com/earwig/kgrader.git kgrader diff --git a/lib/kgrader/cli.rb b/lib/kgrader/cli.rb index 4a87c3e..d14e772 100644 --- a/lib/kgrader/cli.rb +++ b/lib/kgrader/cli.rb @@ -24,21 +24,21 @@ module KGrader course.roster(semester).load rosterfile end - def grade(course, semester, assignment, options = {}) + def grade(course, semester, assignment, students = nil, options = {}) course = Course.new(@fs, course) semester ||= course.current_semester - course.task(semester, assignment).grade options + course.task(semester, assignment, students).grade options end - def commit(course, semester, assignment, options = {}) + def commit(course, semester, assignment, students = nil) course = Course.new(@fs, course) semester ||= course.current_semester - course.task(semester, assignment).commit options + course.task(semester, assignment, students).commit end def clean - # TODO: also purge uncommitted grades clear_jail + # TODO: also purge uncommitted grades: set all graded to ungraded and delete all pending files end def clobber diff --git a/lib/kgrader/course.rb b/lib/kgrader/course.rb index a80fab1..1e50045 100644 --- a/lib/kgrader/course.rb +++ b/lib/kgrader/course.rb @@ -23,8 +23,8 @@ module KGrader @assignments[name] ||= Assignment.new @fs, self, name end - def task(semester, assignment) - Task.new @fs, self, semester, assignment + def task(semester, assignment, students = nil) + Task.new @fs, self, semester, assignment, students end def rosters diff --git a/lib/kgrader/roster.rb b/lib/kgrader/roster.rb index 81a601f..cc6f43f 100644 --- a/lib/kgrader/roster.rb +++ b/lib/kgrader/roster.rb @@ -10,7 +10,7 @@ module KGrader end def load(filename) - @students = @fs.load(filename).map! { |item| item.first } + @students = @fs.load(filename).map! &:first FileUtils.mkdir_p File.dirname(rosterfile) File.write rosterfile, @students.join("\n") rescue FilesystemError => err @@ -18,7 +18,7 @@ module KGrader end def students - @students ||= @fs.load(rosterfile).map! { |item| item.first } + @students ||= @fs.load(rosterfile).map! &:first rescue FilesystemError raise RosterError, "unknown semester: #{semester}" end diff --git a/lib/kgrader/submission.rb b/lib/kgrader/submission.rb index 3b66c2b..48a876c 100644 --- a/lib/kgrader/submission.rb +++ b/lib/kgrader/submission.rb @@ -29,6 +29,7 @@ module KGrader def create FileUtils.mkdir_p @root self.status = :init + nil end def fetch(due) @@ -43,20 +44,48 @@ module KGrader rewind due self.status = revision == oldrev ? :graded : :ungraded end + nil end def grade - # TODO + # TODO: + # self.status = :ungraded + # [grade the stuff] + # [save report to gradefile] + # FileUtils.touch pendingfile # self.status = :graded + # return grade summary string + + sleep rand / 2 + '100%' + end + + def commit + # TODO: + # if status == :graded && File.exists? pendingfile + # [copy gradefile to repo and commit] + # FileUtils.rm pendingfile + # end + + sleep rand / 2 + nil end private + def repo + File.join @root, "repo" + end + def statusfile File.join @root, "status.txt" end - def repo - File.join @root, "repo" + def gradefile + File.join @root, "grade.txt" + end + + def pendingfile + File.join @root, "pending" end def revision diff --git a/lib/kgrader/task.rb b/lib/kgrader/task.rb index f13d7bb..7ede464 100644 --- a/lib/kgrader/task.rb +++ b/lib/kgrader/task.rb @@ -1,64 +1,71 @@ +require 'ruby-progressbar' + module KGrader class Task - def initialize(filesystem, course, semester, assignment) - @fs = filesystem - @course = course - @semester = semester - - @assignment = @course.assignment assignment - @students = @course.roster(@semester).students + def initialize(filesystem, course, semester, assignment, students = nil) + @fs = filesystem + @course = course + @semester = semester + @assignment = @course.assignment assignment + @submissions = get_submissions students end def grade(options = {}) - submissions = get_submissions options[:students] due = options.fetch(:due, Time.now) fetch = options.fetch(:fetch, true) regrade = options.fetch(:regrade, false) - count = submissions.count - puts "[grading #{count} student#{'s' if count != 1}]" - - submissions.each do |sub| - unless sub.exists? - puts "[init #{sub.student}]" - sub.create - end + subtask 'setup' do |sub| + sub.create unless sub.exists? end if fetch - submissions.each do |sub| - puts "[fetch #{sub.student}]" + subtask 'fetch' do |sub| sub.fetch due end end - submissions.each do |sub| - sub.status = :ungraded if regrade - if sub.status == :ungraded - puts "[grade #{sub.student}]" + subtask 'grade' do |sub| + if sub.status == :init || sub.status == :fetching + next 'skip (need to fetch first)' + elsif sub.status == :graded && !regrade + next + else sub.grade end end end - def commit(options = {}) - submissions = get_submissions options[:students] - - # TODO - puts "[committing]" - puts "course => #{@course.name}" - puts "semester => #{@semester}" - puts "assignment => #{@assignment.name}" - puts "students => #{submissions.map { |sub| sub.student }.join ', '}" + def commit + subtask 'commit', &:commit end private def get_submissions(students) - students.nil? ? (students = @students) : (students &= @students) + roster = @course.roster(@semester).students + students.nil? ? (students = roster) : (students &= roster) students.map do |student| Submission.new @fs, @course, @semester, @assignment, student end end + + def student_len + @student_len ||= @submissions.map { |sub| sub.student.length }.max + end + + def subtask(name) + progress = ProgressBar.create title: name, total: @submissions.size, + throttle_rate: 0, format: '%t [%b>%i] %j%% %e ' + + @submissions.each.with_index do |sub, i| + job = "#{name} [#{sub.student.ljust student_len}]" + progress.title = "#{job}:" + result = yield sub + progress.title = name if i == @submissions.size - 1 + progress.log "#{job}#{': ' if result}#{result}" if result + progress.increment + end + end end end diff --git a/rakefile b/rakefile index dbb412b..65157ab 100644 --- a/rakefile +++ b/rakefile @@ -45,13 +45,15 @@ task :grade do course, assignment, options = parse_args 2..2, { :semester => :string, :students => :array, :due => :time, :fetch => :bool, :regrade => :bool } - run { |cli| cli.grade course, options[:semester], assignment, options } + semester, students = options[:semester], options[:students] + run { |cli| cli.grade course, semester, assignment, students, options } end task :commit do course, assignment, options = parse_args 2..2, { :semester => :string, :students => :array } - run { |cli| cli.commit course, options[:semester], assignment, options } + semester, students = options[:semester], options[:students] + run { |cli| cli.commit course, semester, assignment, students } end task :clean do