Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adding initial support to generate content type from more descriptive…
… cli args
- Loading branch information
Showing
4 changed files
with
262 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package main | ||
|
||
import "testing" | ||
|
||
func TestParseType(t *testing.T) { | ||
// blog title:string Author:string PostCategory:string content:string some_thing:int | ||
args := []string{ | ||
"blog", "title:string", "Author:string", | ||
"PostCategory:string", "content:string", | ||
"some_thing:int", "Some_otherThing:float64", | ||
} | ||
|
||
gt, err := parseType(args) | ||
if err != nil { | ||
t.Errorf("Failed: %s", err.Error()) | ||
} | ||
|
||
if gt.Name != "Blog" { | ||
t.Errorf("Expected %s, got: %s", "Blog", gt.Name) | ||
} | ||
} | ||
|
||
func TestFieldJSONName(t *testing.T) { | ||
cases := map[string]string{ | ||
"_T": "t", | ||
"T": "t", | ||
"_tT_": "t_t_", | ||
"TestCapsNoSym": "test_caps_no_sym", | ||
"test_Some_caps_Sym": "test_some_caps_sym", | ||
"testnocaps": "testnocaps", | ||
"_Test_Caps_Sym_odd": "test_caps_sym_odd", | ||
"test-hyphen": "test-hyphen", | ||
"Test-hyphen-Caps": "test-hyphen-caps", | ||
"Test-Hyphen_Sym-Caps": "test-hyphen_sym-caps", | ||
} | ||
|
||
for input, expected := range cases { | ||
output := fieldJSONName(input) | ||
if output != expected { | ||
t.Errorf("Expected: %s, got: %s", expected, output) | ||
} | ||
} | ||
} | ||
|
||
func TestFieldName(t *testing.T) { | ||
cases := map[string]string{ | ||
"_T": "T", | ||
"T": "T", | ||
"_tT_": "TT", | ||
"TestCapsNoSym": "TestCapsNoSym", | ||
"test_Some_caps_Sym": "TestSomeCapsSym", | ||
"testnocaps": "Testnocaps", | ||
"_Test_Caps_Sym_odd": "TestCapsSymOdd", | ||
"test-hyphen": "TestHyphen", | ||
"Test-hyphen-Caps": "TestHyphenCaps", | ||
"Test-Hyphen_Sym-Caps": "TestHyphenSymCaps", | ||
} | ||
|
||
for input, expected := range cases { | ||
output := fieldName(input) | ||
if output != expected { | ||
t.Errorf("Expected: %s, got: %s", expected, output) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"go/format" | ||
"html/template" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
type generateType struct { | ||
Name string | ||
Initial string | ||
Fields []generateField | ||
} | ||
|
||
type generateField struct { | ||
Name string | ||
TypeName string | ||
JSONName string | ||
} | ||
|
||
// blog title:string Author:string PostCategory:string content:string some_thing:int | ||
func parseType(args []string) (generateType, error) { | ||
t := generateType{ | ||
Name: fieldName(args[0]), | ||
} | ||
t.Initial = strings.ToLower(string(t.Name[0])) | ||
|
||
fields := args[1:] | ||
for _, field := range fields { | ||
f, err := parseField(field) | ||
if err != nil { | ||
return generateType{}, err | ||
} | ||
|
||
t.Fields = append(t.Fields, f) | ||
} | ||
|
||
return t, nil | ||
} | ||
|
||
func parseField(raw string) (generateField, error) { | ||
// title:string | ||
if !strings.Contains(raw, ":") { | ||
return generateField{}, fmt.Errorf("Invalid generate argument. [%s]", raw) | ||
} | ||
|
||
pair := strings.Split(raw, ":") | ||
field := generateField{ | ||
Name: fieldName(pair[0]), | ||
TypeName: strings.ToLower(pair[1]), | ||
JSONName: fieldJSONName(pair[0]), | ||
} | ||
|
||
return field, nil | ||
} | ||
|
||
// get the initial field name passed and check it for all possible cases | ||
// MyTitle:string myTitle:string my_title:string -> MyTitle | ||
// error-message:string -> ErrorMessage | ||
func fieldName(name string) string { | ||
// remove _ or - if first character | ||
if name[0] == '-' || name[0] == '_' { | ||
name = name[1:] | ||
} | ||
|
||
// remove _ or - if last character | ||
if name[len(name)-1] == '-' || name[len(name)-1] == '_' { | ||
name = name[:len(name)-1] | ||
} | ||
|
||
// upcase the first character | ||
name = strings.ToUpper(string(name[0])) + name[1:] | ||
|
||
// remove _ or - character, and upcase the character immediately following | ||
for i := 0; i < len(name); i++ { | ||
r := rune(name[i]) | ||
if isUnderscore(r) || isHyphen(r) { | ||
up := strings.ToUpper(string(name[i+1])) | ||
name = name[:i] + up + name[i+2:] | ||
} | ||
} | ||
|
||
return name | ||
} | ||
|
||
// get the initial field name passed and convert to json-like name | ||
// MyTitle:string myTitle:string my_title:string -> my_title | ||
// error-message:string -> error-message | ||
func fieldJSONName(name string) string { | ||
// remove _ or - if first character | ||
if name[0] == '-' || name[0] == '_' { | ||
name = name[1:] | ||
} | ||
|
||
// downcase the first character | ||
name = strings.ToLower(string(name[0])) + name[1:] | ||
|
||
// check for uppercase character, downcase and insert _ before it if i-1 | ||
// isn't already _ or - | ||
for i := 0; i < len(name); i++ { | ||
r := rune(name[i]) | ||
if isUpper(r) { | ||
low := strings.ToLower(string(r)) | ||
if name[i-1] == '_' || name[i-1] == '-' { | ||
name = name[:i] + low + name[i+1:] | ||
} else { | ||
name = name[:i] + "_" + low + name[i+1:] | ||
} | ||
} | ||
} | ||
|
||
return name | ||
} | ||
|
||
func isUpper(char rune) bool { | ||
if char >= 'A' && char <= 'Z' { | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
func isUnderscore(char rune) bool { | ||
return char == '_' | ||
} | ||
|
||
func isHyphen(char rune) bool { | ||
return char == '-' | ||
} | ||
|
||
func generateContentType(args []string, path string) error { | ||
name := args[0] | ||
fileName := strings.ToLower(name) + ".go" | ||
|
||
// open file in ./content/ dir | ||
// if exists, alert user of conflict | ||
pwd, err := os.Getwd() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if path != "" { | ||
pwd = path | ||
} | ||
|
||
contentDir := filepath.Join(pwd, "content") | ||
filePath := filepath.Join(contentDir, fileName) | ||
|
||
if _, err := os.Stat(filePath); !os.IsNotExist(err) { | ||
return fmt.Errorf("Please remove '%s' before executing this command.", fileName) | ||
} | ||
|
||
// no file exists.. ok to write new one | ||
file, err := os.Create(filePath) | ||
defer file.Close() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// parse type info from args | ||
gt, err := parseType(args) | ||
if err != nil { | ||
return fmt.Errorf("Failed to parse type args: %s", err.Error()) | ||
} | ||
|
||
tmpl, err := template.ParseFiles("contentType.tmpl") | ||
if err != nil { | ||
return fmt.Errorf("Failed to parse template: %s", err.Error()) | ||
} | ||
|
||
buf := &bytes.Buffer{} | ||
err = tmpl.Execute(buf, gt) | ||
if err != nil { | ||
return fmt.Errorf("Failed to execute template: %s", err.Error()) | ||
} | ||
|
||
fmtBuf, err := format.Source(buf.Bytes()) | ||
if err != nil { | ||
return fmt.Errorf("Failed to format template: %s", err.Error()) | ||
} | ||
|
||
_, err = file.Write(fmtBuf) | ||
if err != nil { | ||
return fmt.Errorf("Failed to write generated file buffer: %s", err.Error()) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.