Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/go_learning.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 81 additions & 0 deletions quiz/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"bufio"
"encoding/csv"
"flag"
"fmt"
"log"
"math/rand"
"os"
"strings"
"time"
)

type Quiz struct {
filename string
timeLimit int
shuffle bool
problems [][]string

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like a Problem or Question struct would be better than a slice of slices.

totalScore int
totalQuestions int
}

func (q *Quiz) readProblems() {
csvfile, err := os.Open(q.filename)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably make sure you close the file after opening it.
defer csvfile.Close()

if err != nil {
log.Fatalln("Couldn't open csv file ", err)
}
r := csv.NewReader(csvfile)
records, err := r.ReadAll()
if err != nil {
log.Fatalln(err)
}
q.problems = records
}
func (q *Quiz) shuffleProblems() {
rand.Seed(time.Now().UnixNano())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeding should only happen once and in the main function.

rand.Shuffle(len(q.problems), func(i, j int) { q.problems[i], q.problems[j] = q.problems[j], q.problems[i] })
}

func (q *Quiz) printProblems() {
in := bufio.NewReader(os.Stdin)
for i := 0; i < len(q.problems); i++ {
question, answer := q.problems[i][0], q.problems[i][1]
fmt.Println("What is " + question + " ?")
userAnswer, _ := in.ReadString('\n')
Comment on lines +43 to +46

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Go, you'll typically see people iterating through slices using the range clause.
i.e., your code might look something like:

Suggested change
for i := 0; i < len(q.problems); i++ {
question, answer := q.problems[i][0], q.problems[i][1]
fmt.Println("What is " + question + " ?")
userAnswer, _ := in.ReadString('\n')
for _, problem := range q.problems {
question, answer := problem[0], problem[1]
fmt.Printf("What is %s?\n", question)
userAnswer, _ := in.ReadString('\n')
// Rest of your code here
}

Also note the use of fmt.Printf() instead of fmt.Println(). It's not actually important in this case, given that question is just a string, but I thought I'd make a note just in case you weren't familiar.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay. I'll make sure that I follow this in the future.


//Ignores case mismatch and additional white spaces
if strings.Join(strings.Fields(strings.ToLower(userAnswer)), "") == strings.ToLower(answer) {
q.totalScore++
}
q.totalQuestions++
}
}

func main() {

//Get flags values
filename := flag.String("filename", "problems.csv", "File containing the questions")
timeLimit := flag.Int("timeLimit", 30, "Time limit in seconds")
shuffle := flag.Bool("shuffle", false, "Shuffle questions")
flag.Parse()

q := Quiz{filename: *filename, timeLimit: *timeLimit, shuffle: *shuffle}

q.readProblems()
if q.shuffle {
q.shuffleProblems()
}

//Setting timer
timer := time.AfterFunc(time.Second*time.Duration(q.timeLimit), func() {
fmt.Println("Total Score : ", q.totalScore)
fmt.Println("No. of Questions : ", q.totalQuestions)
os.Exit(0)
})
defer timer.Stop()

q.printProblems()

}
2 changes: 1 addition & 1 deletion urlshort/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"net/http"

"go_learning/urlshort"
"github.com/SwarnaLathaNatarajan/go_learning/urlshort"
)

func main() {
Expand Down
32 changes: 30 additions & 2 deletions urlshort/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package urlshort

import (
"net/http"

"gopkg.in/yaml.v2"
)

// MapHandler will return an http.HandlerFunc (which also
Expand All @@ -12,7 +14,14 @@ import (
// http.Handler will be called instead.
func MapHandler(pathsToUrls map[string]string, fallback http.Handler) http.HandlerFunc {
// TODO: Implement this...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still need this TODO?

return nil
return func(w http.ResponseWriter, r *http.Request) {
path, ok := pathsToUrls[r.URL.Path]
if ok {
http.Redirect(w, r, path, http.StatusFound)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is http.StatusFound correct? I remember needing to use a 211 or some other status to signify a redirect.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checks out

} else {
fallback.ServeHTTP(w, r)
}
Comment on lines +18 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In go you will typically return instead of using else statements where appropriate.

Suggested change
path, ok := pathsToUrls[r.URL.Path]
if ok {
http.Redirect(w, r, path, http.StatusFound)
} else {
fallback.ServeHTTP(w, r)
}
if path, ok := pathsToUrls[r.URL.Path]; ok {
http.Redirect(w, r, path, http.StatusFound)
}
fallback.ServeHTTP(w, r)

}
}

// YAMLHandler will parse the provided YAML and then return
Expand All @@ -33,5 +42,24 @@ func MapHandler(pathsToUrls map[string]string, fallback http.Handler) http.Handl
// a mapping of paths to urls.
func YAMLHandler(yml []byte, fallback http.Handler) (http.HandlerFunc, error) {
// TODO: Implement this...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still need this TODO?

return nil, nil
parsedYaml, err := parseYAML(yml)
if err != nil {
return nil, err
}
pathMap := buildMap(parsedYaml)
return MapHandler(pathMap, fallback), nil
}

func parseYAML(yml []byte) (out []map[string]string, err error) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure you need this function since it would only be two lines in the YAMLHandler function.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parseYAML stub was suggested in the problem. That's why I went ahead with it.

err = yaml.Unmarshal(yml, &out)
return out, err

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the named return values in the signature was a clever idea here. When you do that you don't need to specify the variables in the return statement (as long as you are returning the signature values).

}

func buildMap(parsedYaml []map[string]string) map[string]string {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this going to only accept YAML? The bonus objective is to also be able to use JSON.

pathMap := make(map[string]string)
for _, entry := range parsedYaml {
key := entry["path"]
pathMap[key] = entry["url"]
Comment on lines +61 to +62

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you could have used a struct instead of a map here. Using a struct would be good practice for using go tags.

}
return pathMap
}