Skip to content

Commit

Permalink
🎈 update: add some useful function
Browse files Browse the repository at this point in the history
  • Loading branch information
OhYee committed Sep 9, 2019
1 parent 1604205 commit 49c3288
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 47 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
bin
bin
.vscode
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,37 @@ Using json file and go template to generate go code.

## Installation

```
```bash
go get github.com/OhYee/gcg
go install github.com/OhYee/gcg
```

## Usage

```
```bash
gcg data.json compare.go
```

## document
## Document

The json file must have these field:

|name|type||
|:---:|:---:|:---:|
|:---|:---|:---|
|package|string|package name|
|import|`[]string` or `[][]string`|import part of the file|
|body|`[]strut{template string, args interface{}}` or `[]struct{template []string, args interface{}}`|the go file body|

The `template` and `args` in `body` will be the arguments of go `text/template`

### Function

|name|args||
|:---|:---|:---|
|lower|`string`|make all letters to their lower case|
|upper|`string`|make all letters to their upper case|
|upperFirstChar|`string`|make the first letter to its upper case, keep others|

## Example

See [number compare package](https://github.com/OhYee/gcg/tree/master/example/compare), you can delete `compare.go` and using `gcg data.json compare.go` or `go generate g.go` to re-generate it.
Expand Down
10 changes: 9 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,21 @@ gcg data.json compare.go
JSON文件字段要求

|名称|类型||
|:---:|:---:|:---:|
|:---|:---|:---|
|package|string|生成文件的包名|
|import|`[]string` or `[][]string`|Go文件的引入包部分|
|body|`[]strut{template string, args interface{}}` or `[]struct{template []string, args interface{}}`|Go文件主体|

`body``template``args` 将用于 Go `text/template` 的参数

### 函数

|名称|参数||
|:---|:---|:---|
|lower|`string`|使所有字母小写|
|upper|`string`|使所有字母大写|
|upperFirstChar|`string`|使首字母大写|

## 样例

详情见 [大小比较包](https://github.com/OhYee/gcg/tree/master/example/compare), 你可以先删除 `compare.go` 然后使用 `gcg data.json compare.go` 或者 `go generate g.go` 来重新生成它.
Expand Down
2 changes: 1 addition & 1 deletion example/compare/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
],
"body": [
{
"template": "const.tpl",
"template": "/home/ohyee/projects/gcg/example/compare/const.tpl",
"args": ["-"]
},
{
Expand Down
102 changes: 62 additions & 40 deletions gcg.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (
"encoding/json"
"fmt"
"go/format"
"io"
"io/ioutil"
"os"
"strings"
"text/template"
)

const (
version = "0.0.2"
version = "0.0.3"
helpText = "Using `gcg <json file> [<output file>]` to generate go file\nSuch as `gcg data.json` or `gcg data.json ../add.go`"
)

Expand All @@ -35,6 +36,18 @@ type bodyArea struct {
}
type jsonMap = map[string]interface{}

var funcMap = template.FuncMap{
"upperFirstChar": func(text string) string {
return fmt.Sprintf("%s%s", strings.ToUpper(text[0:1]), text[1:len(text)])
},
"upper": func(text string) string {
return strings.ToUpper(text)
},
"lower": func(text string) string {
return strings.ToLower(text)
},
}

// exitWhenError exit the program when error is not null
func exitWhenError(err error) {
if err != nil {
Expand Down Expand Up @@ -88,28 +101,28 @@ func importPackage(x interface{}) (s string) {
return
}

func main() {
var inputFile string
var outputFile *os.File
switch len(os.Args) {
case 1:
exitWhenFalse(false, helpText)
case 2:
if os.Args[1] == "-h" || os.Args[1] == "--help" {
exitWhenFalse(false, helpText)
} else if os.Args[1] == "-v" || os.Args[1] == "--version" {
exitWhenFalse(false, fmt.Sprintf("Go Code Generator version: %s\n", version))
}
inputFile = os.Args[1]
outputFile = os.Stdout
default:
var err error
inputFile = os.Args[1]
outputFile, err = os.Create(os.Args[2])
exitWhenError(err)
// getFilename from a path (go template name can not be a path)
func getFileName(path string) (filename string) {
pathList := strings.Split(path, "/")
filename = pathList[len(pathList)-1]
return
}

// renderTemplate render the block template
func renderTemplate(buf io.Writer, templates []string, args []interface{}) {
templateName := getFileName(templates[0])
tpl, err := template.New(templateName).Funcs(funcMap).ParseFiles(templates...)
exitWhenError(err)
for _, arg := range args {
// tpl.Execute(buf, arg)
tpl.ExecuteTemplate(buf, templateName, arg)
buf.Write([]byte{'\n'})
}
args := readData(inputFile)
}

// renderContent render generated file content
func renderContent(args arguments) []byte {
// header
buf := bytes.NewBufferString("// generated by Go Code Generator(https://github.com/OhYee/gcg); DO NOT EDIT\n\n")
buf.WriteString(fmt.Sprintf("package %s\n\n", args.PackageName))
buf.WriteString(fmt.Sprintf("import (\n%s\n)\n\n",
Expand All @@ -127,6 +140,7 @@ func main() {
}(args.ImportedPackage),
))

// body
for _, block := range args.Body {
var templates []string
switch block.Template.(type) {
Expand All @@ -144,31 +158,39 @@ func main() {
default:
exitWhenFalse(false, "template must be string or []string")
}

tpl, err := template.New(templates[0]).Funcs(
template.FuncMap{
"upperFirstChar": func(text string) string {
return strings.ToTitle(text)
},
"upper": func(text string) string {
return strings.ToUpper(text)
},
"lower": func(text string) string {
return strings.ToLower(text)
},
},
).ParseFiles(templates...)
exitWhenError(err)
for _, arg := range block.Args {
tpl.Execute(buf, arg)
buf.WriteString("\n\n")
}
renderTemplate(buf, templates, block.Args)
}

// code format
b, err := format.Source(buf.Bytes())
if err != nil {
fmt.Printf("goformat error\n%s\n", err)
b = buf.Bytes()
}
return b
}

func main() {
var inputFile string
var outputFile *os.File
switch len(os.Args) {
case 1:
exitWhenFalse(false, helpText)
case 2:
if os.Args[1] == "-h" || os.Args[1] == "--help" {
exitWhenFalse(false, helpText)
} else if os.Args[1] == "-v" || os.Args[1] == "--version" {
exitWhenFalse(false, fmt.Sprintf("Go Code Generator version: %s\n", version))
}
inputFile = os.Args[1]
outputFile = os.Stdout
default:
var err error
inputFile = os.Args[1]
outputFile, err = os.Create(os.Args[2])
exitWhenError(err)
}
args := readData(inputFile)
b := renderContent(args)
outputFile.Write(b)
}
84 changes: 84 additions & 0 deletions gcg_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package main

import (
"bytes"
"io/ioutil"
"os"
"testing"
)

func writeToTempFile(t *testing.T, content string) string {
file, err := ioutil.TempFile("", "test")
if err != nil {
t.Errorf("Create temp file error: %v", err)
}
_, err = file.WriteString(content)
if err != nil {
t.Errorf("Write to temp file error: %v", err)
}
file.Close()
return file.Name()
}

func Test_renderTemplate(t *testing.T) {
tests := []struct {
name string
template string
args []interface{}
result string
}{
{
name: "test upper",
template: "{{upper .text}}",
args: []interface{}{
map[string]interface{}{
"text": "ABcdefg1234567",
},
},
result: "ABCDEFG1234567\n",
},
{
name: "test lower",
template: "{{lower .text}}",
args: []interface{}{
map[string]interface{}{
"text": "ABcdefg1234567",
},
},
result: "abcdefg1234567\n",
},
{
name: "test upperFirstChar",
template: "{{upperFirstChar .text}}",
args: []interface{}{
map[string]interface{}{
"text": "ABcdefg1234567",
},
},
result: "ABcdefg1234567\n",
},
{
name: "test upperFirstChar 2",
template: "{{upperFirstChar .text}}",
args: []interface{}{
map[string]interface{}{
"text": "abc",
},
},
result: "Abc\n",
},
}

buf := bytes.NewBuffer([]byte{})
for _, tt := range tests {
buf.Reset()
filename := writeToTempFile(t, tt.template)
t.Run(tt.name, func(t *testing.T) {
renderTemplate(buf, []string{filename}, tt.args)
if buf.String() != tt.result {
t.Errorf("want %v, but got %v", tt.result, buf.String())
}
})
os.Remove(filename)
}
}

0 comments on commit 49c3288

Please sign in to comment.