diff --git a/.gitignore b/.gitignore index 399a14a..2e384e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ cover.out - +schematic diff --git a/schema/gen.go b/schema/gen.go index 8c2869d..1e5e77c 100644 --- a/schema/gen.go +++ b/schema/gen.go @@ -6,26 +6,11 @@ import ( bundle "github.com/heroku/schematic/schema/templates" "go/format" "regexp" - "strings" "text/template" - "unicode" - "unicode/utf8" ) var templates = template.New("package.tmpl").Funcs(helpers) -var helpers = template.FuncMap{ - "initialCap": initialCap, - "initialLow": initialLow, - "methodCap": methodCap, - "validIdentifer": validIdentifer, - "asComment": asComment, - "jsonTag": jsonTag, - "params": params, - "args": args, - "join": join, -} - var ( newlines = regexp.MustCompile(`(?m:\s*$)`) acronyms = regexp.MustCompile(`(?m)(Url|Http|Id|Uuid|Api|Uri|Ssl|Cname|Oauth)`) @@ -124,6 +109,10 @@ func (s *Schema) GoType(p *Schema) string { case "array": return "[]" + s.GoType(prop.Items) case "object": + // Check if additionalProperties is false. + if m, ok := prop.AdditionalProperties.(bool); ok && !m { + return "map[string]string" + } var buf bytes.Buffer templates.ExecuteTemplate(&buf, "astruct.tmpl", struct { Definition *Schema @@ -148,9 +137,16 @@ func (s *Schema) Parameters(l *Link) map[string]string { for name, def := range l.HRef.Resolve(s) { params[name] = s.GoType(def) } + switch l.Rel { + case "update", "create": + params["options"] = l.GoType(s) + case "instances": + params["r"] = "*ListRange" + } return params } +// Return function return values types. func (s *Schema) Values(name string, l *Link) []string { var values []string name = initialCap(name) @@ -165,108 +161,7 @@ func (s *Schema) Values(name string, l *Link) []string { return values } -func jsonTag(n string, def *Schema) string { - tags := []string{n} - if !contains(n, def.Required) { - tags = append(tags, "omitempty") - } - return fmt.Sprintf("`json:\"%s\"`", strings.Join(tags, ",")) -} - -func contains(n string, r []string) bool { - for _, r := range r { - if r == n { - return true - } - } - return false -} - -func initialCap(ident string) string { - if ident == "" { - panic("blank identifier") - } - return depunct(ident, true) -} - -func methodCap(ident string) string { - return initialCap(strings.ToLower(ident)) -} - -func initialLow(ident string) string { - capitalize := initialCap(ident) - r, n := utf8.DecodeRuneInString(capitalize) - return string(unicode.ToLower(r)) + capitalize[n:] -} - -func validIdentifer(ident string) string { - return depunct(ident, false) -} - -func depunct(ident string, needCap bool) string { - var buf bytes.Buffer - for _, c := range ident { - if c == '-' || c == '.' || c == '$' || c == '/' || c == ':' || c == '_' || c == ' ' || c == '{' || c == '}' { - needCap = true - continue - } - if needCap { - c = unicode.ToUpper(c) - needCap = false - } - buf.WriteByte(byte(c)) - } - depuncted := acronyms.ReplaceAllFunc(buf.Bytes(), func(m []byte) []byte { - if len(m) > 4 { - return append(bytes.ToUpper(m[:2]), m[2:]...) - } - return bytes.ToUpper(m) - }) - return string(depuncted) -} - -func asComment(c string) string { - var buf bytes.Buffer - const maxLen = 70 - removeNewlines := func(s string) string { - return strings.Replace(s, "\n", "\n// ", -1) - } - for len(c) > 0 { - line := c - if len(line) < maxLen { - fmt.Fprintf(&buf, "// %s\n", removeNewlines(line)) - break - } - line = line[:maxLen] - si := strings.LastIndex(line, " ") - if si != -1 { - line = line[:si] - } - fmt.Fprintf(&buf, "// %s\n", removeNewlines(line)) - c = c[len(line):] - if si != -1 { - c = c[1:] - } - } - return buf.String() -} - -func join(p []string) string { - return strings.Join(p, ",") -} - -func params(m map[string]string) string { - var p []string - for k, v := range m { - p = append(p, fmt.Sprintf("%s %s", k, v)) - } - return strings.Join(p, ",") -} - -func args(m map[string]*Schema) string { - var p []string - for k, _ := range m { - p = append(p, k) - } - return strings.Join(p, ", ") +func (l *Link) GoType(r *Schema) string { + // FIXME: Arguments are reverse from Schema.GoType() + return r.GoType(l.Schema) } diff --git a/schema/helpers.go b/schema/helpers.go new file mode 100644 index 0000000..2d41cc6 --- /dev/null +++ b/schema/helpers.go @@ -0,0 +1,128 @@ +package schema + +import ( + "bytes" + "fmt" + "strings" + "text/template" + "unicode" + "unicode/utf8" +) + +var helpers = template.FuncMap{ + "initialCap": initialCap, + "initialLow": initialLow, + "methodCap": methodCap, + "validIdentifer": validIdentifer, + "asComment": asComment, + "jsonTag": jsonTag, + "params": params, + "args": args, + "join": join, +} + +func jsonTag(n string, def *Schema) string { + tags := []string{n} + if !contains(n, def.Required) { + tags = append(tags, "omitempty") + } + return fmt.Sprintf("`json:\"%s\"`", strings.Join(tags, ",")) +} + +func contains(n string, r []string) bool { + for _, r := range r { + if r == n { + return true + } + } + return false +} + +func initialCap(ident string) string { + if ident == "" { + panic("blank identifier") + } + return depunct(ident, true) +} + +func methodCap(ident string) string { + return initialCap(strings.ToLower(ident)) +} + +func initialLow(ident string) string { + capitalize := initialCap(ident) + r, n := utf8.DecodeRuneInString(capitalize) + return string(unicode.ToLower(r)) + capitalize[n:] +} + +func validIdentifer(ident string) string { + return depunct(ident, false) +} + +func depunct(ident string, needCap bool) string { + var buf bytes.Buffer + for _, c := range ident { + if c == '-' || c == '.' || c == '$' || c == '/' || c == ':' || c == '_' || c == ' ' || c == '{' || c == '}' { + needCap = true + continue + } + if needCap { + c = unicode.ToUpper(c) + needCap = false + } + buf.WriteByte(byte(c)) + } + depuncted := acronyms.ReplaceAllFunc(buf.Bytes(), func(m []byte) []byte { + if len(m) > 4 { + return append(bytes.ToUpper(m[:2]), m[2:]...) + } + return bytes.ToUpper(m) + }) + return string(depuncted) +} + +func asComment(c string) string { + var buf bytes.Buffer + const maxLen = 70 + removeNewlines := func(s string) string { + return strings.Replace(s, "\n", "\n// ", -1) + } + for len(c) > 0 { + line := c + if len(line) < maxLen { + fmt.Fprintf(&buf, "// %s\n", removeNewlines(line)) + break + } + line = line[:maxLen] + si := strings.LastIndex(line, " ") + if si != -1 { + line = line[:si] + } + fmt.Fprintf(&buf, "// %s\n", removeNewlines(line)) + c = c[len(line):] + if si != -1 { + c = c[1:] + } + } + return buf.String() +} + +func join(p []string) string { + return strings.Join(p, ",") +} + +func params(m map[string]string) string { + var p []string + for k, v := range m { + p = append(p, fmt.Sprintf("%s %s", k, v)) + } + return strings.Join(p, ",") +} + +func args(m map[string]*Schema) string { + var p []string + for k, _ := range m { + p = append(p, k) + } + return strings.Join(p, ", ") +} diff --git a/schema/templates/funcs.tmpl b/schema/templates/funcs.tmpl index 457e728..adb57ec 100644 --- a/schema/templates/funcs.tmpl +++ b/schema/templates/funcs.tmpl @@ -5,13 +5,17 @@ func (c *Client) {{printf "%s-%s" $Name .Title | initialCap}}({{$Root.Parameters . | params}}) ({{$Root.Values $Name . | join}}) { {{if eq .Rel "destroy"}} return c.Delete(fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) + {{else if eq .Rel "self"}} + {{$Var := initialLow $Name}}var {{$Var}} {{initialCap $Name}} + return &{{$Var}}, c.Get(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) {{else if eq .Rel "instances"}} {{$Var := printf "%s-%s" $Name "List" | initialLow}} var {{$Var}} []*{{initialCap $Name}} return {{$Var}}, c.{{methodCap .Method}}(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) {{else}} {{$Var := initialLow $Name}}var {{$Var}} {{initialCap $Name}} - return &{{$Var}}, c.{{methodCap .Method}}(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) + return &{{$Var}}, c.{{methodCap .Method}}(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}}), options) {{end}} } -{{end}} \ No newline at end of file +{{end}} + diff --git a/schema/templates/struct.tmpl b/schema/templates/struct.tmpl index b486264..a4c4c19 100644 --- a/schema/templates/struct.tmpl +++ b/schema/templates/struct.tmpl @@ -1,4 +1,4 @@ {{if .Definition.Properties}} {{asComment .Definition.Description}} type {{initialCap .Name}} {{template "astruct.tmpl" .}} -{{end}} \ No newline at end of file +{{end}} diff --git a/schema/templates/templates.go b/schema/templates/templates.go index 361ea81..21e6fa7 100644 --- a/schema/templates/templates.go +++ b/schema/templates/templates.go @@ -14,16 +14,21 @@ var templates = map[string]string{"astruct.tmpl": `{{$Root := .Root}} struct { func (c *Client) {{printf "%s-%s" $Name .Title | initialCap}}({{$Root.Parameters . | params}}) ({{$Root.Values $Name . | join}}) { {{if eq .Rel "destroy"}} return c.Delete(fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) + {{else if eq .Rel "self"}} + {{$Var := initialLow $Name}}var {{$Var}} {{initialCap $Name}} + return &{{$Var}}, c.Get(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) {{else if eq .Rel "instances"}} {{$Var := printf "%s-%s" $Name "List" | initialLow}} var {{$Var}} []*{{initialCap $Name}} return {{$Var}}, c.{{methodCap .Method}}(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) {{else}} {{$Var := initialLow $Name}}var {{$Var}} {{initialCap $Name}} - return &{{$Var}}, c.{{methodCap .Method}}(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}})) + return &{{$Var}}, c.{{methodCap .Method}}(&{{$Var}}, fmt.Sprintf("{{.HRef}}", {{.HRef.Resolve $Root | args}}), options) {{end}} } -{{end}}`, +{{end}} + +`, "imports.tmpl": `{{if .}} {{if len . | eq 1}} import {{range .}}"{{.}}"{{end}} @@ -40,7 +45,8 @@ var templates = map[string]string{"astruct.tmpl": `{{$Root := .Root}} struct { "struct.tmpl": `{{if .Definition.Properties}} {{asComment .Definition.Description}} type {{initialCap .Name}} {{template "astruct.tmpl" .}} -{{end}}`, +{{end}} +`, } func Parse(t *template.Template) (*template.Template, error) { @@ -60,4 +66,3 @@ func Parse(t *template.Template) (*template.Template, error) { } return t, nil } -