|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "encoding/csv" |
| 5 | + "flag" |
| 6 | + "fmt" |
| 7 | + "io" |
| 8 | + "log" |
| 9 | + "os" |
| 10 | + "time" |
| 11 | + |
| 12 | + quiz "github.com/gophercises/quiz/students/hackeryarn/myquiz" |
| 13 | + "github.com/gophercises/quiz/students/hackeryarn/problem" |
| 14 | +) |
| 15 | + |
| 16 | +const ( |
| 17 | + // FileFlag is used to set a file for the questions |
| 18 | + FileFlag = "file" |
| 19 | + // FileFlagValue is the value used when no FileFlag is provided |
| 20 | + FileFlagValue = "problems.csv" |
| 21 | + // FileFlagUsage is the help string for the FileFlag |
| 22 | + FileFlagUsage = "Questions file" |
| 23 | + |
| 24 | + // TimerFlag is used for setting a timer for the quiz |
| 25 | + TimerFlag = "timer" |
| 26 | + // TimerFlagValue is the value used when no TimerFlag is provided |
| 27 | + TimerFlagValue = 30 |
| 28 | + // TimerFlagUsage is the help string for the TimerFlag |
| 29 | + TimerFlagUsage = "Amount of seconds the quiz will allow" |
| 30 | +) |
| 31 | + |
| 32 | +// Flagger configures the flags used |
| 33 | +type Flagger interface { |
| 34 | + StringVar(p *string, name, value, usage string) |
| 35 | + IntVar(p *int, name string, value int, usage string) |
| 36 | +} |
| 37 | + |
| 38 | +type quizFlagger struct{} |
| 39 | + |
| 40 | +func (q *quizFlagger) StringVar(p *string, name, value, usage string) { |
| 41 | + flag.StringVar(p, name, value, usage) |
| 42 | +} |
| 43 | + |
| 44 | +func (q *quizFlagger) IntVar(p *int, name string, value int, usage string) { |
| 45 | + flag.IntVar(p, name, value, usage) |
| 46 | +} |
| 47 | + |
| 48 | +// Timer is used to start a timer |
| 49 | +type Timer interface { |
| 50 | + NewTimer(d time.Duration) *time.Timer |
| 51 | +} |
| 52 | + |
| 53 | +type quizTimer struct{} |
| 54 | + |
| 55 | +func (q quizTimer) NewTimer(d time.Duration) *time.Timer { |
| 56 | + return time.NewTimer(d) |
| 57 | +} |
| 58 | + |
| 59 | +// ReadCSV parses the CSV file into a Problem struct |
| 60 | +func ReadCSV(reader io.Reader) quiz.Quiz { |
| 61 | + csvReader := csv.NewReader(reader) |
| 62 | + |
| 63 | + problems := []problem.Problem{} |
| 64 | + for { |
| 65 | + record, err := csvReader.Read() |
| 66 | + if err == io.EOF { |
| 67 | + break |
| 68 | + } else if err != nil { |
| 69 | + log.Fatalln("Error reading CSV:", err) |
| 70 | + } |
| 71 | + |
| 72 | + problems = append(problems, problem.New(record)) |
| 73 | + } |
| 74 | + |
| 75 | + return quiz.New(problems) |
| 76 | +} |
| 77 | + |
| 78 | +// TimerSeconds is the amount of time allowed for the quiz |
| 79 | +var TimerSeconds int |
| 80 | +var file string |
| 81 | + |
| 82 | +// ConfigFlags sets all the flags used by the application |
| 83 | +func ConfigFlags(f Flagger) { |
| 84 | + f.StringVar(&file, FileFlag, FileFlagValue, FileFlagUsage) |
| 85 | + f.IntVar(&TimerSeconds, TimerFlag, TimerFlagValue, TimerFlagUsage) |
| 86 | +} |
| 87 | + |
| 88 | +// StartTimer begins a timer once the user provides input |
| 89 | +func StartTimer(w io.Writer, r io.Reader, timer Timer) *time.Timer { |
| 90 | + fmt.Fprint(w, "Ready to start?") |
| 91 | + fmt.Fscanln(r) |
| 92 | + |
| 93 | + return timer.NewTimer(time.Second * time.Duration(TimerSeconds)) |
| 94 | +} |
| 95 | + |
| 96 | +func init() { |
| 97 | + flagger := &quizFlagger{} |
| 98 | + ConfigFlags(flagger) |
| 99 | + |
| 100 | + flag.Parse() |
| 101 | +} |
| 102 | + |
| 103 | +func main() { |
| 104 | + file, err := os.Open(file) |
| 105 | + if err != nil { |
| 106 | + log.Fatalln("Could not open file", err) |
| 107 | + } |
| 108 | + |
| 109 | + quiz := ReadCSV(file) |
| 110 | + |
| 111 | + timer := StartTimer(os.Stdout, os.Stdin, quizTimer{}) |
| 112 | + go func() { |
| 113 | + <-timer.C |
| 114 | + fmt.Println("") |
| 115 | + quiz.PrintResults(os.Stdout) |
| 116 | + os.Exit(0) |
| 117 | + }() |
| 118 | + |
| 119 | + quiz.Run(os.Stdout, os.Stdin) |
| 120 | +} |
0 commit comments