A code autograder for student homework submissions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.0 KiB

  1. require 'ruby-progressbar'
  2. module KGrader
  3. class Task
  4. def initialize(filesystem, course, semester, assignment, students = nil)
  5. @fs = filesystem
  6. @course = course
  7. @semester = semester
  8. @assignment = @course.assignment assignment
  9. @submissions = get_submissions students
  10. end
  11. def grade(options = {})
  12. due = options.fetch(:due, Time.now)
  13. fetch = options.fetch(:fetch, true)
  14. regrade = options.fetch(:regrade, false)
  15. if options.include?(:due) && !fetch
  16. raise TaskError, "can't set a new due date without fetching"
  17. end
  18. prepare
  19. subtask 'setup' do |sub|
  20. sub.create unless sub.exists?
  21. end
  22. if fetch
  23. subtask 'fetch' do |sub|
  24. sub.fetch due
  25. end
  26. end
  27. subtask 'grade' do |sub|
  28. if sub.status == :init || sub.status == :fetching
  29. next 'skip (need to fetch first)'
  30. elsif sub.status == :graded && !regrade
  31. next
  32. else
  33. sub.grade
  34. end
  35. end
  36. end
  37. def commit
  38. prepare
  39. subtask 'commit', &:commit
  40. end
  41. private
  42. def get_submissions(students)
  43. roster = @course.roster(@semester).students
  44. students.nil? ? (students = roster) : (students &= roster)
  45. students.map do |student|
  46. Submission.new @fs, @course, @semester, @assignment, student
  47. end
  48. end
  49. def student_len
  50. @student_len ||= @submissions.map { |sub| sub.student.length }.max
  51. end
  52. def prepare
  53. @course.backend.prepare @semester, @assignment
  54. end
  55. def subtask(name)
  56. progress = ProgressBar.create title: name, total: @submissions.size,
  57. throttle_rate: 0, format: '%t [%b>%i] %j%% %e '
  58. @submissions.each.with_index do |sub, i|
  59. job = "#{name} [#{sub.student.ljust student_len}]"
  60. progress.title = "#{job}:"
  61. result = yield sub
  62. progress.title = name if i == @submissions.size - 1
  63. progress.log "#{job}#{': ' if result}#{result}" if result
  64. progress.increment
  65. end
  66. end
  67. end
  68. end