{{.}}
12 | {{end}} 13 |├── students ├── adeel41 │ ├── arc-console.tpl │ ├── runner.go │ ├── arc_option.go │ ├── arc.tpl │ ├── console_runner.go │ ├── story_arc.go │ ├── story_arc_provider.go │ ├── web_runner.go │ ├── main.go │ ├── story.go │ └── gopher.json ├── ccallergard │ ├── adventure.go │ ├── html.go │ ├── scene_template.html │ ├── main │ │ └── main.go │ └── gopher.json ├── README.md ├── manan │ ├── story.html │ ├── cmd │ │ └── main.go │ ├── cyoa_test.go │ ├── cyoa.go │ └── gopher.json ├── cherednichenkoa │ ├── settings │ │ └── settings.go │ ├── templates │ │ └── story.html │ ├── main.go │ ├── source │ │ └── json_file.go │ └── route-handler │ │ └── route_handler.go ├── dennisvis │ ├── templates │ │ └── main.html │ ├── main.go │ └── gopher.json └── barisere │ ├── cyoa.html │ ├── main.go │ └── gopher.json ├── .gitignore ├── README.md └── gopher.json /students/adeel41/arc-console.tpl: -------------------------------------------------------------------------------- 1 | {{.Title}} 2 | {{.Paragraph}} 3 | 4 | {{range .Options}} 5 | {{.Number}}. {{.Text}} 6 | {{end}} -------------------------------------------------------------------------------- /students/adeel41/runner.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //Runner is implemented by ConsoleRunner and WebRunner 4 | type Runner interface { 5 | Start(provider *StoryArcProvider) 6 | } 7 | -------------------------------------------------------------------------------- /students/ccallergard/adventure.go: -------------------------------------------------------------------------------- 1 | package cyoa 2 | 3 | type Scene struct { 4 | Title string `json:"title"` 5 | Story []string `json:"story"` 6 | Options []struct { 7 | Text string `json:"text"` 8 | Arc string `json:"arc"` 9 | } `json:"options"` 10 | } 11 | 12 | type Adventure map[string]Scene 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | tmp/ 16 | .idea/ 17 | -------------------------------------------------------------------------------- /students/README.md: -------------------------------------------------------------------------------- 1 | # Student Examples 2 | 3 | The following are example implementations submitted by students/gophers learning from this course. 4 | 5 | The primary purposes of these examples are: 6 | 7 | 1. To provide example implementations to discuss and review when recording the screencasts for this course. 8 | 2. To provide a way for students to contribute to this course. 9 | -------------------------------------------------------------------------------- /students/adeel41/arc_option.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //ArcOption is an option for the story 4 | type ArcOption struct { 5 | Number int 6 | Text string 7 | Arc string 8 | } 9 | 10 | //Load loads the json data into an ArcOption 11 | func (ao *ArcOption) Load(number int, data map[string]interface{}) { 12 | ao.Number = number 13 | ao.Text = data["text"].(string) 14 | ao.Arc = data["arc"].(string) 15 | } 16 | -------------------------------------------------------------------------------- /students/manan/story.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |{{.}}
10 | {{end}} 11 |{{.Paragraph}}
11 | {{range .Options}} 12 | {{.Text}} 13 | {{end}} 14 | 15 | -------------------------------------------------------------------------------- /students/cherednichenkoa/settings/settings.go: -------------------------------------------------------------------------------- 1 | package settings 2 | 3 | type Settings struct { 4 | FilePath string 5 | ListenPort string 6 | TemplatePath string 7 | } 8 | 9 | func (conf *Settings) GetFilePath() string { 10 | return conf.FilePath 11 | } 12 | 13 | func (conf *Settings) GetListenPort() string { 14 | return conf.ListenPort 15 | } 16 | 17 | func (conf *Settings) GetTemplatePath() string { 18 | return conf.TemplatePath 19 | } -------------------------------------------------------------------------------- /students/manan/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "Manan/cyoa" 5 | "flag" 6 | "fmt" 7 | "log" 8 | "net/http" 9 | "os" 10 | ) 11 | 12 | func main() { 13 | filename := flag.String("file", "gopher.json", "the JSON file with CYOA story") 14 | port := flag.Int("port", 8080, "the port to start CYOA Web Application") 15 | flag.Parse() 16 | f, err := os.Open(*filename) 17 | if err != nil { 18 | panic(err) 19 | } 20 | story, err := cyoa.ParseJSON(f) 21 | if err != nil { 22 | panic(err) 23 | } 24 | 25 | h := cyoa.NewHandler(story, nil) 26 | fmt.Printf("Started server at Port %d\n", *port) 27 | log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), h)) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /students/ccallergard/html.go: -------------------------------------------------------------------------------- 1 | package cyoa 2 | 3 | import ( 4 | "html/template" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | // Generate uses given template to create HTML files based on an Adventure 10 | func Generate(cyoa Adventure, dirPath string, templatePath string) error { 11 | err := os.MkdirAll(dirPath, os.ModePerm) 12 | if err != nil { 13 | return err 14 | } 15 | 16 | cyoaTemplate, err := template.ParseFiles(templatePath) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | for sceneName, scene := range cyoa { 22 | path := filepath.Join(dirPath, sceneName+".html") 23 | out, err := os.Create(path) 24 | if err != nil { 25 | return err 26 | } 27 | cyoaTemplate.Execute(out, &scene) 28 | out.Close() 29 | } 30 | 31 | return nil 32 | 33 | } 34 | -------------------------------------------------------------------------------- /students/cherednichenkoa/templates/story.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |{{.}}
12 | {{end}} 13 |The End !
25 | {{end}} 26 |{{ $s }}
39 | {{ end }} 40 | 41 | {{ range $o := .Options }} 42 | ☞{{ $o.Text }}{{.}}
18 | {{end}} 19 |{{.}}
34 | {{end}} 35 | {{if .Options}} 36 | {{range .Options}} 37 | {{.Text}} 38 | {{end}} 39 | {{else}} 40 |The end
41 | {{end}} 42 | {{end}} -------------------------------------------------------------------------------- /students/ccallergard/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "flag" 6 | "fmt" 7 | "github.com/gophercises/cyoa/students/ccallergard" 8 | "io/ioutil" 9 | "log" 10 | "net/http" 11 | "strconv" 12 | ) 13 | 14 | var ( 15 | jsonf = flag.String("f", "gopher.json", "Adventure JSON file") 16 | dir = flag.String("d", "_html", "HTML output directory") 17 | port = flag.Int("p", 8080, "HTTP port") 18 | template = flag.String("t", "scene_template.html", "HTML template") 19 | ) 20 | 21 | func main() { 22 | flag.Parse() 23 | 24 | cyoajson, err := ioutil.ReadFile(*jsonf) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | 29 | var adv cyoa.Adventure 30 | err = json.Unmarshal(cyoajson, &adv) 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | 35 | err = cyoa.Generate(adv, *dir, *template) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | 40 | cyoaMux := http.NewServeMux() 41 | cyoaMux.Handle("/", http.RedirectHandler("/cyoa/intro.html", http.StatusPermanentRedirect)) 42 | cyoaMux.Handle("/cyoa/", http.StripPrefix("/cyoa/", http.FileServer(http.Dir(*dir)))) 43 | fmt.Println("HTTP server listening on", *port) 44 | log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), cyoaMux)) 45 | } 46 | -------------------------------------------------------------------------------- /students/cherednichenkoa/route-handler/route_handler.go: -------------------------------------------------------------------------------- 1 | package route_handler 2 | 3 | import ( 4 | "gopherex/cyoa/students/cherednichenkoa/settings" 5 | "gopherex/cyoa/students/cherednichenkoa/source" 6 | "html/template" 7 | "net/http" 8 | "strings" 9 | ) 10 | 11 | const ( 12 | defaultStory = "intro" 13 | ) 14 | 15 | type RouteHandler struct { 16 | Settings settings.Settings 17 | } 18 | 19 | func (rh *RouteHandler) ServeRequests() { 20 | fileHandler := source.JsonFileHandler{Settings: rh.Settings} 21 | fileContent, err := fileHandler.GetFileContent() 22 | if err != nil { 23 | panic(err) 24 | } 25 | urlHandler := rh.getMapHandler(fileContent) 26 | http.HandleFunc("/", urlHandler) 27 | http.ListenAndServe(rh.getPort(), nil) 28 | } 29 | 30 | func (rh *RouteHandler) getMapHandler(stories map[string]source.StoryDetails) http.HandlerFunc { 31 | return func(w http.ResponseWriter, req *http.Request) { 32 | tmpl := template.Must(template.ParseFiles(rh.Settings.GetTemplatePath())) 33 | path := rh.prepareUrl(req) 34 | story, ok := stories[path] 35 | if ok { 36 | tmpl.Execute(w, story) 37 | return 38 | } 39 | 40 | tmpl.Execute(w, stories[defaultStory]) 41 | } 42 | } 43 | 44 | func (rh *RouteHandler) getPort() string { 45 | port := ":" + rh.Settings.GetListenPort() 46 | return port 47 | } 48 | 49 | func (rh *RouteHandler) prepareUrl(req *http.Request) string { 50 | path := strings.Trim(req.URL.Path,"/") 51 | return path 52 | } -------------------------------------------------------------------------------- /students/adeel41/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "log" 7 | "os" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | fmt.Println("Press y key to start the console and ENTER otherwise webserver will be started in 5 seconds...") 14 | keyEntered := make(chan string) 15 | timeout := time.NewTimer(5 * time.Second) 16 | go readInputFromUser(keyEntered) 17 | 18 | select { 19 | case input := <-keyEntered: 20 | if strings.HasPrefix(strings.ToLower(input), "y") { 21 | initliazeAndStart(ConsoleRunner{}) 22 | } else { 23 | initliazeAndStart(WebRunner{}) 24 | } 25 | case <-timeout.C: 26 | initliazeAndStart(WebRunner{}) 27 | } 28 | } 29 | 30 | func readInputFromUser(keyEntered chan string) { 31 | reader := bufio.NewReader(os.Stdin) 32 | input, err := reader.ReadString('\n') 33 | if err != nil { 34 | fmt.Println(err) 35 | } 36 | keyEntered <- input 37 | } 38 | 39 | func initliazeAndStart(runner Runner) { 40 | story := new(Story) 41 | err := story.Load("gopher.json") 42 | if err != nil { 43 | fmt.Println("Stopping program...") 44 | return 45 | } 46 | 47 | tt := ConsoleTemplate 48 | _, ok := runner.(WebRunner) 49 | if ok { 50 | tt = WebTemplate 51 | } 52 | 53 | provider := &StoryArcProvider{ 54 | Story: story, 55 | TemplateType: tt, 56 | } 57 | 58 | err = provider.Initialize() 59 | if err != nil { 60 | log.Panicln(err) 61 | return 62 | } 63 | runner.Start(provider) 64 | } 65 | -------------------------------------------------------------------------------- /students/adeel41/story.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | ) 10 | 11 | //Story contains all arcs found in the file 12 | type Story struct { 13 | arcs []StoryArc 14 | } 15 | 16 | //Load loads the file and extract all arcs found in json file 17 | func (s *Story) Load(filePath string) error { 18 | jsonData, err := s.getJSON(filePath) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | var arcs []StoryArc 24 | for key, data := range jsonData { 25 | arc := new(StoryArc) 26 | arc.Load(key, data.(map[string]interface{})) 27 | arcs = append(arcs, *arc) 28 | } 29 | s.arcs = arcs 30 | return nil 31 | } 32 | 33 | func (s Story) getJSON(filepath string) (map[string]interface{}, error) { 34 | file, err := os.Open(filepath) 35 | if err != nil { 36 | log.Println("Cannot find gopher.json file") 37 | return nil, err 38 | } 39 | defer file.Close() 40 | bytes, err := ioutil.ReadAll(file) 41 | if err != nil { 42 | log.Println("Unable to read gopher.json file") 43 | return nil, err 44 | } 45 | 46 | var data interface{} 47 | err = json.Unmarshal(bytes, &data) 48 | if err != nil { 49 | log.Println("Cannot parse json specified in gopher.json file") 50 | return nil, err 51 | } 52 | return data.(map[string]interface{}), nil 53 | } 54 | 55 | //GetArc finds the arc specified in the key argument and returns it 56 | func (s Story) GetArc(key string) (*StoryArc, error) { 57 | for _, arc := range s.arcs { 58 | if arc.Identifier == key { 59 | return &arc, nil 60 | } 61 | } 62 | return nil, errors.New("Cannot find " + key + " arc") 63 | } 64 | -------------------------------------------------------------------------------- /students/manan/cyoa.go: -------------------------------------------------------------------------------- 1 | package cyoa 2 | 3 | import ( 4 | "encoding/json" 5 | "io" 6 | "log" 7 | "net/http" 8 | "strings" 9 | "text/template" 10 | ) 11 | 12 | type Story map[string]Chapter 13 | 14 | type Chapter struct { 15 | Title string `json:"title"` 16 | Paragraphs []string `json:"story"` 17 | Options []Option `json:"options"` 18 | } 19 | 20 | type Option struct { 21 | Text string `json:"text"` 22 | Arc string `json:"arc"` 23 | } 24 | 25 | type handler struct { 26 | s Story 27 | t *template.Template 28 | } 29 | 30 | func init() { 31 | tpl = template.Must(template.New("").Parse(defaultHandlerTmpl)) 32 | } 33 | 34 | var tpl *template.Template 35 | 36 | var defaultHandlerTmpl = ` 37 | 38 | 39 | 40 |{{.}}
46 | {{end}} 47 |