From 40291a96ddf68d766283850ff11def5823640f7f Mon Sep 17 00:00:00 2001 From: Francesc Campoy Date: Wed, 4 Feb 2015 13:30:07 +0000 Subject: [PATCH 1/4] Adding server for code generation --- server/app.yaml | 27 ++++++++++ server/main.go | 19 +++++++ server/server.go | 115 ++++++++++++++++++++++++++++++++++++++++ server/static/home.html | 73 +++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 server/app.yaml create mode 100644 server/main.go create mode 100644 server/server.go create mode 100644 server/static/home.html diff --git a/server/app.yaml b/server/app.yaml new file mode 100644 index 0000000..530472b --- /dev/null +++ b/server/app.yaml @@ -0,0 +1,27 @@ +# Copyright 2015 Google Inc. All rights reserved. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http:#www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to writing, software distributed +# under the License is distributed on a "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. + +# See the License for the specific language governing permissions and +# limitations under the License. + +version: gae +runtime: go +api_version: go1 + +handlers: +- url: /generate + script: _go_app + +- url: / + static_files: static/home.html + upload: static/home.html + +- url: / + static_dir: static diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..6207104 --- /dev/null +++ b/server/main.go @@ -0,0 +1,19 @@ +// +build !appengine + +package main + +import ( + "flag" + "net/http" +) + +func main() { + port := flag.String("http", "127.0.0.1:8080", "ip and port to listen to") + flag.Parse() + http.HandleFunc("/", homeHandler) + http.ListenAndServe(*port, nil) +} + +func homeHandler(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, "static/home.html") +} diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..4ad8e16 --- /dev/null +++ b/server/server.go @@ -0,0 +1,115 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Server is an http server that provides an alternative way of generating code +// based on int types and the constants defined with it. +// +// Use the http flag to change the address on which the server will listen for +// requests. The default is 127.0.0.1:8080. +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "path/filepath" + "text/template" + + "go/format" + + "github.com/campoy/jsonenums/parser" +) + +func init() { + http.Handle("/generate", handler(generateHandler)) +} + +func generateHandler(w http.ResponseWriter, r *http.Request) error { + if r.Method != "GET" { + return codeError{fmt.Errorf("only GET accepted"), http.StatusMethodNotAllowed} + } + code := r.FormValue("code") + if code == "" { + return codeError{fmt.Errorf("no code to be parsed"), http.StatusBadRequest} + } + typ := r.FormValue("type") + if typ == "" { + return codeError{fmt.Errorf("no type to be analyzed"), http.StatusBadRequest} + } + + dir, err := createDir(code) + if err != nil { + return err + } + defer os.RemoveAll(dir) + + pkg, err := parser.ParsePackage(dir, "") + if err != nil { + return fmt.Errorf("parse package: %v", err) + } + + values, err := pkg.ValuesOfType(typ) + if err != nil { + return fmt.Errorf("find values: %v", err) + } + + t, err := template.New("code").Parse(r.FormValue("template")) + if err != nil { + return codeError{fmt.Errorf("parse template: %v", err), http.StatusBadRequest} + } + var data = struct { + PackageName string + TypeName string + Values []string + }{pkg.Name, typ, values} + + var buf bytes.Buffer + if err := t.Execute(&buf, data); err != nil { + return codeError{fmt.Errorf("execute template: %v", err), http.StatusBadRequest} + } + src, err := format.Source(buf.Bytes()) + if err != nil { + return codeError{fmt.Errorf("code generated is not valid: %v\n%v", err, buf.String()), http.StatusBadRequest} + } + w.Write(src) + return nil +} + +func createDir(content string) (string, error) { + dir, err := ioutil.TempDir("", "jsonenums") + if err != nil { + return "", fmt.Errorf("create tmp dir: %v", err) + } + f, err := os.Create(filepath.Join(dir, "main.go")) + if err != nil { + os.RemoveAll(dir) + return "", fmt.Errorf("create tmp file: %v", err) + } + f.WriteString(content) + f.Close() + return dir, err +} + +type handler func(http.ResponseWriter, *http.Request) error + +func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + err := h(w, r) + if err != nil { + code := http.StatusInternalServerError + if cErr, ok := err.(codeError); ok { + code = cErr.code + } else { + log.Printf("%v: %v", r.URL, code) + } + http.Error(w, err.Error(), code) + } +} + +type codeError struct { + error + code int +} diff --git a/server/static/home.html b/server/static/home.html new file mode 100644 index 0000000..2513053 --- /dev/null +++ b/server/static/home.html @@ -0,0 +1,73 @@ + +jsonenums + + + + + + + +
+ + + +
+ + + + + + + From dfe6af903e8ad07a358e204c7d06ccd5e1eef352 Mon Sep 17 00:00:00 2001 From: Francesc Campoy Date: Wed, 4 Feb 2015 13:38:28 +0000 Subject: [PATCH 2/4] Improved generated code by defining map outside of function. --- template.go | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/template.go b/template.go index dd78689..f937a6f 100644 --- a/template.go +++ b/template.go @@ -20,32 +20,39 @@ import ( {{range $typename, $values := .TypesAndValues}} -func (r {{$typename}}) MarshalJSON() ([]byte, error) { - if s, ok := interface{}(r).(fmt.Stringer); ok { - return json.Marshal(s.String()) +var ( + _{{$typename}}NameToValue = map[string]{{$typename}} { + {{range $values}}"{{.}}": {{.}}, + {{end}} } - s, ok := map[{{$typename}}]string { - {{range $values}}{{.}}: "{{.}}",{{end}} - }[r] - if !ok { - return nil, fmt.Errorf("invalid {{$typename}}: %d", r) - } - return json.Marshal(s) -} -var _{{$typename}}NameToValue = map[string]{{$typename}} { - {{range $values}}"{{.}}": {{.}},{{end}} -} + _{{$typename}}ValueToName = map[{{$typename}}]string { + {{range $values}}{{.}}: "{{.}}", + {{end}} + } +) func init() { var v {{$typename}} if _, ok := interface{}(v).(fmt.Stringer); ok { _{{$typename}}NameToValue = map[string]{{$typename}} { - {{range $values}}interface{}({{.}}).(fmt.Stringer).String(): {{.}},{{end}} + {{range $values}}interface{}({{.}}).(fmt.Stringer).String(): {{.}}, + {{end}} } } } +func (r {{$typename}}) MarshalJSON() ([]byte, error) { + if s, ok := interface{}(r).(fmt.Stringer); ok { + return json.Marshal(s.String()) + } + s, ok := _{{$typename}}ValueToName[r] + if !ok { + return nil, fmt.Errorf("invalid {{$typename}}: %d", r) + } + return json.Marshal(s) +} + func (r *{{$typename}}) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { From a77ef8d8e573450f09553e1fb382214d39121731 Mon Sep 17 00:00:00 2001 From: Francesc Campoy Date: Wed, 4 Feb 2015 13:40:08 +0000 Subject: [PATCH 3/4] Updated generated code in example --- example/shirtsize_jsonenums.go | 49 ++++++++++++++++++++---------- example/weekday_jsonenums.go | 54 ++++++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/example/shirtsize_jsonenums.go b/example/shirtsize_jsonenums.go index 41938cb..af60b7e 100644 --- a/example/shirtsize_jsonenums.go +++ b/example/shirtsize_jsonenums.go @@ -7,32 +7,51 @@ import ( "fmt" ) -func (r ShirtSize) MarshalJSON() ([]byte, error) { - if s, ok := interface{}(r).(fmt.Stringer); ok { - return json.Marshal(s.String()) +var ( + _ShirtSizeNameToValue = map[string]ShirtSize{ + "NA": NA, + "XS": XS, + "S": S, + "M": M, + "L": L, + "XL": XL, } - s, ok := map[ShirtSize]string{ - NA: "NA", XS: "XS", S: "S", M: "M", L: "L", XL: "XL", - }[r] - if !ok { - return nil, fmt.Errorf("invalid ShirtSize: %d", r) - } - return json.Marshal(s) -} -var _ShirtSizeNameToValue = map[string]ShirtSize{ - "NA": NA, "XS": XS, "S": S, "M": M, "L": L, "XL": XL, -} + _ShirtSizeValueToName = map[ShirtSize]string{ + NA: "NA", + XS: "XS", + S: "S", + M: "M", + L: "L", + XL: "XL", + } +) func init() { var v ShirtSize if _, ok := interface{}(v).(fmt.Stringer); ok { _ShirtSizeNameToValue = map[string]ShirtSize{ - interface{}(NA).(fmt.Stringer).String(): NA, interface{}(XS).(fmt.Stringer).String(): XS, interface{}(S).(fmt.Stringer).String(): S, interface{}(M).(fmt.Stringer).String(): M, interface{}(L).(fmt.Stringer).String(): L, interface{}(XL).(fmt.Stringer).String(): XL, + interface{}(NA).(fmt.Stringer).String(): NA, + interface{}(XS).(fmt.Stringer).String(): XS, + interface{}(S).(fmt.Stringer).String(): S, + interface{}(M).(fmt.Stringer).String(): M, + interface{}(L).(fmt.Stringer).String(): L, + interface{}(XL).(fmt.Stringer).String(): XL, } } } +func (r ShirtSize) MarshalJSON() ([]byte, error) { + if s, ok := interface{}(r).(fmt.Stringer); ok { + return json.Marshal(s.String()) + } + s, ok := _ShirtSizeValueToName[r] + if !ok { + return nil, fmt.Errorf("invalid ShirtSize: %d", r) + } + return json.Marshal(s) +} + func (r *ShirtSize) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { diff --git a/example/weekday_jsonenums.go b/example/weekday_jsonenums.go index 6353c21..c24d250 100644 --- a/example/weekday_jsonenums.go +++ b/example/weekday_jsonenums.go @@ -1,4 +1,4 @@ -// generated by jsonenums -type=WeekDay example; DO NOT EDIT +// generated by jsonenums -type=WeekDay; DO NOT EDIT package main @@ -7,32 +7,54 @@ import ( "fmt" ) -func (r WeekDay) MarshalJSON() ([]byte, error) { - if s, ok := interface{}(r).(fmt.Stringer); ok { - return json.Marshal(s.String()) +var ( + _WeekDayNameToValue = map[string]WeekDay{ + "Monday": Monday, + "Tuesday": Tuesday, + "Wednesday": Wednesday, + "Thursday": Thursday, + "Friday": Friday, + "Saturday": Saturday, + "Sunday": Sunday, } - s, ok := map[WeekDay]string{ - Monday: "Monday", Tuesday: "Tuesday", Wednesday: "Wednesday", Thursday: "Thursday", Friday: "Friday", Saturday: "Saturday", Sunday: "Sunday", - }[r] - if !ok { - return nil, fmt.Errorf("invalid WeekDay: %d", r) - } - return json.Marshal(s) -} -var _WeekDayNameToValue = map[string]WeekDay{ - "Monday": Monday, "Tuesday": Tuesday, "Wednesday": Wednesday, "Thursday": Thursday, "Friday": Friday, "Saturday": Saturday, "Sunday": Sunday, -} + _WeekDayValueToName = map[WeekDay]string{ + Monday: "Monday", + Tuesday: "Tuesday", + Wednesday: "Wednesday", + Thursday: "Thursday", + Friday: "Friday", + Saturday: "Saturday", + Sunday: "Sunday", + } +) func init() { var v WeekDay if _, ok := interface{}(v).(fmt.Stringer); ok { _WeekDayNameToValue = map[string]WeekDay{ - interface{}(Monday).(fmt.Stringer).String(): Monday, interface{}(Tuesday).(fmt.Stringer).String(): Tuesday, interface{}(Wednesday).(fmt.Stringer).String(): Wednesday, interface{}(Thursday).(fmt.Stringer).String(): Thursday, interface{}(Friday).(fmt.Stringer).String(): Friday, interface{}(Saturday).(fmt.Stringer).String(): Saturday, interface{}(Sunday).(fmt.Stringer).String(): Sunday, + interface{}(Monday).(fmt.Stringer).String(): Monday, + interface{}(Tuesday).(fmt.Stringer).String(): Tuesday, + interface{}(Wednesday).(fmt.Stringer).String(): Wednesday, + interface{}(Thursday).(fmt.Stringer).String(): Thursday, + interface{}(Friday).(fmt.Stringer).String(): Friday, + interface{}(Saturday).(fmt.Stringer).String(): Saturday, + interface{}(Sunday).(fmt.Stringer).String(): Sunday, } } } +func (r WeekDay) MarshalJSON() ([]byte, error) { + if s, ok := interface{}(r).(fmt.Stringer); ok { + return json.Marshal(s.String()) + } + s, ok := _WeekDayValueToName[r] + if !ok { + return nil, fmt.Errorf("invalid WeekDay: %d", r) + } + return json.Marshal(s) +} + func (r *WeekDay) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { From 081abb77210ff00924a202ebf27764f6e0966cf6 Mon Sep 17 00:00:00 2001 From: Francesc Campoy Date: Wed, 4 Feb 2015 13:44:42 +0000 Subject: [PATCH 4/4] added license comments --- server/main.go | 4 ++++ server/static/home.html | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/server/main.go b/server/main.go index 6207104..52be792 100644 --- a/server/main.go +++ b/server/main.go @@ -1,3 +1,7 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + // +build !appengine package main diff --git a/server/static/home.html b/server/static/home.html index 2513053..d10733b 100644 --- a/server/static/home.html +++ b/server/static/home.html @@ -1,3 +1,11 @@ + + + + jsonenums