Merge pull request #5 from campoy/refactor

Add server
This commit is contained in:
Francesc Campoy 2015-02-04 13:45:11 +00:00
commit c80e0662c2
7 changed files with 339 additions and 45 deletions

View File

@ -7,32 +7,51 @@ import (
"fmt" "fmt"
) )
func (r ShirtSize) MarshalJSON() ([]byte, error) { var (
if s, ok := interface{}(r).(fmt.Stringer); ok { _ShirtSizeNameToValue = map[string]ShirtSize{
return json.Marshal(s.String()) "NA": NA,
} "XS": XS,
s, ok := map[ShirtSize]string{ "S": S,
NA: "NA", XS: "XS", S: "S", M: "M", L: "L", XL: "XL", "M": M,
}[r] "L": L,
if !ok { "XL": XL,
return nil, fmt.Errorf("invalid ShirtSize: %d", r)
}
return json.Marshal(s)
} }
var _ShirtSizeNameToValue = map[string]ShirtSize{ _ShirtSizeValueToName = map[ShirtSize]string{
"NA": NA, "XS": XS, "S": S, "M": M, "L": L, "XL": XL, NA: "NA",
XS: "XS",
S: "S",
M: "M",
L: "L",
XL: "XL",
} }
)
func init() { func init() {
var v ShirtSize var v ShirtSize
if _, ok := interface{}(v).(fmt.Stringer); ok { if _, ok := interface{}(v).(fmt.Stringer); ok {
_ShirtSizeNameToValue = map[string]ShirtSize{ _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 { func (r *ShirtSize) UnmarshalJSON(data []byte) error {
var s string var s string
if err := json.Unmarshal(data, &s); err != nil { if err := json.Unmarshal(data, &s); err != nil {

View File

@ -7,32 +7,54 @@ import (
"fmt" "fmt"
) )
func (r WeekDay) MarshalJSON() ([]byte, error) { var (
if s, ok := interface{}(r).(fmt.Stringer); ok { _WeekDayNameToValue = map[string]WeekDay{
return json.Marshal(s.String()) "Monday": Monday,
} "Tuesday": Tuesday,
s, ok := map[WeekDay]string{ "Wednesday": Wednesday,
Monday: "Monday", Tuesday: "Tuesday", Wednesday: "Wednesday", Thursday: "Thursday", Friday: "Friday", Saturday: "Saturday", Sunday: "Sunday", "Thursday": Thursday,
}[r] "Friday": Friday,
if !ok { "Saturday": Saturday,
return nil, fmt.Errorf("invalid WeekDay: %d", r) "Sunday": Sunday,
}
return json.Marshal(s)
} }
var _WeekDayNameToValue = map[string]WeekDay{ _WeekDayValueToName = map[WeekDay]string{
"Monday": Monday, "Tuesday": Tuesday, "Wednesday": Wednesday, "Thursday": Thursday, "Friday": Friday, "Saturday": Saturday, "Sunday": Sunday, Monday: "Monday",
Tuesday: "Tuesday",
Wednesday: "Wednesday",
Thursday: "Thursday",
Friday: "Friday",
Saturday: "Saturday",
Sunday: "Sunday",
} }
)
func init() { func init() {
var v WeekDay var v WeekDay
if _, ok := interface{}(v).(fmt.Stringer); ok { if _, ok := interface{}(v).(fmt.Stringer); ok {
_WeekDayNameToValue = map[string]WeekDay{ _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 { func (r *WeekDay) UnmarshalJSON(data []byte) error {
var s string var s string
if err := json.Unmarshal(data, &s); err != nil { if err := json.Unmarshal(data, &s); err != nil {

27
server/app.yaml Normal file
View File

@ -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

23
server/main.go Normal file
View File

@ -0,0 +1,23 @@
// 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
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")
}

115
server/server.go Normal file
View File

@ -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
}

81
server/static/home.html Normal file
View File

@ -0,0 +1,81 @@
<!DOCTYPE html>
<!--
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.
-->
<html>
<title>jsonenums</title>
<style>
textarea,
input {
display: block;
width: 80%;
margin: auto;
}
textarea {
height: 200px;
overflow-y: scroll;
}
</style>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script>
function generate() {
$.get("/generate", {
"code": $("#code").val(),
"type": $("#type").val(),
"template": $("#template").val(),
}).done(function(res) {
$("#result").val(res);
$("#result").css('background','#fff');
}).fail(function(res) {
$("#result").val(res.responseText);
$("#result").css('background','#fee');
})
}
</script>
<body>
<form action="/generate" method="GET">
<input type="text" id="type" value="WeekDay">
<textarea id="code">
package test
type WeekDay int
const (
Monday WeekDay = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
</textarea>
<textarea id="template">
package {{.PackageName}}
func (r {{.TypeName}}) String() string {
s, ok := map[{{.TypeName}}]string {
{{range .Values}}{{.}}:"{{.}}",{{end}}
}
if !ok {
return "unknown {{.TypeName}}"
}
return s
}
</textarea>
</form>
<input type="button" onclick="generate()" value="generate code">
<textarea id="result">
</textarea>
</body>
</html>

View File

@ -20,32 +20,39 @@ import (
{{range $typename, $values := .TypesAndValues}} {{range $typename, $values := .TypesAndValues}}
func (r {{$typename}}) MarshalJSON() ([]byte, error) { var (
if s, ok := interface{}(r).(fmt.Stringer); ok { _{{$typename}}NameToValue = map[string]{{$typename}} {
return json.Marshal(s.String()) {{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}} { _{{$typename}}ValueToName = map[{{$typename}}]string {
{{range $values}}"{{.}}": {{.}},{{end}} {{range $values}}{{.}}: "{{.}}",
{{end}}
} }
)
func init() { func init() {
var v {{$typename}} var v {{$typename}}
if _, ok := interface{}(v).(fmt.Stringer); ok { if _, ok := interface{}(v).(fmt.Stringer); ok {
_{{$typename}}NameToValue = map[string]{{$typename}} { _{{$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 { func (r *{{$typename}}) UnmarshalJSON(data []byte) error {
var s string var s string
if err := json.Unmarshal(data, &s); err != nil { if err := json.Unmarshal(data, &s); err != nil {