pax_global_header 0000666 0000000 0000000 00000000064 13502324010 0014500 g ustar 00root root 0000000 0000000 52 comment=eb5b6aa387fb8e39dfaa43d584488a29af617eed easygen-4.1.0/ 0000775 0000000 0000000 00000000000 13502324010 0013135 5 ustar 00root root 0000000 0000000 easygen-4.1.0/.gitignore 0000664 0000000 0000000 00000000413 13502324010 0015123 0 ustar 00root root 0000000 0000000 # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof easygen-4.1.0/.travis.yml 0000664 0000000 0000000 00000000015 13502324010 0015242 0 ustar 00root root 0000000 0000000 language: go easygen-4.1.0/LICENSE 0000664 0000000 0000000 00000002063 13502324010 0014143 0 ustar 00root root 0000000 0000000 The MIT License (MIT) Copyright (c) 2015 suntong Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. easygen-4.1.0/README.e.md 0000664 0000000 0000000 00000017102 13502324010 0014640 0 ustar 00root root 0000000 0000000 # {{.Name}} [](LICENSE) {{template "badge/godoc" .}} {{template "badge/goreport" .}} {{template "badge/travis" .}} [ ](https://codeship.com/projects/135255) ## {{toc 5}} # {{.Name}} - Easy to use universal code/text generator Command `{{.Name}}` is an easy to use universal code/text generator. It can be used as a text or html generator for _arbitrary_ purposes with _arbitrary_ data and templates. It is a good [GSL](https://github.com/imatix/gsl) replacement, as it - is more easy to define driving data, in form of YML instead of XML - has more powerful template engine that based on Go template. You can also write your own function in Go to customize your template. You can even use easygen as a generic Go template testing tool using the `-ts` commandline option, and much more. Note this document is for `{{.Name}}` versions 4.0+. For historic versions check out the [Different Versions](#different-versions) section. ## Usage ### $ {{exec "easygen" | color "sh"}} ## Install ### Install as Debian/Unbuntu package apt install {{.Name}} ### Install from source go get github.com/go-easygen/easygen/... ls -l $GOPATH/bin You should find an `{{.Name}}` executable newly created in there. ## Test export PATH=$PATH:$GOPATH/bin $ easygen $GOPATH/src/github.com/go-easygen/easygen/test/list0 The colors are: red, blue, white, . cd $GOPATH/src/github.com/go-easygen/easygen $ easygen test/list1 The quoted colors are: "red", "blue", "white", . $ easygen test/listfunc1 test/list0 red, blue, white. And also check out the provided [more examples](https://godoc.org/github.com/go-easygen/easygen#pkg-examples) in the [](https://godoc.org/github.com/go-easygen/easygen) document. ## Details It can be used as a code generator, for example, command line parameter handling code generator, or anything that is structurally repetitive, like the following: - [Introduction to easygen and its philosophy ](https://suntong.github.io/blogs/2016/01/01/easygen---easy-to-use-universal-code/text-generator) - [Easygen is now coding itself ](https://sfxpt.wordpress.com/2015/07/04/easygen-is-now-coding-itself/) - [Showcasing the power of easygen with ffcvt ](https://sfxpt.wordpress.com/2015/08/02/showcasing-the-power-of-easygen-with-ffcvt/) - [Easygen for HTML mock-up ](https://sfxpt.wordpress.com/2015/07/10/easygen-for-mock-up/) - [Moving beyond code-gen and mock-up, using easygen in real life creating GPT partitions](https://suntong.github.io/blogs/2015/12/26/creating-gpt-partitions-easily-on-the-command-line) Ready to get started? Then check out [Getting Started](https://github.com/go-easygen/easygen/wiki/Getting-Started) to start building your way to turn your data into any form, any way you want. ## Command line flag handling code auto-generation [ ](https://suntong.github.io/blogs/) As explained above, one practical use of `easygen` is to auto-generating Go code for command line parameter handling, for both [`viper` and `cobra`](https://github.com/suntong/blog/blob/master/GoOptP7-easygen.md), and Go's [built-in `flag` package](https://sfxpt.wordpress.com/2015/07/04/easygen-is-now-coding-itself/). ### `easygen` itself Currently, `easygen`'s command line parameter handling is built on top of Go's built-in `flag` package, and the handling code is entirely generated by `easygen` itself. Thus, showing how `easygen` is handling the command line parameters itself also means showing what functionality the auto-generated command line parameter handling code can do for you. Currently, there are three tiers program parameters can be given: 1. Default values defined within the program, so that program parameters can have meaningful defaults to start with 1. Values defined in environment variables 1. Values passed from command line The latter will have higher priority and will override values defined formerly. I.e., the values from command line will override that in environment variables, which in turn override program defaults. We will use the `-ts`, template string, as an example to illustrate. The program defaults is empty, which means using the `.tmpl` template file the same as the `.yaml` data file. We will override that first by environment variable, then from command line, illustrated in next section. ### `cli` based See, [A cookbook on how to jump-start a `cli` based command line handling program](cli-project.md#cookbook) ## The `easygen` usage ### Command line [Check here for more on using `easygen` the command line tool](using_easygen.md). ### The library The `easygen` is a library as well as a command line tools. Not only it is super easy to use, it is super easy to extend as well. The [restructured `easygen`](https://github.com/go-easygen/easygen/issues/10) can now be a building block that people can easily extend, any extra functionalities, or extra feature that it depends on, or any external dependencies are now moved out to sub modules. Thus the library users can now pick and choose exactly what they want from the library. - The [egVar package example](http://godoc.org/github.com/go-easygen/easygen/egVar#example-package) shows how to add the variable name manipulation on top of the default library. - The [egCal package example](http://godoc.org/github.com/go-easygen/easygen/egCal#example-package) shows how to add the variable name manipulation and generic calculation functionalities, together with the default functions, all at the same time. To put them all together, check out the `easygen`'s `main.go`: #### > cmd/easygen/main.go ```go package main import ( "flag" "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egCal" "github.com/go-easygen/easygen/egVar" ) //go:generate sh -v easygen.gen.sh //////////////////////////////////////////////////////////////////////////// // Main func main() { flag.Usage = Usage flag.Parse() // One mandatory non-flag arguments if flag.NArg() < 1 { Usage() } tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()). Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs()) args := flag.Args() if len(easygen.Opts.TemplateStr) > 0 { easygen.Process0(tmpl, os.Stdout, easygen.Opts.TemplateStr, args...) } else { easygen.Process(tmpl, os.Stdout, args...) } } ``` It has been as simple as this up until version 3. I.e., it's quite simple to make use of `easygen` as a package. ### Different Versions The `easygen` has gone through four different versions whose API are a bit different between them. To always stay at the latest version, `import` "github.com/go-easygen/easygen" in your Go code. However, to stay within a certain version, `import` the following package respectively to what you need: - V4: "[gopkg.in/easygen.v4](https://gopkg.in/easygen.v4)" - V3: "[gopkg.in/easygen.v3](https://gopkg.in/easygen.v3)" - V2: "[gopkg.in/easygen.v2](https://gopkg.in/easygen.v2)" - V1: "[gopkg.in/easygen.v1](https://gopkg.in/easygen.v1)" To see the differences between them, check out - [V4 vs V3](https://github.com/go-easygen/easygen/wiki/V4-vs-V3) - [V3 vs V2](https://github.com/go-easygen/easygen/wiki/V3-vs-V2) - [V2 vs V1](https://github.com/go-easygen/easygen/wiki/V2-vs-V1) ## Author(s) & Contributor(s) Tong SUN  Gerrit Renker https://github.com/grrtrr All patches welcome. easygen-4.1.0/README.md 0000664 0000000 0000000 00000023104 13502324010 0014414 0 ustar 00root root 0000000 0000000 # easygen [](LICENSE) [](http://godoc.org/github.com/go-easygen/easygen) [](https://goreportcard.com/report/github.com/go-easygen/easygen) [](https://travis-ci.org/go-easygen/easygen) [ ](https://codeship.com/projects/135255) ## TOC - [easygen - Easy to use universal code/text generator](#easygen---easy-to-use-universal-codetext-generator) - [Usage](#usage) - [$ easygen](#-easygen) - [Install](#install) - [Install as Debian/Unbuntu package](#install-as-debianunbuntu-package) - [Install from source](#install-from-source) - [Test](#test) - [Details](#details) - [Command line flag handling code auto-generation](#command-line-flag-handling-code-auto-generation) - [`easygen` itself](#`easygen`-itself) - [`cli` based](#`cli`-based) - [The `easygen` usage](#the-`easygen`-usage) - [Command line](#command-line) - [The library ](#the-library-) - [> cmd/easygen/main.go](#-cmdeasygenmaingo) - [Different Versions](#different-versions) - [Author(s) & Contributor(s)](#author(s)-&-contributor(s)) # easygen - Easy to use universal code/text generator Command `easygen` is an easy to use universal code/text generator. It can be used as a text or html generator for _arbitrary_ purposes with _arbitrary_ data and templates. It is a good [GSL](https://github.com/imatix/gsl) replacement, as it - is more easy to define driving data, in form of YML instead of XML - has more powerful template engine that based on Go template. You can also write your own function in Go to customize your template. You can even use easygen as a generic Go template testing tool using the `-ts` commandline option, and much more. Note this document is for `easygen` versions 4.0+. For historic versions check out the [Different Versions](#different-versions) section. ## Usage ### $ easygen ```sh easygen version 4.0.0 Usage: easygen [flags] template_name [data_filename [data_filename...]] Flags: -debug level debugging level -ej extension extension of json file (default ".json") -et extension extension of template file (default ".tmpl") -ey extension extension of yaml file (default ".yaml") -ts string template string (in text) data_filename(s): The name for the .yaml or .json data. - If omitted derive from the template_name. - Can have the extension or without it. If withot extension, will try .yaml first then .json - Can include the path as well. template_name: The name for the template file. - Can have the extension or without it. - Can include the path as well. - Can be a comma-separated list giving many template files, in which case at least one data_filename must be given. Flag defaults can be overridden by corresponding environment variable, e.g.: EASYGEN_EY=.yml EASYGEN_ET=.tpl easygen ... ``` ## Install ### Install as Debian/Unbuntu package apt install easygen ### Install from source go get github.com/go-easygen/easygen/... ls -l $GOPATH/bin You should find an `easygen` executable newly created in there. ## Test export PATH=$PATH:$GOPATH/bin $ easygen $GOPATH/src/github.com/go-easygen/easygen/test/list0 The colors are: red, blue, white, . cd $GOPATH/src/github.com/go-easygen/easygen $ easygen test/list1 The quoted colors are: "red", "blue", "white", . $ easygen test/listfunc1 test/list0 red, blue, white. And also check out the provided [more examples](https://godoc.org/github.com/go-easygen/easygen#pkg-examples) in the [](https://godoc.org/github.com/go-easygen/easygen) document. ## Details It can be used as a code generator, for example, command line parameter handling code generator, or anything that is structurally repetitive, like the following: - [Introduction to easygen and its philosophy ](https://suntong.github.io/blogs/2016/01/01/easygen---easy-to-use-universal-code/text-generator) - [Easygen is now coding itself ](https://sfxpt.wordpress.com/2015/07/04/easygen-is-now-coding-itself/) - [Showcasing the power of easygen with ffcvt ](https://sfxpt.wordpress.com/2015/08/02/showcasing-the-power-of-easygen-with-ffcvt/) - [Easygen for HTML mock-up ](https://sfxpt.wordpress.com/2015/07/10/easygen-for-mock-up/) - [Moving beyond code-gen and mock-up, using easygen in real life creating GPT partitions](https://suntong.github.io/blogs/2015/12/26/creating-gpt-partitions-easily-on-the-command-line) Ready to get started? Then check out [Getting Started](https://github.com/go-easygen/easygen/wiki/Getting-Started) to start building your way to turn your data into any form, any way you want. ## Command line flag handling code auto-generation [ ](https://suntong.github.io/blogs/) As explained above, one practical use of `easygen` is to auto-generating Go code for command line parameter handling, for both [`viper` and `cobra`](https://github.com/suntong/blog/blob/master/GoOptP7-easygen.md), and Go's [built-in `flag` package](https://sfxpt.wordpress.com/2015/07/04/easygen-is-now-coding-itself/). ### `easygen` itself Currently, `easygen`'s command line parameter handling is built on top of Go's built-in `flag` package, and the handling code is entirely generated by `easygen` itself. Thus, showing how `easygen` is handling the command line parameters itself also means showing what functionality the auto-generated command line parameter handling code can do for you. Currently, there are three tiers program parameters can be given: 1. Default values defined within the program, so that program parameters can have meaningful defaults to start with 1. Values defined in environment variables 1. Values passed from command line The latter will have higher priority and will override values defined formerly. I.e., the values from command line will override that in environment variables, which in turn override program defaults. We will use the `-ts`, template string, as an example to illustrate. The program defaults is empty, which means using the `.tmpl` template file the same as the `.yaml` data file. We will override that first by environment variable, then from command line, illustrated in next section. ### `cli` based See, [A cookbook on how to jump-start a `cli` based command line handling program](cli-project.md#cookbook) ## The `easygen` usage ### Command line [Check here for more on using `easygen` the command line tool](using_easygen.md). ### The library The `easygen` is a library as well as a command line tools. Not only it is super easy to use, it is super easy to extend as well. The [restructured `easygen`](https://github.com/go-easygen/easygen/issues/10) can now be a building block that people can easily extend, any extra functionalities, or extra feature that it depends on, or any external dependencies are now moved out to sub modules. Thus the library users can now pick and choose exactly what they want from the library. - The [egVar package example](http://godoc.org/github.com/go-easygen/easygen/egVar#example-package) shows how to add the variable name manipulation on top of the default library. - The [egCal package example](http://godoc.org/github.com/go-easygen/easygen/egCal#example-package) shows how to add the variable name manipulation and generic calculation functionalities, together with the default functions, all at the same time. To put them all together, check out the `easygen`'s `main.go`: #### > cmd/easygen/main.go ```go package main import ( "flag" "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egCal" "github.com/go-easygen/easygen/egVar" ) //go:generate sh -v easygen.gen.sh //////////////////////////////////////////////////////////////////////////// // Main func main() { flag.Usage = Usage flag.Parse() // One mandatory non-flag arguments if flag.NArg() < 1 { Usage() } tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()). Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs()) args := flag.Args() if len(easygen.Opts.TemplateStr) > 0 { easygen.Process0(tmpl, os.Stdout, easygen.Opts.TemplateStr, args...) } else { easygen.Process(tmpl, os.Stdout, args...) } } ``` It has been as simple as this up until version 3. I.e., it's quite simple to make use of `easygen` as a package. ### Different Versions The `easygen` has gone through four different versions whose API are a bit different between them. To always stay at the latest version, `import` "github.com/go-easygen/easygen" in your Go code. However, to stay within a certain version, `import` the following package respectively to what you need: - V4: "[gopkg.in/easygen.v4](https://gopkg.in/easygen.v4)" - V3: "[gopkg.in/easygen.v3](https://gopkg.in/easygen.v3)" - V2: "[gopkg.in/easygen.v2](https://gopkg.in/easygen.v2)" - V1: "[gopkg.in/easygen.v1](https://gopkg.in/easygen.v1)" To see the differences between them, check out - [V4 vs V3](https://github.com/go-easygen/easygen/wiki/V4-vs-V3) - [V3 vs V2](https://github.com/go-easygen/easygen/wiki/V3-vs-V2) - [V2 vs V1](https://github.com/go-easygen/easygen/wiki/V2-vs-V1) ## Author(s) & Contributor(s) Tong SUN  Gerrit Renker https://github.com/grrtrr All patches welcome. easygen-4.1.0/cli-project.md 0000664 0000000 0000000 00000040355 13502324010 0015701 0 ustar 00root root 0000000 0000000 # Jump start the cli based project This is on how to jump-start a [`cli`](https://github.com/mkideal/cli/) based project. The [`cli`](https://github.com/mkideal/cli/) package really make it easy to code your command line handling program, especially when you need to deal with _sub commands_ like `apt-get`, `git` etc do. Now, want to make it even simpler? ## Usage Yes! Use the code auto generation. It can make things even more simple. Run the following on command line so that you can see for yourself: ``` go get github.com/go-easygen/easygen ls -l $GOPATH/bin export PATH=$PATH:$GOPATH/bin easygen $GOPATH/src/github.com/go-easygen/easygen/test/commandlineCLI-024 ``` ## Result You should see the following Go code: ```go // -*- go -*- //////////////////////////////////////////////////////////////////////////// // Program: gogo // Purpose: Golang package manager //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var app = &cli.Register(&cli.Command{ Name: "gogo", Desc: "Golang package manager", Text: " gogo is a new golang package manager\n very very good", Argv: func() interface{} { return new(gogoT) }, Fn: gogo, NumArg: cli.ExactN(1), }) type gogoT struct { cli.Helper Version bool `cli:"v,version" usage:"display version"` List bool `cli:"l,list" usage:"list all sub commands or not"` } func gogo(ctx *cli.Context) error { argv := ctx.Argv().(*gogoT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[gogo]: %v\n", ctx.Args()) return nil } //////////////////////////////////////////////////////////////////////////// // Program: build // Purpose: Build golang application //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var buildCmd = app.Register(&cli.Command{ Name: "build", Desc: "Build golang application", Text: "Usage:\n gogo build [Options] Arch(i386|amd64)", Argv: func() interface{} { return new(buildT) }, Fn: build, NumArg: cli.ExactN(1), CanSubRoute: true, }) type buildT struct { cli.Helper Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } func build(ctx *cli.Context) error { argv := ctx.Argv().(*buildT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[build]: %v\n", ctx.Args()) return nil } //////////////////////////////////////////////////////////////////////////// // Program: install // Purpose: Install golang application //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var installCmd = app.Register(&cli.Command{ Name: "install", Desc: "Install golang application", Text: "Usage:\n gogo install [Options] package [package...]", Argv: func() interface{} { return new(installT) }, Fn: install, NumArg: cli.AtLeast(1), CanSubRoute: true, }) type installT struct { cli.Helper Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } func install(ctx *cli.Context) error { argv := ctx.Argv().(*installT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[install]: %v\n", ctx.Args()) return nil } //////////////////////////////////////////////////////////////////////////// // Program: publish // Purpose: Publish golang application //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var publishCmd = app.Register(&cli.Command{ Name: "publish", Desc: "Publish golang application", Argv: func() interface{} { return new(publishT) }, Fn: publish, }) type publishT struct { cli.Helper Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` List bool `cli:"l,list" usage:"list all sub commands"` } func publish(ctx *cli.Context) error { argv := ctx.Argv().(*publishT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[publish]: %v\n", ctx.Args()) return nil } ``` As you can see the skeleton of the program has been automatically generated. ## Source So what's behind the scene of the "magic"? Take a look at the driving [Yaml file](https://github.com/go-easygen/easygen/blob/master/test/commandlineCLI-024.yaml), that's everything you specify to make the magic happen. I'm republishing it below for your reference: ```yaml # program name, name for the executable ProgramName: gogo # package name # - For standalone program that does not belong to any package, e.g., # https://github.com/suntong/easygen/blob/7791e4f0e5605543d27da1671a21376cdb9dcf2a/easygen/easygen.go # just ignore the first line, the `package` output, and copy the rest # - If you don't mind using a separated file to handle commandline paramters, # then name the package as "main". see the spin-out "TF-minus1.go" file under # https://github.com/suntong/easygen/tree/d1ab0b5fe80ddac57fe9ef51f6ccb3ab998cd5ee # - If you are using it in a pacakge, look no further than # https://github.com/suntong/easygen/blob/master/easygenapi/config.go # which was a direct dump: easygen test/commandlineFlag | gofmt > easygenapi/config.go # PackageName: main Name: gogo Var: app Desc: "Golang package manager" Text: ' gogo is a new golang package manager\n very very good' NumArg: cli.ExactN(1) Options: - Name: Version Type: bool Flag: v,version Usage: display version - Name: List Type: bool Flag: l,list Usage: list all sub commands or not Command: - Name: build Desc: "Build golang application" Text: 'Usage:\n gogo build [Options] Arch(i386|amd64)' NumArg: cli.ExactN(1) Options: - Name: Dir Type: string Flag: dir Value: '"./"' Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: '".go,.c,.s"' Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: install Desc: "Install golang application" Text: 'Usage:\n gogo install [Options] package [package...]' NumArg: cli.AtLeast(1) Options: - Name: Dir Type: string Flag: dir Value: '"./"' Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: '".go,.c,.s"' Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: publish Desc: "Publish golang application" Options: - Name: Dir Type: string Flag: dir Value: '"./"' Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: '".go,.c,.s"' Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: List Type: bool Flag: l,list Usage: "list all sub commands" ``` Yes, you are right -- that's all you need to have the above code skeleton generated. ## Takeaway ### Understanding how to use easygen for cli based project Now, the question is, how it can help your own project. Assuming you have never code a `cli` based project before, what you need to do are, - Take a look at the above [Yaml file](https://github.com/go-easygen/easygen/blob/master/test/commandlineCLI-024.yaml) and see the _generated Go code_, and see their relationship. - Take a look at the [orginal finished Go code](https://github.com/mkideal/cli/tree/master/_examples/024-multi-command) that such code generation is for, and see what else you need to do to make it a working code. - The generated Go code was meant to be cut into each corresponding Go code files, e.g., the `main.go`, `build.go`, `install.go` and `publish.go` as in the above [finished code](https://github.com/mkideal/cli/tree/master/_examples/024-multi-command) - At this point, you have a good starting point already, because the code skeletons are already in place. ### Round-trip generation This is for illustration only. However, for round-trip generation, I.e., you generate and use the generated code, and you find yourself need to add more options later, then such manual cut & paste (into each corresponding Go code) method will be flimsy. So what shall we do? - Take a look at the [template file](https://github.com/go-easygen/easygen/blob/master/test/commandlineCLI.tmpl) that is being used to generate the Go code. This is where the _true_ magic happens. - I recommend removing all the repeating part, and the sample implementation part out. I.e., your own `build.go`, `install.go` and `publish.go` contains the true implementation, and use the code-gen to automatically generate all the declaration part. This way the automatically-generated code can always been overwritten (with the latest definition) without affecting your existing implementation. - For details on code automatic generation, refer to [easygen](https://github.com/go-easygen/easygen/) for all other information. ### Practical Example There is a new `commandlineCLI-027` set of data and template, that is built after [code sample 027](https://github.com/mkideal/cli/tree/master/_examples/027-global-option). Replace the above `commandlineCLI-024` with `commandlineCLI-027`, you will get [code for the corresponding samples](https://github.com/go-easygen/easygen/blob/master/test/commandlineCLI-027.ref). Further more, the `commandlineCLI-027` is built with the above *"round-trip generation"* principle in mind. Take a look at [`redoCmds.go`](https://github.com/suntong/lang/blob/master/lang/Go/src/sys/CLI/027-global-redo/redoCmds.go) in the [027-global-redo](https://github.com/suntong/lang/tree/master/lang/Go/src/sys/CLI/027-global-redo) project, it is completely generated by [easygen](https://github.com/go-easygen/easygen/), and can be regenerated as many times as you want, and whenever you want, even after several releases. ## Cookbook Since I've written the above how-to, I've followed it to generate lots of my code wire-frames, polishing and fine-tuning my approaches along the way. Now, the procedure has mostly been stabilized, so I think it is a good idea to share how I am doing it, generating my cli-based code wire-frames. All the following code-gen are based on my [cli-t0.tmpl](https://github.com/suntong/cli/blob/78b8d5e8b97d0950faec5e7844f220a572577ba0/cli-t0.tmpl) template. ### Simple case, no sub-commands Let's start with the simpler case, generating cli handling code that has no sub-commands. This is the way tradition Unix tools use, and there are many tradition *nix tools that are doing this way, e.g., `cp`, `rm`, `find`, `rsync` etc, to name a few. Here is how to generate a cli handling code-base for this case, using [my picv v0.1.0 ](https://github.com/suntong/picv/tree/0.1.0) as the example: 1. Provide a `.yaml` file -- [picv.yaml](https://github.com/suntong/picv/blob/0.1.0/picv.yaml) 1. Provide a code-gen shell script -- [picvCLIGen.sh](https://github.com/suntong/picv/blob/0.1.0/picvCLIGen.sh) and run it to generate [picvCLIDef.go](https://github.com/suntong/picv/blob/0.1.0/picvCLIDef.go) 1. Extract the commented out code to [picvMain.go](https://github.com/suntong/picv/blob/0.1.0/picvMain.go) and [picvCLICmd.go](https://github.com/suntong/picv/blob/0.1.0/picvCLICmd.go) 1. Now the code wire-frame is done, and ready for compilation and execution. ``` $ picv -h picture vault built on 2017-06-03 Tool to deal with camera pictures and put them in vault Usage: picv [Options] dir [dirs...] Options: -h, --help display help information -g, --gap[=5] Gap in days to be considered as different group/vault -p, --pod[=15] Minimum number of picture to have before splitting to a different group/vault -v, --verbose Verbose mode (Multiple -v options increase the verbosity.) $ picv {"Help":false,"Gap":5,"Pod":15,"Verbose":{}}{"Help":false,"Gap":5,"Pod":15,"Verbose":{}} ``` If you need to tweak the `.yaml` file further, just 1. Update the `.yaml` file 1. Run `go generate -x` to update the [picvCLIDef.go](https://github.com/suntong/picv/blob/0.1.0/picvCLIDef.go) file 1. And then do more editing to [picvCLICmd.go](https://github.com/suntong/picv/blob/0.1.0/picvCLICmd.go) to incorporate the new changes ### With sub-commands case The _sub commands_ are modern way of providing cli interfaces, like `apt-get`, `git` etc. As a comparison, the tradition rcs (Revision Control System) tool uses different commands for version repo management, check-in, check-out, and view logs (`rcs`, `ci`, `co`, `rlog` respectively), but `git` provides these functionalities all under the same `git` command, but different sub commands instead (`clone`/`init` etc, `commit`, `checkout`, `log`). How to generate cli handling code that has sub-commands? The procedure is exactly the same as above. I'm using [my picv v0.2.0 ](https://github.com/suntong/picv/tree/0.2.0) this time as the example: 1. Provide a `.yaml` file -- [picv.yaml](https://github.com/suntong/picv/blob/0.2.0/picv.yaml). You can see that the `.yaml` file only changes in its organization, while the content are reused nearly 100%, only that [new sub-commands are added](https://github.com/suntong/picv/blob/10daaa84d9545ffb129c4909de7019dc896fd0be/picv.yaml) and [options have been shifted around](https://github.com/suntong/picv/commit/10daaa84d9545ffb129c4909de7019dc896fd0be#diff-78301e4359962421c827625b6393ab5b). 1. Provide a code-gen shell script -- [picvCLIGen.sh](https://github.com/suntong/picv/blob/0.2.0/picvCLIGen.sh) and run it to generate [picvCLIDef.go](https://github.com/suntong/picv/blob/0.2.0/picvCLIDef.go). This step is exactly as above. 1. Extract the commented out code to [picvMain.go](https://github.com/suntong/picv/blob/0.2.0/picvMain.go), [cmdCut.go](https://github.com/suntong/picv/blob/0.2.0/cmdCut.go) and the new [cmdArch.go](https://github.com/suntong/picv/blob/0.2.0/cmdArch.go). Note that I leave the _Main dispatcher_ in `picvMain.go` in this case, because it is clearer, as each sub commands just need to deal with their own handling. 1. Now the code wire-frame is done, and ready for compilation and execution. ``` $ picv -h picture vault built on 2017-06-03 Tool to deal with camera pictures and put them in vault Options: -h, --help display help information -v, --verbose Verbose mode (Multiple -v options increase the verbosity.) Commands: cut Separate picture into groups arch Archive groups of picture into vaults $ picv cut -h Separate picture into groups Options: -h, --help display help information -v, --verbose Verbose mode (Multiple -v options increase the verbosity.) -g, --gap[=5] Gap in days to be considered as different group/vault -p, --pod[=15] Minimum number of picture to have before splitting to a different group/vault $ picv cut {"Gap":5,"Pod":15,"Verbose":0} $ picv cut -vv {"Gap":5,"Pod":15,"Verbose":2} ``` The rest are the same as above as well. ## Further abstraction Note the output of my picv [v0.1.0 ](https://github.com/suntong/picv/tree/0.1.0) and [v0.2.0 ](https://github.com/suntong/picv/tree/0.2.0) are different. This is because I've done a further abstraction step (manually, but could also be somewhat automated if you want) in [v0.1.1 ](https://github.com/suntong/picv/tree/0.1.1), which defined an option structure that is independent of the `mkideal/cli` package. I view this further abstraction a _logical_ representation of the options the tool can use, while the option structure defined in [picvCLIDef.go](https://github.com/suntong/picv/blob/master/picvCLIDef.go) is a _"physical"_ representation of the options, because its foreign-package-depending nature. This step is not absolutely necessary, but I found such practice more organized. Note [how it is masking/hiding the implementation detail that `-v` is from global option, and how easy it is to make the corresponding changes when the `-v` option changed its definition location](https://github.com/suntong/picv/commit/10daaa84d9545ffb129c4909de7019dc896fd0be#diff-e7c16ee367258e94c2fc12e8b273d921R32). easygen-4.1.0/cmd/ 0000775 0000000 0000000 00000000000 13502324010 0013700 5 ustar 00root root 0000000 0000000 easygen-4.1.0/cmd/easygen/ 0000775 0000000 0000000 00000000000 13502324010 0015333 5 ustar 00root root 0000000 0000000 easygen-4.1.0/cmd/easygen/.gitignore 0000664 0000000 0000000 00000000010 13502324010 0017312 0 ustar 00root root 0000000 0000000 easygen easygen-4.1.0/cmd/easygen/config.tmpl 0000664 0000000 0000000 00000000767 13502324010 0017510 0 ustar 00root root 0000000 0000000 // !!! !!! // WARNING: Code automatically generated. Editing discouraged. // !!! !!! package {{.PackageName}} //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions const progname = "{{.ProgramName}}" // os.Args[0] // The {{.StructName}} struct defines the structure to hold the commandline values type {{.StructName}} struct { {{range .Options}}{{if ne .Name "SEPARATOR" }} {{.Name}} {{.Type}} // {{.Usage}}{{end}}{{end}} } easygen-4.1.0/cmd/easygen/easygen.1.ronn 0000664 0000000 0000000 00000004063 13502324010 0020026 0 ustar 00root root 0000000 0000000 # easygen -- Easy to use universal code/text generator ## SYNOPSIS easygen [flags] template_name [data_filename [data_filename...]] data_filename(s): The name for the .yaml or .json data. - If omitted derive from the template_name. - Can have the extension or without it. If withot extension, will try .yaml first then .json - Can include the path as well. template_name: The name for the template file. - Can have the extension or without it. - Can include the path as well. - Can be a comma-separated list giving many template files, in which case at least one data_filename must be given. ## DESCRIPTION Command `easygen` is an easy to use universal code/text generator. It can be used as a text or html generator for _arbitrary_ purposes with _arbitrary_ data and templates. It is a good GSL replacement, as it - is more easy to define driving data, in form of YML instead of XML - has more powerful template engine that based on Go template. You can even write your own function in Go to customize your template. You can even use easygen as a generic Go template testing tool using the `-ts` commandline option, and much more. ## Usage It's very easy to use -- just type `easygen` and following the inline help. Or try the following example to get started: export PATH=$PATH:$GOPATH/bin $ easygen $GOPATH/src/github.com/go-easygen/easygen/test/list0 The colors are: red, blue, white, . cd $GOPATH/src/github.com/go-easygen/easygen $ easygen test/list1 The quoted colors are: "red", "blue", "white", . $ easygen -tf test/listfunc1 test/list0 red, blue, white. ## EXAMPLES `easygen` comes with comprehensive online documents. For further details, please go to: https://github.com/go-easygen/easygen https://suntong.github.io/blogs/2016/01/01/easygen---easy-to-use-universal-code/text-generator https://github.com/go-easygen/easygen/blob/master/using_easygen.md https://github.com/go-easygen/easygen/wiki/Getting-Started https://godoc.org/github.com/go-easygen/easygen#pkg-examples easygen-4.1.0/cmd/easygen/easygen.gen.sh 0000775 0000000 0000000 00000000205 13502324010 0020072 0 ustar 00root root 0000000 0000000 easygen config easygen | gofmt > ../../config.go easygen flags easygen | sed 's/^package easygen/package main/' | gofmt > flags.go easygen-4.1.0/cmd/easygen/easygen.yaml 0000664 0000000 0000000 00000004427 13502324010 0017661 0 ustar 00root root 0000000 0000000 # program name, name for the executable ProgramName: easygen # package name # - For standalone program that does not belong to any package, e.g., # https://github.com/suntong/easygen/blob/7791e4f0e5605543d27da1671a21376cdb9dcf2a/easygen/easygen.go # just ignore the first line, the `package` output, and copy the rest # - If you don't mind using a separated file to handle commandline paramters, # then name the package as "main". see the spin-out "TF-minus1.go" file under # https://github.com/suntong/easygen/tree/d1ab0b5fe80ddac57fe9ef51f6ccb3ab998cd5ee # - If you are using it in a pacakge, look no further than # https://github.com/suntong/easygen/blob/master/easygenapi/config.go # which was a direct dump: easygen test/commandlineFlag | gofmt > easygenapi/config.go # PackageName: easygen # Name of the structure to hold the values for/from commandline StructName: Options # The actual variable that hold the commandline paramter values StructVar: Opts Options: - Name: TemplateStr Type: string Flag: ts Value: '""' Usage: "template string (in text)" - Name: ExtYaml Type: string Flag: ey Value: '".yaml"' Usage: "`extension` of yaml file" - Name: ExtJson Type: string Flag: ej Value: '".json"' Usage: "`extension` of json file" - Name: ExtTmpl Type: string Flag: et Value: '".tmpl"' Usage: "`extension` of template file" - Name: Debug Type: int Flag: debug Value: 0 Usage: "debugging `level`" # Whether to use the USAGE_SUMMARY in Usage help UsageSummary: "" UsageLead: "\\nUsage:\\n %s [flags] template_name [data_filename [data_filename...]]\\n\\nFlags:\\n\\n" UsageEnd: "\\ndata_filename(s): The name for the .yaml or .json data.\\n - If omitted derive from the template_name.\\n - Can have the extension or without it. If withot extension,\\n will try .yaml first then .json\\n - Can include the path as well.\\n\\ntemplate_name: The name for the template file.\\n - Can have the extension or without it.\\n - Can include the path as well.\\n - Can be a comma-separated list giving many template files, in which case\\n at least one data_filename must be given.\\n\\nFlag defaults can be overridden by corresponding environment variable, e.g.:\\n EASYGEN_EY=.yml EASYGEN_ET=.tpl easygen ...\\n" easygen-4.1.0/cmd/easygen/flags.go 0000664 0000000 0000000 00000004731 13502324010 0016763 0 ustar 00root root 0000000 0000000 // !!! !!! // WARNING: Code automatically generated. Editing discouraged. // !!! !!! package main import ( "flag" "fmt" "os" "github.com/go-easygen/easygen" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions //const progname = "easygen" // os.Args[0] //////////////////////////////////////////////////////////////////////////// // Global variables definitions //////////////////////////////////////////////////////////////////////////// // Commandline definitions func init() { // set default values for command line parameters flag.StringVar(&easygen.Opts.TemplateStr, "ts", "", "template string (in text)") flag.StringVar(&easygen.Opts.ExtYaml, "ey", ".yaml", "`extension` of yaml file") flag.StringVar(&easygen.Opts.ExtJson, "ej", ".json", "`extension` of json file") flag.StringVar(&easygen.Opts.ExtTmpl, "et", ".tmpl", "`extension` of template file") flag.IntVar(&easygen.Opts.Debug, "debug", 0, "debugging `level`") // Now override those default values from environment variables if len(easygen.Opts.TemplateStr) == 0 || len(os.Getenv("EASYGEN_TS")) != 0 { easygen.Opts.TemplateStr = os.Getenv("EASYGEN_TS") } if len(easygen.Opts.ExtYaml) == 0 || len(os.Getenv("EASYGEN_EY")) != 0 { easygen.Opts.ExtYaml = os.Getenv("EASYGEN_EY") } if len(easygen.Opts.ExtJson) == 0 || len(os.Getenv("EASYGEN_EJ")) != 0 { easygen.Opts.ExtJson = os.Getenv("EASYGEN_EJ") } if len(easygen.Opts.ExtTmpl) == 0 || len(os.Getenv("EASYGEN_ET")) != 0 { easygen.Opts.ExtTmpl = os.Getenv("EASYGEN_ET") } } // Usage function shows help on commandline usage func Usage() { fmt.Fprintf(os.Stderr, "%s version %s\n\nUsage:\n %s [flags] template_name [data_filename [data_filename...]]\n\nFlags:\n\n", progname, version, progname) flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\ndata_filename(s): The name for the .yaml or .json data.\n - If omitted derive from the template_name.\n - Can have the extension or without it. If withot extension,\n will try .yaml first then .json\n - Can include the path as well.\n\ntemplate_name: The name for the template file.\n - Can have the extension or without it.\n - Can include the path as well.\n - Can be a comma-separated list giving many template files, in which case\n at least one data_filename must be given.\n\nFlag defaults can be overridden by corresponding environment variable, e.g.:\n EASYGEN_EY=.yml EASYGEN_ET=.tpl easygen ...\n") os.Exit(0) } easygen-4.1.0/cmd/easygen/flags.tmpl 0000664 0000000 0000000 00000003362 13502324010 0017331 0 ustar 00root root 0000000 0000000 // !!! !!! // WARNING: Code automatically generated. Editing discouraged. // !!! !!! package {{.PackageName}} import ( "flag" "fmt" "os" "github.com/go-easygen/easygen" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions //const progname = "{{.ProgramName}}" // os.Args[0] //////////////////////////////////////////////////////////////////////////// // Global variables definitions //////////////////////////////////////////////////////////////////////////// // Commandline definitions func init() { // set default values for command line parameters{{range .Options}}{{if eq .Name "SEPARATOR" }} {{else}} flag.{{clk2uc .Type}}Var(&easygen.{{$.StructVar}}.{{.Name}}, "{{.Flag}}", {{.Value}}, "{{.Usage}}"){{end}}{{end}} // Now override those default values from environment variables{{range .Options}}{{if eq .Name "SEPARATOR" }} {{else}}{{if eq .Type "string" }}{{$envVar := printf "%s_%s" (clk2ss $.ProgramName) (clk2ss .Flag)}} if len(easygen.{{$.StructVar}}.{{.Name}}) == 0 || len(os.Getenv("{{$envVar}}")) != 0 { easygen.{{$.StructVar}}.{{.Name}} = os.Getenv("{{$envVar}}") }{{end}}{{end}}{{end}} } {{if eqf .UsageSummary "True" }} const USAGE_SUMMARY = "{{range .Options}}{{if eq .Name "SEPARATOR" }}\n{{else}}{{$envVar := printf "%s_%s" (clk2ss $.ProgramName) (clk2ss .Flag)}} -{{.Flag}}\t{{.Usage}} ({{$envVar}})\n{{end}}{{end}}\nDetails:\n\n" {{end}} // Usage function shows help on commandline usage func Usage() { fmt.Fprintf(os.Stderr, "%s version %s\n{{.UsageLead}}", progname, version, progname){{if eq .UsageSummary "TRUE" }} fmt.Fprintf(os.Stderr, USAGE_SUMMARY){{end}} flag.PrintDefaults() fmt.Fprintf(os.Stderr, "{{.UsageEnd}}") os.Exit(0) } easygen-4.1.0/cmd/easygen/main.go 0000664 0000000 0000000 00000004464 13502324010 0016616 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////////// // Porgram: easygen // Purpose: Easy to use universal code/text generator // Authors: Tong Sun (c) 2015-2019, All rights reserved //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // Program start /* Command easygen is an easy to use universal code/text generator. It can be used as a text or html generator for arbitrary purposes with arbitrary data and templates. It can be used as a code generator, or anything that is structurally repetitive. Some command line parameter handling code generator are provided as examples, including the Go's built-in flag package, and the viper & cobra package. You can even use easygen as a generic Go template testing tool using the -ts commandline option. */ package main import ( "flag" "os" "strings" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egCal" "github.com/go-easygen/easygen/egFilePath" "github.com/go-easygen/easygen/egVar" ) //go:generate sh -v easygen.gen.sh //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions //////////////////////////////////////////////////////////////////////////// // Global variables definitions var ( progname = "easygen" version = "4.1.0" date = "2019-06-18" ) //////////////////////////////////////////////////////////////////////////// // Main func main() { flag.Usage = Usage flag.Parse() // One mandatory non-flag arguments if flag.NArg() < 1 { Usage() } args := flag.Args() // There is only one command line argument if len(args) == 1 { // when template_name is comma-separated list, data_filename must be given if strings.Contains(args[0], ",") { Usage() } // else, dup template_name as data_filename args = append(args, args[0]) } tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()). Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs()).Funcs(egFilePath.FuncDefs()) var err error if len(easygen.Opts.TemplateStr) > 0 { err = easygen.Process0(tmpl, os.Stdout, easygen.Opts.TemplateStr, args...) } else { err = easygen.Process2(tmpl, os.Stdout, args[0], args[1:]...) } if err != nil { panic(err) } } easygen-4.1.0/cmd/easygen/main_test.go 0000664 0000000 0000000 00000006207 13502324010 0017652 0 ustar 00root root 0000000 0000000 package main_test import ( "bytes" "os" "os/exec" "strings" "testing" ) const ( cmdEasygen = "easygen" dirTest = "../../test/" extRef = ".ref" // extension for reference file extGot = ".got" // extension for generated file ) // testEasygen runs @cmdEasyGen with @argv and compares the generated // output for @name with the corresponding @extRef func testEasygen(t *testing.T, name string, argv ...string) { var ( diffOut bytes.Buffer generatedOutput = name + extGot cmd = exec.Command(cmdEasygen, argv...) ) t.Logf("Testing %s:\n\t%s %s", name, cmdEasygen, strings.Join(argv, " ")) // open the out file for writing outfile, err := os.Create(generatedOutput) if err != nil { t.Errorf("write error [%s: %s] %s.", name, argv, err) } defer outfile.Close() cmd.Stdout = outfile err = cmd.Start() if err != nil { t.Errorf("start error [%s: %s] %s.", name, argv, err) } err = cmd.Wait() if err != nil { t.Errorf("exit error [%s: %s] %s.", name, argv, err) } cmd = exec.Command("diff", "-U1", name+extRef, generatedOutput) cmd.Stdout = &diffOut err = cmd.Start() if err != nil { t.Errorf("start error %s [%s: %s]", err, name, argv) } err = cmd.Wait() if err != nil { t.Errorf("cmp error %s [%s: %s]\n%s", err, name, argv, diffOut.String()) } os.Remove(generatedOutput) } func TestExec(t *testing.T) { os.Chdir(dirTest) //Test Basic Functions testEasygen(t, "list0", "list0") // Filename suffixes are optional testEasygen(t, "list0", "list0.yaml") testEasygen(t, "list0", "list0", "list0") testEasygen(t, "list0", "list0.tmpl", "list0") testEasygen(t, "list0", "list0.tmpl", "list0.yaml") testEasygen(t, "list0E", "list0E", "list0") testEasygen(t, "list1", "list1") testEasygen(t, "listfunc1", "listfunc1") testEasygen(t, "listfunc2", "listfunc2") //Test Basic Json Functions testEasygen(t, "list0j", "list0j") testEasygen(t, "list0j", "list0j", "list0j") testEasygen(t, "list0j", "list0j", "list0j.json") // template_name can be a comma-separated list testEasygen(t, "list01", "list0,listfunc1", "list0") //Test HTML testEasygen(t, "list1HTML", "list1HTML", "list1") // varcaser string functions testEasygen(t, "var0", "-ts", "{{.Name}}", "var0") testEasygen(t, "var1", "-ts", "{{clk2uc .Name}}", "var0") testEasygen(t, "var2", "-ts", "{{clk2ss .Name}}", "var0") //Test Bigger files testEasygen(t, "commandlineCLI-024", "commandlineCLI-024") testEasygen(t, "commandlineCLI-027", "commandlineCLI-027") testEasygen(t, "commandlineCLI-027s", "commandlineCLI-027", "commandlineCLI-027s") testEasygen(t, "commandlineCVFull", "commandlineCVFull") testEasygen(t, "commandlineCV", "commandlineCV") testEasygen(t, "commandlineFlag", "commandlineFlag") // Enum generation: (a) run template with multiple data inputs, // (b) run the same input with multiple template files: testEasygen(t, "enum_multiple_data_files", "enum_c-header", "raid_type", "raid_driver") testEasygen(t, "enum_multiple_template_files", "enum_c-header,enum_c-source", "raid_type.yaml") testEasygen(t, "enum_multiple_template_and_data", "enum_c-header,enum_c-to_str", "raid_type", "raid_driver.yaml") } easygen-4.1.0/config.go 0000664 0000000 0000000 00000001140 13502324010 0014725 0 ustar 00root root 0000000 0000000 // !!! !!! // WARNING: Code automatically generated. Editing discouraged. // !!! !!! package easygen //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions const progname = "easygen" // os.Args[0] // The Options struct defines the structure to hold the commandline values type Options struct { TemplateStr string // template string (in text) ExtYaml string // `extension` of yaml file ExtJson string // `extension` of json file ExtTmpl string // `extension` of template file Debug int // debugging `level` } easygen-4.1.0/easygen.go 0000664 0000000 0000000 00000015670 13502324010 0015130 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////////// // Package: easygen // Purpose: Easy to use universal code/text generator // Authors: Tong Sun (c) 2015-2019, All rights reserved //////////////////////////////////////////////////////////////////////////// /* Package easygen is an easy to use universal code/text generator library. It can be used as a text or html generator for arbitrary purposes with arbitrary data and templates. It can be used as a code generator, or anything that is structurally repetitive. Some command line parameter handling code generator are provided as examples, including the Go's built-in flag package, and the viper & cobra package. Many examples have been provided to showcase its functionality, and different ways to use it. */ package easygen import ( "encoding/json" "fmt" "io" "io/ioutil" "os" "path/filepath" "regexp" "strings" "gopkg.in/yaml.v2" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions //////////////////////////////////////////////////////////////////////////// // Global variables definitions // EgData -- EasyGen driven Data type EgData interface{} // Opts holds the actual values from the command line parameters var Opts = Options{ExtYaml: ".yaml", ExtJson: ".json", ExtTmpl: ".tmpl"} //////////////////////////////////////////////////////////////////////////// // Function definitions // ReadDataFile reads in the driving data from the given file, which can // be optionally without the defined extension func ReadDataFile(fileName string) EgData { if IsExist(fileName + Opts.ExtYaml) { return ReadYamlFile(fileName + Opts.ExtYaml) } else if IsExist(fileName + Opts.ExtJson) { return ReadJsonFile(fileName + Opts.ExtJson) } else if IsExist(fileName) { verbose("Reading exist Data File", 2) fext := filepath.Ext(fileName) fext = fext[1:] // ignore the leading "." if regexp.MustCompile(`(?i)^y`).MatchString(fext) { verbose("Reading YAML file", 2) return ReadYamlFile(fileName) } else if regexp.MustCompile(`(?i)^j`).MatchString(fext) { return ReadJsonFile(fileName) } else { checkError(fmt.Errorf("Unsupported file extension for DataFile '%s'", fileName)) } } checkError(fmt.Errorf("DataFile '%s' cannot be found", fileName)) return nil } // ReadYamlFile reads given YAML file as EgData func ReadYamlFile(fileName string) EgData { source, err := ioutil.ReadFile(fileName) checkError(err) m := make(map[interface{}]interface{}) err = yaml.Unmarshal(source, &m) checkError(err) return m } // ReadJsonFile reads given JSON file as EgData func ReadJsonFile(fileName string) EgData { source, err := ioutil.ReadFile(fileName) checkError(err) m := make(map[string]interface{}) err = json.Unmarshal(source, &m) checkError(err) return m } // IsExist checks if the given file exist func IsExist(fileName string) bool { //fmt.Printf("] Checking %s\n", fileName) _, err := os.Stat(fileName) return err == nil || os.IsExist(err) // CAUTION! os.IsExist(err) != !os.IsNotExist(err) // https://gist.github.com/mastef/05f46d3ab2f5ed6a6787#file-isexist_vs_isnotexist-go-L35-L56 } // Process will process the standard easygen input: the `fileName` is for both template and data file name, and produce output from the template according to the corresponding driving data. // Process() is using the V3's calling convention and *only* works properly in V4+ in the case that there is only one fileName passed to it. If need to pass more files, use Process2() instead. func Process(t Template, wr io.Writer, fileNames ...string) error { return Process2(t, wr, fileNames[0], fileNames[:1]...) } // Process2 will process the case that *both* template and data file names are given, and produce output according to the given template and driving data files, // specified via fileNameTempl and fileNames respectively. // fileNameTempl can be a comma-separated string giving many template files func Process2(t Template, wr io.Writer, fileNameTempl string, fileNames ...string) error { for _, dataFn := range fileNames { for _, templateFn := range strings.Split(fileNameTempl, ",") { err := Process1(t, wr, templateFn, dataFn) checkError(err) } } return nil } // Process1 will process a *single* case where both template and data file names are given, and produce output according to the given template and driving data files, // specified via fileNameTempl and fileName respectively. // fileNameTempl is not a comma-separated string, but for a single template file. func Process1(t Template, wr io.Writer, fileNameTempl string, fileName string) error { m := ReadDataFile(fileName) //fmt.Printf("] %+v\n", m) // template file fileName = fileNameTempl fileNameT := fileNameTempl if IsExist(fileName + Opts.ExtTmpl) { fileNameT = fileName + Opts.ExtTmpl } else { // guard against that fileNameTempl passed with Opts.ExtYaml extension if fileName[len(fileName)-len(Opts.ExtYaml):] == Opts.ExtYaml { idx := strings.LastIndex(fileName, ".") fileName = fileName[:idx] if IsExist(fileName + Opts.ExtTmpl) { fileNameT = fileName + Opts.ExtTmpl } } else if IsExist(fileName) { // fileNameTempl passed with Opts.ExtTmpl already fileNameT = fileName } } return Execute(t, wr, fileNameT, m) } // Execute will execute the Template on the given data map `m`. func Execute(t Template, wr io.Writer, fileNameT string, m EgData) error { // 1. Check locally verbose("Checking for template locally: "+fileNameT, 1) if !IsExist(fileNameT) { // 2. Check under /etc/ command := filepath.Base(os.Args[0]) templateFile := fmt.Sprintf("/etc/%s/%s", command, fileNameT) verbose("Checking at "+templateFile, 1) if IsExist(templateFile) { fileNameT = templateFile } else { // 3. Check where executable is ex, e := os.Executable() if e != nil { return e } fileNameT = filepath.Dir(ex) + string(filepath.Separator) + fileNameT verbose("Checking at "+fileNameT, 1) if !IsExist(fileNameT) { checkError(fmt.Errorf("Template file '%s' cannot be found", fileNameT)) } } } tn, err := t.ParseFiles(fileNameT) checkError(err) return tn.ExecuteTemplate(wr, filepath.Base(fileNameT), m) } // Process0 will produce output according to the driving data *without* a template file, using the string from strTempl as the template func Process0(t Template, wr io.Writer, strTempl string, fileNames ...string) error { fileName := fileNames[0] m := ReadDataFile(fileName) tmpl, err := t.Parse(strTempl) checkError(err) return tmpl.Execute(wr, m) } //////////////////////////////////////////////////////////////////////////// // Support Function definitions // Exit if error occurs func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr, "[%s] Fatal error - %s\n", progname, err) os.Exit(1) } } // verbose will print info to stderr according to the verbose level setting func verbose(step string, level int) { if Opts.Debug >= level { print("[", progname, "] ", step, "\n") } } easygen-4.1.0/easygen_test.go 0000664 0000000 0000000 00000004241 13502324010 0016157 0 ustar 00root root 0000000 0000000 package easygen_test import ( "os" "text/template" "github.com/go-easygen/easygen" ) var tmpl *template.Template func init() { tmpl = easygen.NewTemplate().Funcs(easygen.FuncDefs()) } //////////////////////////////////////////////////////////////////////////// // Lists //========================================================================== // list0 data + string template // I.e.: EasyGen -ts "{{range .Colors}}{{.}}, {{end}}" test/list0 // Test string template with list0 data func ExampleProcess0_list0StrTemplate() { // Equivalent testing on commandline: // easygen -ts '{{range .Colors}}{{.}}, {{end}}' test/list0 easygen.Process0(tmpl, os.Stdout, "{{range .Colors}}{{.}}, {{end}}", "test/list0") // Output: // red, blue, white, } // Test HTML template with list1 data func ExampleProcess2_html() { // Equivalent testing on commandline: // easygen -tf test/list1HTML test/list1 easygen.Process2(tmpl, os.Stdout, "test/list1HTML", "test/list1") // Output: // The quoted colors are: "red", "blue", "white", . } //////////////////////////////////////////////////////////////////////////// // Strings Test // Test string comparison in template func ExampleProcess0_stringsCmp() { // Equivalent testing on commandline: // easygen -ts '{{The {{if ... {{end}}.' test/strings0 easygen.Process0(tmpl, os.Stdout, `The {{if eq .StrTest "-AB-axxb- HTML Html html"}}eq says Yea{{else}}eq says Nay{{end}} but {{if eqf .StrTest "-AB-axxb- HTML Html html"}}eqf says Yea{{else}}eqf says Nay{{end}}.`, "test/strings0") // Output: // The eq says Nay but eqf says Yea. } // Test the string split function in template func ExampleProcess0_split0() { // Equivalent testing on commandline: // easygen -ts '{{split .Colorlist}}' test/list0 easygen.Process0(tmpl, os.Stdout, `{{split .Colorlist}}`, "test/list0") // Output: // [red blue white] } // Test the string split function in template again func ExampleProcess0_split1() { // Equivalent testing on commandline: // easygen -ts '{{range ... {{end}}' test/list0 easygen.Process0(tmpl, os.Stdout, `{{range (split .Colorlist)}}{{.}} {{end}}`, "test/list0") // Output: // red blue white } easygen-4.1.0/egCal/ 0000775 0000000 0000000 00000000000 13502324010 0014150 5 ustar 00root root 0000000 0000000 easygen-4.1.0/egCal/EgCal.go 0000664 0000000 0000000 00000002203 13502324010 0015447 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////////// // Package: egCal // Purpose: easygen generic calculation functionalities // Authors: Tong Sun (c) 2017, All rights reserved //////////////////////////////////////////////////////////////////////////// /* Package egCal provides generic calculation functionalities. egCal provides the generic calculation functionalities from consul template functions https://github.com/hashicorp/consul-template / template_functions.go */ package egCal import ( "text/template" "github.com/go-easygen/easygen" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions // EgCal -- EasyGen Calculation type EgCal struct { *easygen.EgBase } var egFuncMap = easygen.FuncMap{ "add": add, "subtract": subtract, "multiply": multiply, "divide": divide, } //////////////////////////////////////////////////////////////////////////// // Function definitions // FuncDefs returns the custom definition mapping for this specific package. func FuncDefs() template.FuncMap { return template.FuncMap(egFuncMap) } easygen-4.1.0/egCal/LICENSE 0000664 0000000 0000000 00000037147 13502324010 0015171 0 ustar 00root root 0000000 0000000 Mozilla Public License, version 2.0 1. Definitions 1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution. 1.3. “Contribution” means Covered Software of a particular Contributor. 1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. “Incompatible With Secondary Licenses” means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. “Executable Form” means any form of the work other than Source Code Form. 1.7. “Larger Work” means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. “License” means this document. 1.9. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. “Modifications” means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. “Patent Claims” of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. “Source Code Form” means the form of the work preferred for making modifications. 1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - “Incompatible With Secondary Licenses” Notice This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. easygen-4.1.0/egCal/consul-template_functions.go 0000664 0000000 0000000 00000016503 13502324010 0021710 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////////// // Package: egCal // Purpose: easygen generic calculation functionalities // Authors: @HashiCorp (c) 2013-17, All rights reserved // https://github.com/hashicorp/consul-template/blob/de2ebf4/template_functions.go#L727-L901 //////////////////////////////////////////////////////////////////////////// package egCal import ( "fmt" "reflect" ) // add returns the sum of a and b. func add(a, b interface{}) (interface{}, error) { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) switch av.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Int() + bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Int() + int64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return float64(av.Int()) + bv.Float(), nil default: return nil, fmt.Errorf("add: unknown type for %q (%T)", bv, b) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return int64(av.Uint()) + bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Uint() + bv.Uint(), nil case reflect.Float32, reflect.Float64: return float64(av.Uint()) + bv.Float(), nil default: return nil, fmt.Errorf("add: unknown type for %q (%T)", bv, b) } case reflect.Float32, reflect.Float64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Float() + float64(bv.Int()), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Float() + float64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return av.Float() + bv.Float(), nil default: return nil, fmt.Errorf("add: unknown type for %q (%T)", bv, b) } default: return nil, fmt.Errorf("add: unknown type for %q (%T)", av, a) } } // subtract returns the difference of b from a. func subtract(a, b interface{}) (interface{}, error) { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) switch av.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Int() - bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Int() - int64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return float64(av.Int()) - bv.Float(), nil default: return nil, fmt.Errorf("subtract: unknown type for %q (%T)", bv, b) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return int64(av.Uint()) - bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Uint() - bv.Uint(), nil case reflect.Float32, reflect.Float64: return float64(av.Uint()) - bv.Float(), nil default: return nil, fmt.Errorf("subtract: unknown type for %q (%T)", bv, b) } case reflect.Float32, reflect.Float64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Float() - float64(bv.Int()), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Float() - float64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return av.Float() - bv.Float(), nil default: return nil, fmt.Errorf("subtract: unknown type for %q (%T)", bv, b) } default: return nil, fmt.Errorf("subtract: unknown type for %q (%T)", av, a) } } // multiply returns the product of a and b. func multiply(a, b interface{}) (interface{}, error) { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) switch av.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Int() * bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Int() * int64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return float64(av.Int()) * bv.Float(), nil default: return nil, fmt.Errorf("multiply: unknown type for %q (%T)", bv, b) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return int64(av.Uint()) * bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Uint() * bv.Uint(), nil case reflect.Float32, reflect.Float64: return float64(av.Uint()) * bv.Float(), nil default: return nil, fmt.Errorf("multiply: unknown type for %q (%T)", bv, b) } case reflect.Float32, reflect.Float64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Float() * float64(bv.Int()), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Float() * float64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return av.Float() * bv.Float(), nil default: return nil, fmt.Errorf("multiply: unknown type for %q (%T)", bv, b) } default: return nil, fmt.Errorf("multiply: unknown type for %q (%T)", av, a) } } // divide returns the division of b from a. func divide(a, b interface{}) (interface{}, error) { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) switch av.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Int() / bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Int() / int64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return float64(av.Int()) / bv.Float(), nil default: return nil, fmt.Errorf("divide: unknown type for %q (%T)", bv, b) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return int64(av.Uint()) / bv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Uint() / bv.Uint(), nil case reflect.Float32, reflect.Float64: return float64(av.Uint()) / bv.Float(), nil default: return nil, fmt.Errorf("divide: unknown type for %q (%T)", bv, b) } case reflect.Float32, reflect.Float64: switch bv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return av.Float() / float64(bv.Int()), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return av.Float() / float64(bv.Uint()), nil case reflect.Float32, reflect.Float64: return av.Float() / bv.Float(), nil default: return nil, fmt.Errorf("divide: unknown type for %q (%T)", bv, b) } default: return nil, fmt.Errorf("divide: unknown type for %q (%T)", av, a) } } easygen-4.1.0/egCal/example_test.go 0000664 0000000 0000000 00000001321 13502324010 0017166 0 ustar 00root root 0000000 0000000 package egCal_test import ( "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egCal" "github.com/go-easygen/easygen/egVar" ) // for standalone test, change package to `main` and the next func def to, // func main() { func Example() { tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs()) easygen.Process0(tmpl, os.Stdout, "{{.Name}}: {{clk2uc .Name}} {{clk2ss .Name}}\n"+ "Cal: {{add 2 3}}, {{multiply 2 3}}, {{subtract 9 2}}, {{divide 24 3}}\n", "../test/var0") // Output: // some-init-method: SomeInitMethod SOME_INIT_METHOD // Cal: 5, 6, 7, 8 } // To show the full code in GoDoc type dummy struct { } easygen-4.1.0/egFilePath/ 0000775 0000000 0000000 00000000000 13502324010 0015145 5 ustar 00root root 0000000 0000000 easygen-4.1.0/egFilePath/EgFilePath.go 0000664 0000000 0000000 00000003736 13502324010 0017455 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////////// // Package: egFilePath // Purpose: EasyGen Generic FilePath Functionalities // Authors: Tong Sun (c) 2019, All rights reserved //////////////////////////////////////////////////////////////////////////// /* Package egFilePath provides filepath manupilation functionalities. egFilePath provides filepath manupilation manipulation, provided by "path/filepath". */ package egFilePath import ( "os" "path/filepath" "strings" "text/template" "github.com/go-easygen/easygen" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions // EgFilePath -- EasyGen FilePath manupilation functionalities type EgFilePath struct { *easygen.EgBase } var egFuncMap = easygen.FuncMap{ //"fpAbs": filepath.Abs, "fpBase": filepath.Base, "fpClean": filepath.Clean, "fpDir": filepath.Dir, //"fpEvalSymlinks": filepath.EvalSymlinks, "fpExt": filepath.Ext, "fpFromSlash": filepath.FromSlash, //"fpGlob": filepath.Glob, "fpHasPrefix": filepath.HasPrefix, "fpIsAbs": filepath.IsAbs, "fpJoin": filepath.Join, //"fpMatch": filepath.Match, "fpRel": filepath.Rel, //"fpSplit": filepath.Split, //"fpSplitList": filepath.SplitList, "fpToSlash": filepath.ToSlash, "fpVolumeName": filepath.VolumeName, "isDir": IsDir, "basename": Basename, } //////////////////////////////////////////////////////////////////////////// // Function definitions // FuncDefs returns the custom definition mapping for this specific package. func FuncDefs() template.FuncMap { return template.FuncMap(egFuncMap) } //========================================================================== // support functions func IsDir(path string) bool { info, _ := os.Stat(path) return info.IsDir() } func Basename(s string) string { s = filepath.Base(s) n := strings.LastIndexByte(s, '.') if n > 0 { return s[:n] } return s } easygen-4.1.0/egFilePath/example_test.go 0000664 0000000 0000000 00000002513 13502324010 0020167 0 ustar 00root root 0000000 0000000 package egFilePath_test import ( "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egFilePath" ) // for standalone test, change package to `main` and the next func def to, // func main() { func Example() { tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egFilePath.FuncDefs()) easygen.Process0(tmpl, os.Stdout, // "Rel: {{fpRel `/a/b/c`}}, {{fpRel `/b/c`}}, {{fpRel `./b/c`}}\n", "Base: {{fpBase `/a/b.c`}}, {{fpBase `/b.c/`}}, {{fpBase `./b.c`}}, {{fpBase `b.c`}}\n"+ "Clean: {{fpClean `/a//b.c/./..`}}, {{fpClean `//b.c///`}}, {{fpClean `/../b.c`}}\n"+ "Dir: {{fpDir `/a/b/c`}}, {{fpDir `/b/c/`}}, {{fpDir `./b/c`}}, {{fpDir `b.c`}}\n"+ "Ext: {{fpExt `index`}}, {{fpExt `index.js`}}, {{fpExt `main.test.js`}}\n"+ "Join: {{fpJoin `/a` `b` `c` `a//` `//b////c`}}, {{fpJoin `a` `b/c`}}, {{fpJoin `a/b` `c`}}\n"+ // "IsDir: {{isDir `.`}}, {{isDir `not-exist`}}.\n"+ "IsDir: {{isDir `.`}}.\n"+ "Basename: {{basename `/a/b.c`}}, {{basename `/b.c/`}}, {{basename `b.c`}}, {{basename `bc`}}", "../test/var0") // Output: // Base: b.c, b.c, b.c, b.c // Clean: /a, /b.c, /b.c // Dir: /a/b, /b/c, b, . // Ext: , .js, .js // Join: /a/b/c/a/b/c, a/b/c, a/b/c // IsDir: true. // Basename: b, b, b, bc } // To show the full code in GoDoc type dummy struct { } easygen-4.1.0/egVar/ 0000775 0000000 0000000 00000000000 13502324010 0014201 5 ustar 00root root 0000000 0000000 easygen-4.1.0/egVar/EgVar.go 0000664 0000000 0000000 00000010371 13502324010 0015536 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////////// // Package: egVar // Purpose: easygen variable naming functionalities // Authors: Tong Sun (c) 2016-17, All rights reserved //////////////////////////////////////////////////////////////////////////// /* Package egVar provides variable naming functionalities. egVar provides variable naming manipulation, available from danverbraganza/varcaser. */ package egVar import ( "text/template" "github.com/danverbraganza/varcaser/varcaser" "github.com/go-easygen/easygen" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions // EgVar -- EasyGen variable naming // // pre-configed varcaser caser converters // the names are self-explanatory from their definitions // https://github.com/danverbraganza/varcaser/ /* ls - LowerSnakeCase: lower_snake_case ss - ScreamingSnakeCase: SCREAMING_SNAKE_CASE lk - KebabCase: kebab-case ScreamingKebabCase: SCREAMING-KEBAB-CASE hh - HttpHeaderCase: HTTP-Header-Case UpperCamelCase: UpperCamelCase (renders HTTP as Http) LowerCamelCase: lowerCamelCase (renders HTTP as Http) uc - UpperCamelCaseKeepCaps: UpperCamelCaseKeepCaps (renders HTTP as HTTP) lc - LowerCamelCaseKeepCaps: lowerCamelCaseKeepCaps (renders HTTP as hTTP) */ type EgVar struct { *easygen.EgBase } var ( cls2lc = varcaser.Caser{ From: varcaser.LowerSnakeCase, To: varcaser.LowerCamelCaseKeepCaps} cls2uc = varcaser.Caser{ From: varcaser.LowerSnakeCase, To: varcaser.UpperCamelCaseKeepCaps} cls2ss = varcaser.Caser{ From: varcaser.LowerSnakeCase, To: varcaser.ScreamingSnakeCase} cls2lk = varcaser.Caser{ From: varcaser.LowerSnakeCase, To: varcaser.KebabCase} cls2hh = varcaser.Caser{ From: varcaser.LowerSnakeCase, To: varcaser.HttpHeaderCase} css2lc = varcaser.Caser{ From: varcaser.ScreamingSnakeCase, To: varcaser.LowerCamelCaseKeepCaps} css2uc = varcaser.Caser{ From: varcaser.ScreamingSnakeCase, To: varcaser.UpperCamelCaseKeepCaps} css2ls = varcaser.Caser{ From: varcaser.ScreamingSnakeCase, To: varcaser.LowerSnakeCase} css2lk = varcaser.Caser{ From: varcaser.ScreamingSnakeCase, To: varcaser.KebabCase} css2hh = varcaser.Caser{ From: varcaser.ScreamingSnakeCase, To: varcaser.HttpHeaderCase} clk2lc = varcaser.Caser{From: varcaser.KebabCase, To: varcaser.LowerCamelCaseKeepCaps} clk2uc = varcaser.Caser{From: varcaser.KebabCase, To: varcaser.UpperCamelCaseKeepCaps} clk2ls = varcaser.Caser{From: varcaser.KebabCase, To: varcaser.LowerSnakeCase} clk2ss = varcaser.Caser{ From: varcaser.KebabCase, To: varcaser.ScreamingSnakeCase} clc2uc = varcaser.Caser{ From: varcaser.LowerCamelCase, To: varcaser.UpperCamelCaseKeepCaps} clc2ls = varcaser.Caser{ From: varcaser.LowerCamelCase, To: varcaser.LowerSnakeCase} clc2ss = varcaser.Caser{ From: varcaser.LowerCamelCase, To: varcaser.ScreamingSnakeCase} cuc2lc = varcaser.Caser{ From: varcaser.UpperCamelCase, To: varcaser.LowerCamelCase} cuc2ls = varcaser.Caser{ From: varcaser.UpperCamelCase, To: varcaser.LowerSnakeCase} cuc2ss = varcaser.Caser{ From: varcaser.UpperCamelCase, To: varcaser.ScreamingSnakeCase} ) var egFuncMap = easygen.FuncMap{ "cls2lc": cls2lc.String, "cls2uc": cls2uc.String, "cls2ss": cls2ss.String, "cls2lk": cls2lk.String, "cls2hh": cls2hh.String, "css2lc": css2lc.String, "css2uc": css2uc.String, "css2ls": css2ls.String, "css2lk": css2lk.String, "css2hh": css2hh.String, "clk2lc": clk2lc.String, "clk2uc": clk2uc.String, "clk2ls": clk2ls.String, "clk2ss": clk2ss.String, "clc2uc": clc2uc.String, "clc2ls": clc2ls.String, "clc2ss": clc2ss.String, "cuc2lc": cuc2lc.String, "cuc2ls": cuc2ls.String, "cuc2ss": cuc2ss.String, // Aliases, for backwards-compatibility with earlier (>= v1) versions "ck2lc": clk2lc.String, "ck2uc": clk2uc.String, "ck2ls": clk2ls.String, "ck2ss": clk2ss.String, } //////////////////////////////////////////////////////////////////////////// // Function definitions // FuncDefs returns the custom definition mapping for this specific package. func FuncDefs() template.FuncMap { return template.FuncMap(egFuncMap) } // NewTemplate returns a new Template for this specific package. func NewTemplate() *EgVar { return &EgVar{&easygen.EgBase{template.New("EgVar")}} } easygen-4.1.0/egVar/EgVar_test.go 0000664 0000000 0000000 00000007336 13502324010 0016604 0 ustar 00root root 0000000 0000000 package egVar_test import ( "fmt" "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egVar" ) func ExampleEgVar_output() { // EgVar variable names converting full coverage test tmpl0 := egVar.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egVar.FuncDefs()) fmt.Println("\n## From lk - KebabCase => CamelCase/SnakeCase") easygen.Process0(tmpl, os.Stdout, "{{.Name}}: {{clk2lc .Name}} {{clk2uc .Name}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, "{{.Name}}: {{clk2ls .Name}} {{clk2ss .Name}}\n", "../test/listfunc2") fmt.Println("\n## From ls/ss - LowerSnakeCase/ScreamingSnakeCase") easygen.Process0(tmpl, os.Stdout, "{{clk2ls .Name}} {{clk2ss .Name}} =>\n", "../test/listfunc2") fmt.Println("### From ls") easygen.Process0(tmpl, os.Stdout, " {{clk2ls .Name | cls2lc}} {{clk2ls .Name | cls2uc}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, " {{clk2ls .Name | cls2ss}} {{clk2ls .Name | cls2lk}} {{clk2ls .Name | cls2hh}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, " {{clk2ls .NameHTTP | cls2lc}} {{clk2ls .NameHTTP | cls2uc}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, " {{clk2ls .NameHTTP | cls2ss}} {{clk2ls .NameHTTP | cls2lk}} {{clk2ls .NameHTTP | cls2hh}}\n", "../test/listfunc2") fmt.Println("### From ss") easygen.Process0(tmpl, os.Stdout, " {{clk2ss .Name | css2lc}} {{clk2ss .Name | css2uc}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, " {{clk2ss .Name | css2ls}} {{clk2ss .Name | css2lk}} {{clk2ss .Name | css2hh}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, " {{clk2ss .NameHTTP | css2lc}} {{clk2ss .NameHTTP | css2uc}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, " {{clk2ss .NameHTTP | css2ls}} {{clk2ss .NameHTTP | css2lk}} {{clk2ss .NameHTTP | css2hh}}\n", "../test/listfunc2") fmt.Println("\n## From lc/uc - LowerCamelCase/UpperCamelCaseKeepCaps") easygen.Process0(tmpl, os.Stdout, "{{clk2lc .Name}} {{clk2uc .Name}} =>\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, "{{clk2lc .Name}}: {{clk2lc .Name | clc2uc}} {{clk2lc .Name | clc2ls}} {{clk2lc .Name | clc2ss}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, "{{clk2uc .Name}}: {{clk2uc .Name | cuc2lc}} {{clk2uc .Name | cuc2ls}} {{clk2uc .Name | cuc2ss}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, "{{.NameMixed}}: {{clc2uc .NameMixed}} {{clc2uc .NameMixed | cuc2lc}} {{clc2ls .NameMixed}} {{clc2ls .NameMixed | cls2lc}}\n", "../test/listfunc2") easygen.Process0(tmpl, os.Stdout, "{{.NameMixed}}: {{clc2ls .NameMixed | cls2ss}} {{clc2ls .NameMixed | cls2lk}} {{clc2ls .NameMixed | cls2hh}}\n", "../test/listfunc2") // Output: // // ## From lk - KebabCase => CamelCase/SnakeCase // some-init-method: someInitMethod SomeInitMethod // some-init-method: some_init_method SOME_INIT_METHOD // // ## From ls/ss - LowerSnakeCase/ScreamingSnakeCase // some_init_method SOME_INIT_METHOD => // ### From ls // someInitMethod SomeInitMethod // SOME_INIT_METHOD some-init-method Some-Init-Method // httpHeaderCase HttpHeaderCase // HTTP_HEADER_CASE http-header-case HTTP-Header-Case // ### From ss // someINITMETHOD SOMEINITMETHOD // some_init_method some-init-method Some-Init-Method // httpHEADERCASE HTTPHEADERCASE // http_header_case http-header-case HTTP-Header-Case // // ## From lc/uc - LowerCamelCase/UpperCamelCaseKeepCaps // someInitMethod SomeInitMethod => // someInitMethod: SomeInitMethod some_init_method SOME_INIT_METHOD // SomeInitMethod: someInitMethod some_init_method SOME_INIT_METHOD // some_InitMethod: Some_InitMethod some_InitMethod some__init_method someInitMethod // some_InitMethod: SOME__INIT_METHOD some--init-method Some--Init-Method } easygen-4.1.0/egVar/example_test.go 0000664 0000000 0000000 00000001102 13502324010 0017214 0 ustar 00root root 0000000 0000000 package egVar_test import ( "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egVar" ) // for standalone test, change package to `main` and the next func def to, // func main() { func Example() { // Equivalent testing on commandline: // easygen test/listfunc2 tmpl0 := egVar.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egVar.FuncDefs()) easygen.Process(tmpl, os.Stdout, "../test/listfunc2") // Output: // some-init-method 5 5 someInitMethod SomeInitMethod } // To show the full code in GoDoc type dummy struct { } easygen-4.1.0/example0_test.go 0000664 0000000 0000000 00000001331 13502324010 0016234 0 ustar 00root root 0000000 0000000 package easygen_test import ( "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egCal" "github.com/go-easygen/easygen/egVar" ) // for standalone test, change package to `main` and the next func def to, // func main() { func ExampleProcess0() { tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs()) easygen.Process0(tmpl, os.Stdout, "{{.Name}}: {{clk2uc .Name}} {{clk2ss .Name}}\n"+ "Cal: {{add 2 3}}, {{multiply 2 3}}, {{subtract 9 2}}, {{divide 24 3}}\n", "test/var0") // Output: // some-init-method: SomeInitMethod SOME_INIT_METHOD // Cal: 5, 6, 7, 8 } // To show the full code in GoDoc type dummy0 struct { } easygen-4.1.0/example_execute_test.go 0000664 0000000 0000000 00000002340 13502324010 0017677 0 ustar 00root root 0000000 0000000 package easygen_test import ( "fmt" "os" "strings" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egCal" "github.com/go-easygen/easygen/egVar" ) type variable struct { Name string } // for standalone test, change package to `main` and the next func def to, // func main() { func ExampleExecute() { easygen.Opts.Debug = 1 tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egVar.FuncDefs()).Funcs(egCal.FuncDefs()) // define driving data of any tye v0 := variable{"some-init-method"} // https://godoc.org/github.com/go-easygen/easygen#Execute // provide full template file name with extension easygen.Execute(tmpl, os.Stdout, "test/var0.tmpl", v0) // Demo of using driving data of pure slice/array v1 := []string{"red", "blue", "white"} easygen.Execute(tmpl, os.Stdout, "test/list00.tmpl", v1) // Demo output to string var b strings.Builder easygen.Execute(tmpl, &b, "test/list00f.tmpl", v1) fmt.Print(b.String()) // Output: // Input: "some-init-method" // Output 1: "SomeInitMethod" // Output 2: "SOME_INIT_METHOD" // The colors are: red, blue, white, . // The colors are: red, blue, white. } // To show the full code in GoDoc type dummyExecute struct { } easygen-4.1.0/example_test.go 0000664 0000000 0000000 00000001746 13502324010 0016166 0 ustar 00root root 0000000 0000000 package easygen_test import ( "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egVar" ) // for standalone test, change package to `main` and the next func def to, // func main() { func ExampleProcess() { tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egVar.FuncDefs()) tmplFileName := "test/var0" easygen.Process(tmpl, os.Stdout, tmplFileName) easygen.Process2(tmpl, os.Stdout, tmplFileName, tmplFileName) // To use Execute(), TemplateFileName has to be exact m := easygen.ReadDataFile(tmplFileName + ".yaml") easygen.Execute(tmpl, os.Stdout, tmplFileName+".tmpl", m) // Output: // Input: "some-init-method" // Output 1: "SomeInitMethod" // Output 2: "SOME_INIT_METHOD" // Input: "some-init-method" // Output 1: "SomeInitMethod" // Output 2: "SOME_INIT_METHOD" // Input: "some-init-method" // Output 1: "SomeInitMethod" // Output 2: "SOME_INIT_METHOD" } // To show the full code in GoDoc type dummy struct { } easygen-4.1.0/readdatafile_test.go 0000664 0000000 0000000 00000002353 13502324010 0017133 0 ustar 00root root 0000000 0000000 package easygen_test import ( "os" "github.com/go-easygen/easygen" "github.com/go-easygen/easygen/egVar" ) // for standalone test, change package to `main` and the next func def to, // func main() { func ExampleReadDataFile() { tmplFileName := "test/var0" tmpl0 := easygen.NewTemplate().Customize() tmpl := tmpl0.Funcs(easygen.FuncDefs()).Funcs(egVar.FuncDefs()) // To use Execute(), TemplateFileName has to be exact tmplFileNameFull := tmplFileName + ".tmpl" m := easygen.ReadDataFile(tmplFileName) easygen.Execute(tmpl, os.Stdout, tmplFileNameFull, m) easygen.Opts.Debug = 0 m = easygen.ReadDataFile(tmplFileName + ".yaml") easygen.Execute(tmpl, os.Stdout, tmplFileNameFull, m) tmplFileName = "test/list0j" tmplFileNameFull = tmplFileName + ".tmpl" m = easygen.ReadDataFile(tmplFileName) easygen.Execute(tmpl, os.Stdout, tmplFileNameFull, m) m = easygen.ReadDataFile(tmplFileName + ".json") easygen.Execute(tmpl, os.Stdout, tmplFileNameFull, m) // Output: // Input: "some-init-method" // Output 1: "SomeInitMethod" // Output 2: "SOME_INIT_METHOD" // Input: "some-init-method" // Output 1: "SomeInitMethod" // Output 2: "SOME_INIT_METHOD" // The colors are: red, blue, white, . // The colors are: red, blue, white, . } easygen-4.1.0/t_strings_test.go 0000664 0000000 0000000 00000007733 13502324010 0016551 0 ustar 00root root 0000000 0000000 package easygen_test import ( "bytes" "testing" "github.com/go-easygen/easygen" ) type testItem struct { tmplStr, expected string } //var tmpl *template.Template func testStringManipulation(t *testing.T, d []testItem) { tmpl = easygen.NewTemplate().Funcs(easygen.FuncDefs()) for _, tc := range d { buf := bytes.NewBufferString("") easygen.Process0(tmpl, buf, tc.tmplStr, "test/strings") v := buf.String() //t.Log(v) if v != tc.expected { t.Errorf("'%s' expects '%s', got '%s'", tc.tmplStr, tc.expected, v) } } } // for standalone test, change package to `main` and the next func def to, // func main() { func TestStringManipulation(t *testing.T) { testData := []testItem{ // == standard strings functions { `{{ stringsContains "seafood" "foo" }}`, "true", }, { `{{ stringsContains "seafood" "bar" }}`, "false", }, { `{{ stringsContainsAny "team" "i" }}`, "false", }, { `{{ stringsContainsAny "failure" "u & i" }}`, "true", }, { `{{ stringsCount "cheese" "e" }}`, "3", }, { `{{ stringsEqualFold "Go" "go" }}`, "true", }, { `{{ stringsFields " foo bar baz " }}`, "[foo bar baz]", }, { `{{ stringsIndex "go gopher" "go" }}`, "0", }, { `{{ stringsLastIndex "go gopher" "go" }}`, "3", }, { `ba{{ stringsRepeat "na" 2 }}`, "banana", }, { `{{ stringsReplace "oink oink oink" "k" "ky" 2 }}`, "oinky oinky oink", }, { `{{ stringsReplace "oink oink oink" "oink" "moo" -1 }}`, "moo moo moo", }, { `{{ stringsSplitN "a,b,c" "," 0 }}`, `[]`, }, { `{{ stringsSplitAfter "a,b,c" "," }}`, `[a, b, c]`, }, { `{{ stringsSplitAfterN "a,b,c" "," 2 }}`, `[a, b,c]`, }, { `{{ stringsTitle "her royal highness" }}`, "Her Royal Highness", }, { `{{ stringsToLower "Gopher" }}`, "gopher", }, { `{{ stringsToUpper "Gopher" }}`, "GOPHER", }, { `{{ stringsTrimSpace " \t\n a lone gopher \n\t\r\n" }}`, "a lone gopher", }, { `{{ stringsTrim " !!! Achtung !!! " "! " }}`, "Achtung", }, { `{{ stringsTrimPrefix "Goodbye,, world!" "Goodbye," }}`, ", world!", }, { `{{ stringsTrimSuffix "Hello, goodbye, etc!" "goodbye, etc!" }}`, "Hello, ", }, // aliases { `The {{if eq .StrTest "these rights belong to those people"}}eq says Yea{{else}}eq says Nay{{end}} but {{if eqf .StrTest "these rights belong to those people"}}eqf says Yea{{else}}eqf says Nay{{end}}.`, "The eq says Nay but eqf says Yea.", }, // == standard regexp functions { `{{ regexpFindString "peach punch" "p([a-z]+)ch" }}`, "peach", }, { `{{ regexpFindAllString "peach punch" "p([a-z]+)ch" -1 }}`, "[peach punch]", }, { `{{ regexpFindAllString "peach punch" "p([a-z]+)ch" 1 }}`, "[peach]", }, { `{{ regexpFindStringIndex "peach punch" "p([a-z]+)ch" }}`, "[0 5]", }, { `{{ regexpFindStringSubmatch "peach punch" "p([a-z]+)ch" }}`, "[peach ea]", }, { `{{ regexpFindStringSubmatchIndex "peach punch" "p([a-z]+)ch" }}`, "[0 5 1 3]", }, // { `{{ regexpMatchString "HTTPS://site/" "(?i)^http" }}`, "true", }, // { `{{ regexpReplaceAllLiteralString "html HTML Html aa uml bb Uml" "(?i)html|uml" "XML" }}`, "XML XML XML aa XML bb XML", }, { `{{ regexpReplaceAllString .StrTest "(?i)th[eo]se" "the" }}`, "the rights belong to the people", }, { `{{ regexpReplaceAllString "This and these are for THOSE people" "(?i)(this|th[eo]se)" "${1}" }}`, "This and these are for THOSE people", }, // { // `{{ regexpReplaceAllStringFunc "a peach" "p([a-z]+)ch" stringsToUpper }}`, // "a PEACH", // }, // == my added strings functions { `{{ coalesce "a" }}`, "a", }, { `{{ coalesce "" "b" }}`, "b", }, { `{{ coalesce "" "" "c" }}`, "c", }, { `{{ coalesce "" "" "" "" }}`, "", }, { `{{ coalesce "" }}`, "", }, } testStringManipulation(t, testData) } /* { `{{ }}`, "", }, */ easygen-4.1.0/template.go 0000664 0000000 0000000 00000011142 13502324010 0015276 0 ustar 00root root 0000000 0000000 //////////////////////////////////////////////////////////////////////////// // Package: easygen // Purpose: Easy to use universal code/text generator // Authors: Tong Sun (c) 2015-17, All rights reserved //////////////////////////////////////////////////////////////////////////// package easygen import ( "io" "os" "strings" "text/template" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions // The Template defines the common ground for both text and html Template type Template interface { Execute(wr io.Writer, data interface{}) error ExecuteTemplate(wr io.Writer, name string, data interface{}) error Parse(text string) (*template.Template, error) ParseFiles(filenames ...string) (*template.Template, error) Name() string } // EgBase -- EasyGen Template Base type EgBase struct { *template.Template } // The FuncMap defined in easygen will shield the dependency of either // text or html template, giving an implementation agnostic abstraction // that will works for both cases. type FuncMap map[string]interface{} var egFuncMap = FuncMap{ // == standard strings function definitions "stringsCompare": strings.Compare, "stringsContains": strings.Contains, "stringsContainsAny": strings.ContainsAny, "stringsContainsRune": strings.ContainsRune, "stringsCount": strings.Count, "stringsEqualFold": strings.EqualFold, "stringsFields": strings.Fields, "stringsFieldsFunc": strings.FieldsFunc, "stringsHasPrefix": strings.HasPrefix, "stringsHasSuffix": strings.HasSuffix, "stringsIndex": strings.Index, "stringsIndexAny": strings.IndexAny, "stringsIndexByte": strings.IndexByte, "stringsIndexFunc": strings.IndexFunc, "stringsIndexRune": strings.IndexRune, "stringsJoin": strings.Join, "stringsLastIndex": strings.LastIndex, "stringsLastIndexAny": strings.LastIndexAny, "stringsLastIndexByte": strings.LastIndexByte, "stringsLastIndexFunc": strings.LastIndexFunc, "stringsMap": strings.Map, "stringsRepeat": strings.Repeat, "stringsReplace": strings.Replace, "stringsSplit": strings.Split, "stringsSplitAfter": strings.SplitAfter, "stringsSplitAfterN": strings.SplitAfterN, "stringsSplitN": strings.SplitN, "stringsTitle": strings.Title, "stringsToLower": strings.ToLower, "stringsToLowerSpecial": strings.ToLowerSpecial, "stringsToTitle": strings.ToTitle, "stringsToTitleSpecial": strings.ToTitleSpecial, "stringsToUpper": strings.ToUpper, "stringsToUpperSpecial": strings.ToUpperSpecial, "stringsTrim": strings.Trim, "stringsTrimFunc": strings.TrimFunc, "stringsTrimLeft": strings.TrimLeft, "stringsTrimLeftFunc": strings.TrimLeftFunc, "stringsTrimPrefix": strings.TrimPrefix, "stringsTrimRight": strings.TrimRight, "stringsTrimRightFunc": strings.TrimRightFunc, "stringsTrimSpace": strings.TrimSpace, "stringsTrimSuffix": strings.TrimSuffix, // aliases "eqf": strings.EqualFold, "split": strings.Fields, // == standard regexp function definitions "regexpFindAllString": regexpFindAllString, "regexpFindAllStringIndex": regexpFindAllStringIndex, "regexpFindAllStringSubmatch": regexpFindAllStringSubmatch, "regexpFindAllStringSubmatchIndex": regexpFindAllStringSubmatchIndex, "regexpFindString": regexpFindString, "regexpFindStringIndex": regexpFindStringIndex, "regexpFindStringSubmatch": regexpFindStringSubmatch, "regexpFindStringSubmatchIndex": regexpFindStringSubmatchIndex, "regexpMatchString": regexpMatchString, "regexpReplaceAllLiteralString": regexpReplaceAllLiteralString, "regexpReplaceAllString": regexpReplaceAllString, "regexpReplaceAllStringFunc": regexpReplaceAllStringFunc, "regexpSplit": regexpSplit, // == my added functions "ENV": os.Getenv, "coalesce": coalesce, "quote4shell": quote4shell, "minus1": minus1, "date": date, "timestamp": timestamp, } //////////////////////////////////////////////////////////////////////////// // Function definitions // FuncDefs returns the custom definition mapping for this specific package. func FuncDefs() template.FuncMap { return template.FuncMap(egFuncMap) } // NewTemplate returns a new Template for this specific package. func NewTemplate() *EgBase { return &EgBase{template.New("EgBase")} } // Customize allows customization for this specific package. func (t *EgBase) Customize() *EgBase { return t } easygen-4.1.0/test/ 0000775 0000000 0000000 00000000000 13502324010 0014114 5 ustar 00root root 0000000 0000000 easygen-4.1.0/test/.gitignore 0000664 0000000 0000000 00000000110 13502324010 0016074 0 ustar 00root root 0000000 0000000 # Generated output, to be compared with the .ref reference output *.got easygen-4.1.0/test/commandlineCLI-024.ref 0000664 0000000 0000000 00000007061 13502324010 0017737 0 ustar 00root root 0000000 0000000 // -*- go -*- //////////////////////////////////////////////////////////////////////////// // Program: gogo // Purpose: Golang package manager //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var app = &cli.Register(&cli.Command{ Name: "gogo", Desc: "Golang package manager", Text: " gogo is a new golang package manager\n very very good", Argv: func() interface{} { return new(gogoT) }, Fn: gogo, NumArg: cli.ExactN(1), }) type gogoT struct { cli.Helper Version bool `cli:"v,version" usage:"display version"` List bool `cli:"l,list" usage:"list all sub commands or not"` } func gogo(ctx *cli.Context) error { argv := ctx.Argv().(*gogoT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[gogo]: %v\n", ctx.Args()) return nil } //////////////////////////////////////////////////////////////////////////// // Program: build // Purpose: Build golang application //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var buildCmd = app.Register(&cli.Command{ Name: "build", Desc: "Build golang application", Text: "Usage:\n gogo build [Options] Arch(i386|amd64)", Argv: func() interface{} { return new(buildT) }, Fn: build, NumArg: cli.ExactN(1), CanSubRoute: true, }) type buildT struct { cli.Helper Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } func build(ctx *cli.Context) error { argv := ctx.Argv().(*buildT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[build]: %v\n", ctx.Args()) return nil } //////////////////////////////////////////////////////////////////////////// // Program: install // Purpose: Install golang application //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var installCmd = app.Register(&cli.Command{ Name: "install", Desc: "Install golang application", Text: "Usage:\n gogo install [Options] package [package...]", Argv: func() interface{} { return new(installT) }, Fn: install, NumArg: cli.AtLeast(1), CanSubRoute: true, }) type installT struct { cli.Helper Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } func install(ctx *cli.Context) error { argv := ctx.Argv().(*installT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[install]: %v\n", ctx.Args()) return nil } //////////////////////////////////////////////////////////////////////////// // Program: publish // Purpose: Publish golang application //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) var publishCmd = app.Register(&cli.Command{ Name: "publish", Desc: "Publish golang application", Argv: func() interface{} { return new(publishT) }, Fn: publish, }) type publishT struct { cli.Helper Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` List bool `cli:"l,list" usage:"list all sub commands"` } func publish(ctx *cli.Context) error { argv := ctx.Argv().(*publishT) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[publish]: %v\n", ctx.Args()) return nil } easygen-4.1.0/test/commandlineCLI-024.tmpl 0000664 0000000 0000000 00000003367 13502324010 0020144 0 ustar 00root root 0000000 0000000 // -*- go -*- //////////////////////////////////////////////////////////////////////////// // Program: {{.Name}} // Purpose: {{.Desc}} //////////////////////////////////////////////////////////////////////////// package {{$.PackageName}} import ( "github.com/mkideal/cli" ) var {{.Var}} = &cli.Register(&cli.Command{ Name: "{{.Name}}", Desc: "{{.Desc}}", {{if .Text}} Text: "{{.Text}}", {{end}} Argv: func() interface{} { return new({{.Name}}T) }, Fn: {{.Name}}, {{if .NumArg}} NumArg: {{.NumArg}}, {{end}}}) type {{.Name}}T struct { cli.Helper{{range .Options}} {{.Name}} {{.Type}} `cli:"{{.Flag}}" usage:"{{.Usage}}"{{if .Value}} dft:{{.Value}}{{end}}`{{end}} } func {{.Name}}(ctx *cli.Context) error { argv := ctx.Argv().(*{{.Name}}T) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[{{.Name}}]: %v\n", ctx.Args()) return nil } {{range .Command}} //////////////////////////////////////////////////////////////////////////// // Program: {{.Name}} // Purpose: {{.Desc}} //////////////////////////////////////////////////////////////////////////// package {{$.PackageName}} import ( "github.com/mkideal/cli" ) var {{.Name}}Cmd = {{$.Var}}.Register(&cli.Command{ Name: "{{.Name}}", Desc: "{{.Desc}}", {{if .Text}} Text: "{{.Text}}", {{end}} Argv: func() interface{} { return new({{.Name}}T) }, Fn: {{.Name}}, {{if .NumArg}} NumArg: {{.NumArg}}, CanSubRoute: true, {{end}}}) type {{.Name}}T struct { cli.Helper{{range .Options}} {{.Name}} {{.Type}} `cli:"{{.Flag}}" usage:"{{.Usage}}"{{if .Value}} dft:{{.Value}}{{end}}`{{end}} } func {{.Name}}(ctx *cli.Context) error { argv := ctx.Argv().(*{{.Name}}T) ctx.String("%s: %v", ctx.Path(), jsonIndent(argv)) ctx.String("[{{.Name}}]: %v\n", ctx.Args()) return nil } {{end}} easygen-4.1.0/test/commandlineCLI-024.yaml 0000664 0000000 0000000 00000005126 13502324010 0020125 0 ustar 00root root 0000000 0000000 # program name, name for the executable ProgramName: gogo # package name # - For standalone program that does not belong to any package, e.g., # https://github.com/suntong/easygen/blob/7791e4f0e5605543d27da1671a21376cdb9dcf2a/easygen/easygen.go # just ignore the first line, the `package` output, and copy the rest # - If you don't mind using a separated file to handle commandline paramters, # then name the package as "main". see the spin-out "TF-minus1.go" file under # https://github.com/suntong/easygen/tree/d1ab0b5fe80ddac57fe9ef51f6ccb3ab998cd5ee # - If you are using it in a pacakge, look no further than # https://github.com/suntong/easygen/blob/master/easygenapi/config.go # which was a direct dump: easygen test/commandlineFlag | gofmt > easygenapi/config.go # PackageName: main Name: gogo Var: app Desc: "Golang package manager" Text: ' gogo is a new golang package manager\n very very good' NumArg: cli.ExactN(1) Options: - Name: Version Type: bool Flag: v,version Usage: display version - Name: List Type: bool Flag: l,list Usage: list all sub commands or not Command: - Name: build Desc: "Build golang application" Text: 'Usage:\n gogo build [Options] Arch(i386|amd64)' NumArg: cli.ExactN(1) Options: - Name: Dir Type: string Flag: dir Value: '"./"' Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: '".go,.c,.s"' Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: install Desc: "Install golang application" Text: 'Usage:\n gogo install [Options] package [package...]' NumArg: cli.AtLeast(1) Options: - Name: Dir Type: string Flag: dir Value: '"./"' Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: '".go,.c,.s"' Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: publish Desc: "Publish golang application" Options: - Name: Dir Type: string Flag: dir Value: '"./"' Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: '".go,.c,.s"' Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: List Type: bool Flag: l,list Usage: "list all sub commands" easygen-4.1.0/test/commandlineCLI-027.ref 0000664 0000000 0000000 00000007212 13502324010 0017740 0 ustar 00root root 0000000 0000000 // -*- go -*- //////////////////////////////////////////////////////////////////////////// // Program: redo // Purpose: global option redo //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) //////////////////////////////////////////////////////////////////////////// // redo type rootT struct { cli.Helper Self *rootT `cli:"c,config" usage:"config file" json:"-" parser:"jsonfile" dft:"redo.json"` Host string `cli:"H,host" usage:"host address" dft:"$HOST"` Port int `cli:"p,port" usage:"listening port" dft:"80"` } var root = &cli.Command{ Name: "redo", Desc: "global option redo", Text: " redo global option via automatic code-gen", Global: true, Argv: func() interface{} { t := new(rootT); t.Self = t; return t }, Fn: redo, NumArg: cli.ExactN(1), } // func main() { // cli.SetUsageStyle(cli.ManualStyle) // up-down, for left-right, use NormalStyle // //NOTE: You can set any writer implements io.Writer // // default writer is os.Stdout // if err := cli.Root(root, // cli.Tree(buildDef), // cli.Tree(installDef), // cli.Tree(publishDef)).Run(os.Args[1:]); err != nil { // fmt.Fprintln(os.Stderr, err) // } // fmt.Println("") // } // func redo(ctx *cli.Context) error { // ctx.JSON(ctx.RootArgv()) // ctx.JSON(ctx.Argv()) // fmt.Println() // return nil // } //////////////////////////////////////////////////////////////////////////// // build // func buildCLI(ctx *cli.Context) error { // rootArgv := ctx.RootArgv().(*rootT) // argv := ctx.Argv().(*buildT) // fmt.Printf("[build]:\n %+v\n %+v\n %v\n", rootArgv, argv, ctx.Args()) // return nil // } type buildT struct { Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } var buildDef = &cli.Command{ Name: "build", Desc: "Build the network application", Text: "Usage:\n redo build [Options] Arch(i386|amd64)", Argv: func() interface{} { return new(buildT) }, Fn: buildCLI, NumArg: cli.ExactN(1), CanSubRoute: true, } //////////////////////////////////////////////////////////////////////////// // install // func installCLI(ctx *cli.Context) error { // rootArgv := ctx.RootArgv().(*rootT) // argv := ctx.Argv().(*installT) // fmt.Printf("[install]:\n %+v\n %+v\n %v\n", rootArgv, argv, ctx.Args()) // return nil // } type installT struct { Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } var installDef = &cli.Command{ Name: "install", Desc: "Install the network application", Text: "Usage:\n redo install [Options] package [package...]", Argv: func() interface{} { return new(installT) }, Fn: installCLI, NumArg: cli.AtLeast(1), CanSubRoute: true, } //////////////////////////////////////////////////////////////////////////// // publish // func publishCLI(ctx *cli.Context) error { // rootArgv := ctx.RootArgv().(*rootT) // argv := ctx.Argv().(*publishT) // fmt.Printf("[publish]:\n %+v\n %+v\n %v\n", rootArgv, argv, ctx.Args()) // return nil // } type publishT struct { Dir string `cli:"*d,dir" usage:"publish dir"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` List bool `cli:"l,list" usage:"list all sub commands"` } var publishDef = &cli.Command{ Name: "publish", Desc: "Publish the network application", Argv: func() interface{} { return new(publishT) }, Fn: publishCLI, NumOption: cli.AtLeast(1), } easygen-4.1.0/test/commandlineCLI-027.tmpl 0000664 0000000 0000000 00000005157 13502324010 0020146 0 ustar 00root root 0000000 0000000 // -*- go -*- //////////////////////////////////////////////////////////////////////////// // Program: {{.Name}} // Purpose: {{.Desc}} //////////////////////////////////////////////////////////////////////////// package {{$.PackageName}} import ( "github.com/mkideal/cli" ) //////////////////////////////////////////////////////////////////////////// // {{.Name}} type rootT struct { cli.Helper{{range .Options}} {{.Name}} {{.Type}} `cli:"{{.Flag}}" usage:"{{.Usage}}"{{if eq .Name "Self" }} json:"-" parser:"jsonfile"{{end}}{{if .Value}} dft:"{{.Value}}"{{end}}`{{end}} } var root = &cli.Command{ Name: "{{.Name}}", Desc: "{{.Desc}}", {{if .Text}} Text: "{{.Text}}", {{end}}{{if .Global}} Global: {{.Global}}, {{end}}{{if .Self}} Argv: func() interface{} { t := new(rootT); t.Self = t; return t }, {{else}} Argv: func() interface{} { return new(rootT) }, {{end}} Fn: {{.Name}}, {{if .NumOption}} NumOption: {{.NumOption}}, {{end}}{{if .NumArg}} NumArg: {{.NumArg}}, {{end}}{{if .CanSubRoute}} CanSubRoute: {{.CanSubRoute}}, {{end}}} // func main() { // cli.SetUsageStyle(cli.ManualStyle) // up-down, for left-right, use NormalStyle // //NOTE: You can set any writer implements io.Writer // // default writer is os.Stdout // if err := cli.Root(root,{{range $i, $cmd := .Command}} // cli.Tree({{$cmd.Name}}Def){{if lt $i ($.Command | len | minus1)}},{{end}}{{end}}).Run(os.Args[1:]); err != nil { // fmt.Fprintln(os.Stderr, err) // } // fmt.Println("") // } // func {{.Name}}(ctx *cli.Context) error { // ctx.JSON(ctx.RootArgv()) // ctx.JSON(ctx.Argv()) // fmt.Println() // return nil // } {{range .Command}} //////////////////////////////////////////////////////////////////////////// // {{.Name}} // func {{.Name}}CLI(ctx *cli.Context) error { // rootArgv := ctx.RootArgv().(*rootT) // argv := ctx.Argv().(*{{.Name}}T) // fmt.Printf("[{{.Name}}]:\n %+v\n %+v\n %v\n", rootArgv, argv, ctx.Args()) // return nil // } type {{.Name}}T struct { {{range .Options}} {{.Name}} {{.Type}} `cli:"{{.Flag}}" usage:"{{.Usage}}"{{if eq .Name "Self" }} json:"-" parser:"jsonfile"{{end}}{{if .Value}} dft:"{{.Value}}"{{end}}`{{end}} } var {{.Name}}Def = &cli.Command{ Name: "{{.Name}}", Desc: "{{.Desc}}", {{if .Text}} Text: "{{.Text}}", {{end}}{{if .Self}} Argv: func() interface{} { t := new({{.Name}}T); t.Self = t; return t }, {{else}} Argv: func() interface{} { return new({{.Name}}T) }, {{end}} Fn: {{.Name}}CLI, {{if .NumOption}} NumOption: {{.NumOption}}, {{end}}{{if .NumArg}} NumArg: {{.NumArg}}, CanSubRoute: true, {{end}}{{if .CanSubRoute}} CanSubRoute: {{.CanSubRoute}}, {{end}}} {{end}} easygen-4.1.0/test/commandlineCLI-027.yaml 0000664 0000000 0000000 00000005312 13502324010 0020125 0 ustar 00root root 0000000 0000000 # program name, name for the executable ProgramName: redo # package name # - For standalone program that does not belong to any package, e.g., # https://github.com/suntong/easygen/blob/7791e4f0e5605543d27da1671a21376cdb9dcf2a/easygen/easygen.go # just ignore the first line, the `package` output, and copy the rest # - If you don't mind using a separated file to handle commandline paramters, # then name the package as "main". see the spin-out "TF-minus1.go" file under # https://github.com/suntong/easygen/tree/d1ab0b5fe80ddac57fe9ef51f6ccb3ab998cd5ee # - If you are using it in a pacakge, look no further than # https://github.com/suntong/easygen/blob/master/easygenapi/config.go # which was a direct dump: easygen test/commandlineFlag | gofmt > easygenapi/config.go # PackageName: main Name: redo Desc: "global option redo" Text: ' redo global option via automatic code-gen' Global: true NumArg: cli.ExactN(1) Self: true Options: - Name: Self Type: '*rootT' Flag: c,config Usage: config file Value: redo.json - Name: Host Type: string Flag: H,host Usage: host address Value: "$HOST" - Name: Port Type: int Flag: p,port Usage: listening port Value: 80 Command: - Name: build Desc: "Build the network application" Text: 'Usage:\n redo build [Options] Arch(i386|amd64)' NumArg: cli.ExactN(1) Options: - Name: Dir Type: string Flag: dir Value: "./" Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: ".go,.c,.s" Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: install Desc: "Install the network application" Text: 'Usage:\n redo install [Options] package [package...]' NumArg: cli.AtLeast(1) Options: - Name: Dir Type: string Flag: dir Value: "./" Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: ".go,.c,.s" Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: publish Desc: "Publish the network application" NumOption: cli.AtLeast(1) Options: - Name: Dir Type: string Flag: '*d,dir' Usage: publish dir - Name: Suffix Type: string Flag: suffix Value: ".go,.c,.s" Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: List Type: bool Flag: l,list Usage: "list all sub commands" easygen-4.1.0/test/commandlineCLI-027s.ref 0000664 0000000 0000000 00000007214 13502324010 0020125 0 ustar 00root root 0000000 0000000 // -*- go -*- //////////////////////////////////////////////////////////////////////////// // Program: redo // Purpose: global option redo //////////////////////////////////////////////////////////////////////////// package main import ( "github.com/mkideal/cli" ) //////////////////////////////////////////////////////////////////////////// // redo type rootT struct { cli.Helper Host string `cli:"H,host" usage:"host address" dft:"$HOST"` Port int `cli:"p,port" usage:"listening port" dft:"80"` } var root = &cli.Command{ Name: "redo", Desc: "global option redo", Text: " redo global option via automatic code-gen", Global: true, Argv: func() interface{} { return new(rootT) }, Fn: redo, NumArg: cli.ExactN(1), } // func main() { // cli.SetUsageStyle(cli.ManualStyle) // up-down, for left-right, use NormalStyle // //NOTE: You can set any writer implements io.Writer // // default writer is os.Stdout // if err := cli.Root(root, // cli.Tree(buildDef), // cli.Tree(installDef), // cli.Tree(publishDef)).Run(os.Args[1:]); err != nil { // fmt.Fprintln(os.Stderr, err) // } // fmt.Println("") // } // func redo(ctx *cli.Context) error { // ctx.JSON(ctx.RootArgv()) // ctx.JSON(ctx.Argv()) // fmt.Println() // return nil // } //////////////////////////////////////////////////////////////////////////// // build // func buildCLI(ctx *cli.Context) error { // rootArgv := ctx.RootArgv().(*rootT) // argv := ctx.Argv().(*buildT) // fmt.Printf("[build]:\n %+v\n %+v\n %v\n", rootArgv, argv, ctx.Args()) // return nil // } type buildT struct { Self *buildT `cli:"c,config" usage:"config file" json:"-" parser:"jsonfile" dft:"build.json"` Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } var buildDef = &cli.Command{ Name: "build", Desc: "Build the network application", Text: "Usage:\n redo build [Options] Arch(i386|amd64)", Argv: func() interface{} { t := new(buildT); t.Self = t; return t }, Fn: buildCLI, NumArg: cli.ExactN(1), CanSubRoute: true, } //////////////////////////////////////////////////////////////////////////// // install // func installCLI(ctx *cli.Context) error { // rootArgv := ctx.RootArgv().(*rootT) // argv := ctx.Argv().(*installT) // fmt.Printf("[install]:\n %+v\n %+v\n %v\n", rootArgv, argv, ctx.Args()) // return nil // } type installT struct { Dir string `cli:"dir" usage:"source code root dir" dft:"./"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` } var installDef = &cli.Command{ Name: "install", Desc: "Install the network application", Text: "Usage:\n redo install [Options] package [package...]", Argv: func() interface{} { return new(installT) }, Fn: installCLI, NumArg: cli.AtLeast(1), CanSubRoute: true, } //////////////////////////////////////////////////////////////////////////// // publish // func publishCLI(ctx *cli.Context) error { // rootArgv := ctx.RootArgv().(*rootT) // argv := ctx.Argv().(*publishT) // fmt.Printf("[publish]:\n %+v\n %+v\n %v\n", rootArgv, argv, ctx.Args()) // return nil // } type publishT struct { Dir string `cli:"*d,dir" usage:"publish dir"` Suffix string `cli:"suffix" usage:"source file suffix" dft:".go,.c,.s"` Out string `cli:"o,out" usage:"output filename"` List bool `cli:"l,list" usage:"list all sub commands"` } var publishDef = &cli.Command{ Name: "publish", Desc: "Publish the network application", Argv: func() interface{} { return new(publishT) }, Fn: publishCLI, NumOption: cli.AtLeast(1), } easygen-4.1.0/test/commandlineCLI-027s.yaml 0000664 0000000 0000000 00000005344 13502324010 0020315 0 ustar 00root root 0000000 0000000 # program name, name for the executable ProgramName: redo # package name # - For standalone program that does not belong to any package, e.g., # https://github.com/suntong/easygen/blob/7791e4f0e5605543d27da1671a21376cdb9dcf2a/easygen/easygen.go # just ignore the first line, the `package` output, and copy the rest # - If you don't mind using a separated file to handle commandline paramters, # then name the package as "main". see the spin-out "TF-minus1.go" file under # https://github.com/suntong/easygen/tree/d1ab0b5fe80ddac57fe9ef51f6ccb3ab998cd5ee # - If you are using it in a pacakge, look no further than # https://github.com/suntong/easygen/blob/master/easygenapi/config.go # which was a direct dump: easygen test/commandlineFlag | gofmt > easygenapi/config.go # PackageName: main Name: redo Desc: "global option redo" Text: ' redo global option via automatic code-gen' Global: true NumArg: cli.ExactN(1) Options: - Name: Host Type: string Flag: H,host Usage: host address Value: "$HOST" - Name: Port Type: int Flag: p,port Usage: listening port Value: 80 Command: - Name: build Desc: "Build the network application" Text: 'Usage:\n redo build [Options] Arch(i386|amd64)' NumArg: cli.ExactN(1) Self: true Options: - Name: Self Type: '*buildT' Flag: c,config Usage: config file Value: build.json - Name: Dir Type: string Flag: dir Value: "./" Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: ".go,.c,.s" Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: install Desc: "Install the network application" Text: 'Usage:\n redo install [Options] package [package...]' NumArg: cli.AtLeast(1) Options: - Name: Dir Type: string Flag: dir Value: "./" Usage: source code root dir - Name: Suffix Type: string Flag: suffix Value: ".go,.c,.s" Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: publish Desc: "Publish the network application" NumOption: cli.AtLeast(1) Options: - Name: Dir Type: string Flag: '*d,dir' Usage: publish dir - Name: Suffix Type: string Flag: suffix Value: ".go,.c,.s" Usage: "source file suffix" - Name: Out Type: string Flag: o,out Usage: "output filename" - Name: List Type: bool Flag: l,list Usage: "list all sub commands" easygen-4.1.0/test/commandlineCV.ref 0000664 0000000 0000000 00000001336 13502324010 0017334 0 ustar 00root root 0000000 0000000 flags.Bool("debug", false, "Turn on debugging.") viper.BindPFlag("debug", flags.Lookup("debug")) flags.String("addr", "localhost:5002", "Address of the service.") viper.BindPFlag("addr", flags.Lookup("addr")) flags.String("smtp-addr", "localhost:25", "Address of the SMTP server.") viper.BindPFlag("smtp-addr", flags.Lookup("smtp-addr")) flags.String("smtp-user", "", "User for the SMTP server.") viper.BindPFlag("smtp-user", flags.Lookup("smtp-user")) flags.String("smtp-password", "", "Password for the SMTP server.") viper.BindPFlag("smtp-password", flags.Lookup("smtp-password")) flags.String("email-from", "noreply@abc.com", "The from email address.") viper.BindPFlag("email-from", flags.Lookup("email-from")) easygen-4.1.0/test/commandlineCV.tmpl 0000664 0000000 0000000 00000000214 13502324010 0017526 0 ustar 00root root 0000000 0000000 {{range .Options}} flags.{{.Type}}("{{.Name}}", {{.Value}}, "{{.Usage}}") viper.BindPFlag("{{.Name}}", flags.Lookup("{{.Name}}")) {{end}} easygen-4.1.0/test/commandlineCV.yaml 0000664 0000000 0000000 00000001111 13502324010 0017511 0 ustar 00root root 0000000 0000000 Options: - Name: debug Type: Bool Value: false Usage: Turn on debugging. - Name: addr Type: String Value: '"localhost:5002"' Usage: Address of the service. - Name: smtp-addr Type: String Value: '"localhost:25"' Usage: Address of the SMTP server. - Name: smtp-user Type: String Value: '""' Usage: User for the SMTP server. - Name: smtp-password Type: String Value: '""' Usage: Password for the SMTP server. - Name: email-from Type: String Value: '"noreply@abc.com"' Usage: The from email address. easygen-4.1.0/test/commandlineCVFull.ref 0000664 0000000 0000000 00000003100 13502324010 0020146 0 ustar 00root root 0000000 0000000 func init() { viper.SetEnvPrefix("DISPATCH") viper.AutomaticEnv() /* When AutomaticEnv called, Viper will check for an environment variable any time a viper.Get request is made. It will apply the following rules. It will check for a environment variable with a name matching the key uppercased and prefixed with the EnvPrefix if set. */ flags := mainCmd.Flags() flags.Bool("Debug", false, "Turn on debugging.") viper.BindPFlag("Debug", flags.Lookup("Debug")) flags.String("addr", "localhost:5002", "Address of the service.") viper.BindPFlag("addr", flags.Lookup("addr")) flags.String("smtp-addr", "localhost:25", "Address of the SMTP server.") viper.BindPFlag("smtp-addr", flags.Lookup("smtp-addr")) flags.String("smtp-user", "", "User for the SMTP server.") viper.BindPFlag("smtp-user", flags.Lookup("smtp-user")) flags.String("smtp-password", "", "Password for the SMTP server.") viper.BindPFlag("smtp-password", flags.Lookup("smtp-password")) flags.String("email-from", "noreply@abc.com", "The from email address.") viper.BindPFlag("email-from", flags.Lookup("email-from")) // Viper supports reading from yaml, toml and/or json files. Viper can // search multiple paths. Paths will be searched in the order they are // provided. Searches stopped once Config File found. viper.SetConfigName("CommandLineCV") // name of config file (without extension) viper.AddConfigPath("/tmp") viper.AddConfigPath(".") err := viper.ReadInConfig() if err != nil { println("No config file found. Using built-in defaults.") } } easygen-4.1.0/test/commandlineCVFull.tmpl 0000664 0000000 0000000 00000001763 13502324010 0020363 0 ustar 00root root 0000000 0000000 func init() { viper.SetEnvPrefix("{{.CmdPrefix}}") viper.AutomaticEnv() /* When AutomaticEnv called, Viper will check for an environment variable any time a viper.Get request is made. It will apply the following rules. It will check for a environment variable with a name matching the key uppercased and prefixed with the EnvPrefix if set. */ flags := {{.CmdMain}}.Flags() {{range .Options}} flags.{{.Type}}("{{.Name}}", {{.Value}}, "{{.Usage}}") viper.BindPFlag("{{.Name}}", flags.Lookup("{{.Name}}")) {{end}} // Viper supports reading from yaml, toml and/or json files. Viper can // search multiple paths. Paths will be searched in the order they are // provided. Searches stopped once Config File found. viper.SetConfigName("{{.ConfigName}}") // name of config file (without extension) {{range .ConfigPath}} viper.AddConfigPath("{{.}}"){{end}} err := viper.ReadInConfig() if err != nil { println("No config file found. Using built-in defaults.") } } easygen-4.1.0/test/commandlineCVFull.yaml 0000664 0000000 0000000 00000001246 13502324010 0020345 0 ustar 00root root 0000000 0000000 CmdMain: mainCmd CmdPrefix: DISPATCH Options: - Name: Debug Type: Bool Value: false Usage: Turn on debugging. - Name: addr Type: String Value: '"localhost:5002"' Usage: Address of the service. - Name: smtp-addr Type: String Value: '"localhost:25"' Usage: Address of the SMTP server. - Name: smtp-user Type: String Value: '""' Usage: User for the SMTP server. - Name: smtp-password Type: String Value: '""' Usage: Password for the SMTP server. - Name: email-from Type: String Value: '"noreply@abc.com"' Usage: The from email address. ConfigName: CommandLineCV ConfigPath: - /tmp - . easygen-4.1.0/test/commandlineFlag 0000664 0000000 0000000 00000000167 13502324010 0017123 0 ustar 00root root 0000000 0000000 something invalid for .yaml file, to verify that it is preferable to pick the .yaml file with the full extension first easygen-4.1.0/test/commandlineFlag.ref 0000664 0000000 0000000 00000006075 13502324010 0017702 0 ustar 00root root 0000000 0000000 // !!! !!! // WARNING: Code automatically generated. Editing discouraged. // !!! !!! package easygenapi import ( "flag" "fmt" "os" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions const progname = "easygen" // os.Args[0] // The Options struct defines the structure to hold the commandline values type Options struct { HTML bool // treat the template file as html instead of text TemplateStr string // template string (in text) TemplateFile string // .tmpl (comma-separated) template file `name(s)` (default: same as .yaml file) ExtYaml string // `extension` of yaml file ExtTmpl string // `extension` of template file StrFrom string // replace from, the from string used for the replace function StrTo string // replace to, the to string used for the replace function Debug int // debugging `level` } //////////////////////////////////////////////////////////////////////////// // Global variables definitions // Opts holds the actual values from the command line parameters var Opts Options //////////////////////////////////////////////////////////////////////////// // Commandline definitions func init() { // set default values for command line parameters flag.BoolVar(&Opts.HTML, "html", false, "treat the template file as html instead of text") flag.StringVar(&Opts.TemplateStr, "ts", "", "template string (in text)") flag.StringVar(&Opts.TemplateFile, "tf", "", ".tmpl (comma-separated) template file `name(s)` (default: same as .yaml file)") flag.StringVar(&Opts.ExtYaml, "ey", ".yaml", "`extension` of yaml file") flag.StringVar(&Opts.ExtTmpl, "et", ".tmpl", "`extension` of template file") flag.StringVar(&Opts.StrFrom, "rf", "", "replace from, the from string used for the replace function") flag.StringVar(&Opts.StrTo, "rt", "", "replace to, the to string used for the replace function") flag.IntVar(&Opts.Debug, "debug", 0, "debugging `level`") // Now override those default values from environment variables if len(Opts.TemplateStr) == 0 || len(os.Getenv("EASYGEN_TS")) != 0 { Opts.TemplateStr = os.Getenv("EASYGEN_TS") } if len(Opts.TemplateFile) == 0 || len(os.Getenv("EASYGEN_TF")) != 0 { Opts.TemplateFile = os.Getenv("EASYGEN_TF") } if len(Opts.ExtYaml) == 0 || len(os.Getenv("EASYGEN_EY")) != 0 { Opts.ExtYaml = os.Getenv("EASYGEN_EY") } if len(Opts.ExtTmpl) == 0 || len(os.Getenv("EASYGEN_ET")) != 0 { Opts.ExtTmpl = os.Getenv("EASYGEN_ET") } if len(Opts.StrFrom) == 0 || len(os.Getenv("EASYGEN_RF")) != 0 { Opts.StrFrom = os.Getenv("EASYGEN_RF") } if len(Opts.StrTo) == 0 || len(os.Getenv("EASYGEN_RT")) != 0 { Opts.StrTo = os.Getenv("EASYGEN_RT") } } // Usage function shows help on commandline usage func Usage() { fmt.Fprintf(os.Stderr, "\nUsage:\n %s [flags] YamlFileName [YamlFileName...]\n\nFlags:\n\n", progname) flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\nYamlFileName(s): The name for the .yaml data and .tmpl template file\n\tOnly the name part, without extension. Can include the path as well.\n") os.Exit(0) } easygen-4.1.0/test/commandlineFlag.tmpl 0000664 0000000 0000000 00000003727 13502324010 0020103 0 ustar 00root root 0000000 0000000 // !!! !!! // WARNING: Code automatically generated. Editing discouraged. // !!! !!! package {{.PackageName}} import ( "flag" "fmt" "os" ) //////////////////////////////////////////////////////////////////////////// // Constant and data type/structure definitions const progname = "{{.ProgramName}}" // os.Args[0] // The {{.StructName}} struct defines the structure to hold the commandline values type {{.StructName}} struct { {{range .Options}}{{if ne .Name "SEPARATOR" }} {{.Name}} {{.Type}} // {{.Usage}}{{end}}{{end}} } //////////////////////////////////////////////////////////////////////////// // Global variables definitions // {{.StructVar}} holds the actual values from the command line parameters var {{.StructVar}} {{.StructName}} //////////////////////////////////////////////////////////////////////////// // Commandline definitions func init() { // set default values for command line parameters{{range .Options}}{{if eq .Name "SEPARATOR" }} {{else}} flag.{{clk2uc .Type}}Var(&{{$.StructVar}}.{{.Name}}, "{{.Flag}}", {{.Value}}, "{{.Usage}}"){{end}}{{end}} // Now override those default values from environment variables{{range .Options}}{{if eq .Name "SEPARATOR" }} {{else}}{{if eq .Type "string" }}{{$envVar := printf "%s_%s" (clk2ss $.ProgramName) (clk2ss .Flag)}} if len({{$.StructVar}}.{{.Name}}) == 0 || len(os.Getenv("{{$envVar}}")) != 0 { {{$.StructVar}}.{{.Name}} = os.Getenv("{{$envVar}}") }{{end}}{{end}}{{end}} } {{if eqf .UsageSummary "True" }} const USAGE_SUMMARY = "{{range .Options}}{{if eq .Name "SEPARATOR" }}\n{{else}}{{$envVar := printf "%s_%s" (clk2ss $.ProgramName) (clk2ss .Flag)}} -{{.Flag}}\t{{.Usage}} ({{$envVar}})\n{{end}}{{end}}\nDetails:\n\n" {{end}} // Usage function shows help on commandline usage func Usage() { fmt.Fprintf(os.Stderr, "{{.UsageLead}}", progname){{if eq .UsageSummary "TRUE" }} fmt.Fprintf(os.Stderr, USAGE_SUMMARY){{end}} flag.PrintDefaults() fmt.Fprintf(os.Stderr, "{{.UsageEnd}}") os.Exit(0) } easygen-4.1.0/test/commandlineFlag.yaml 0000664 0000000 0000000 00000004344 13502324010 0020065 0 ustar 00root root 0000000 0000000 # program name, name for the executable ProgramName: easygen # package name # - For standalone program that does not belong to any package, e.g., # https://github.com/suntong/easygen/blob/7791e4f0e5605543d27da1671a21376cdb9dcf2a/easygen/easygen.go # just ignore the first line, the `package` output, and copy the rest # - If you don't mind using a separated file to handle commandline paramters, # then name the package as "main". see the spin-out "TF-minus1.go" file under # https://github.com/suntong/easygen/tree/d1ab0b5fe80ddac57fe9ef51f6ccb3ab998cd5ee # - If you are using it in a pacakge, look no further than # https://github.com/suntong/easygen/blob/master/easygenapi/config.go # which was a direct dump: easygen test/commandlineFlag | gofmt > easygenapi/config.go # PackageName: easygenapi # Name of the structure to hold the values for/from commandline StructName: Options # The actual variable that hold the commandline paramter values StructVar: Opts Options: - Name: HTML Type: bool Flag: html Value: false Usage: treat the template file as html instead of text - Name: TemplateStr Type: string Flag: ts Value: '""' Usage: "template string (in text)" - Name: TemplateFile Type: string Flag: tf Value: '""' Usage: ".tmpl (comma-separated) template file `name(s)` (default: same as .yaml file)" - Name: ExtYaml Type: string Flag: ey Value: '".yaml"' Usage: "`extension` of yaml file" - Name: ExtTmpl Type: string Flag: et Value: '".tmpl"' Usage: "`extension` of template file" - Name: StrFrom Type: string Flag: rf Value: '""' Usage: "replace from, the from string used for the replace function" - Name: StrTo Type: string Flag: rt Value: '""' Usage: "replace to, the to string used for the replace function" - Name: Debug Type: int Flag: debug Value: 0 Usage: "debugging `level`" # Whether to use the USAGE_SUMMARY in Usage help UsageSummary: "" UsageLead: "\\nUsage:\\n %s [flags] YamlFileName [YamlFileName...]\\n\\nFlags:\\n\\n" UsageEnd: "\\nYamlFileName(s): The name for the .yaml data and .tmpl template file\\n\\tOnly the name part, without extension. Can include the path as well.\\n" easygen-4.1.0/test/enum_c-header.tmpl 0000664 0000000 0000000 00000000512 13502324010 0017504 0 ustar 00root root 0000000 0000000 {{- if .EnumComments -}} {{- range .EnumComments }} // {{.}} {{- end -}} {{- end }} enum {{.EnumName}} { {{- range $i, $val := .Values -}} {{- if .Comment }} {{- if gt $i 0 }} {{ end }} // {{.Comment}} {{- end -}} {{- if .Value }} {{ .Name }} = {{.Value }}, {{- else }} {{ .Name }}, {{- end -}} {{- end }} }; easygen-4.1.0/test/enum_c-source.tmpl 0000664 0000000 0000000 00000001661 13502324010 0017562 0 ustar 00root root 0000000 0000000 {{/* Randomly pick the first element if no EnumDefault is set. */}} {{ with $DEFAULT := or (.EnumDefault) (index .Values 0 "Name") -}} /** Try to extract an enum {{$.EnumName}} value from @str; fall back to "{{$DEFAULT}}". */ const enum {{$.EnumName}} str_to_{{$.EnumName}}(const char const *str) { {{- range $i, $val := $.Values }} {{ if gt $i 0 -}}} else {{end -}}if (strcasecmp(str, "{{ if .String }}{{.String}}{{else}}{{.Name}}{{end}}") == 0) { return {{ .Name }}; {{- range .AltString }} } else if (strcasecmp(str, "{{.}}") == 0) { return {{ $val.Name }}; {{- end }} {{- if eq (len $.Values|minus1) ($i)}}{{/* Sentinel */}} } {{- end -}} {{- end }} return {{$DEFAULT}}; } {{- end }} /** Stringer function for {{.EnumName}}. */ const char * {{.EnumName}}_to_str(const enum {{.EnumName}} val) { switch (val) { {{- range .Values }} case {{.Name}}: return "{{ if .String }}{{.String}}{{else}}{{.Name}}{{end}}"; {{- end }} } } easygen-4.1.0/test/enum_c-to_str.tmpl 0000664 0000000 0000000 00000000366 13502324010 0017575 0 ustar 00root root 0000000 0000000 /** Stringer function for {{.EnumName}}. */ const char * {{.EnumName}}_to_str(const enum {{.EnumName}} val) { switch (val) { {{- range .Values }} case {{.Name}}: return "{{ if .String }}{{.String}}{{else}}{{.Name}}{{end}}"; {{- end }} } } easygen-4.1.0/test/enum_go.tmpl 0000664 0000000 0000000 00000006264 13502324010 0016453 0 ustar 00root root 0000000 0000000 {{/* NOTE: This produces the _same_ enum values as for C enums, as long the input format is one of: a) enum first { a, b, c} b) enum second { a = 0x5, b, c } The first is handled by iota, the other uses https://golang.org/ref/spec#ConstSpec Currently NOT supported is a mixed form: enum mixed { a, b=0x20, c, d=0x30, e } */}} import ( "database/sql/driver" "encoding/json" "fmt" ) {{ if .EnumComments -}} {{- range .EnumComments -}} // {{.}} {{- end -}} {{- else -}} // {{ cls2uc .EnumName }} is the representation of {{.EnumName -}} {{- end }} type {{ cls2uc .EnumName}} uint32 const ( {{- range $i, $j := .Values -}} {{- if .Comment }} {{- if gt $i 0 }}{{/* insert newline */}} {{ end }} // {{.Comment}} {{- end -}} {{- if eq $i 0 }} {{ .Name }} {{ cls2uc $.EnumName }} = {{if .Value}}{{.Value}} + {{end}}iota {{- else }} {{ .Name }}{{if .Value}} {{ cls2uc $.EnumName }} = {{ .Value }}{{end}} {{- end }} {{- end }} ) {{ with $type := cls2uc $.EnumName -}} {{ with $m := index (clk2ls $type) 0 | printf "%c" -}} // Implements encoding.TextMarshaler func ({{$m}} {{$type}}) MarshalText() ([]byte, error) { switch {{$m}} { {{- range $.Values }} case {{.Name}}: return []byte("{{if .String}}{{.String}}{{else}}{{.Name}}{{end}}"), nil {{- end }} } return nil, fmt.Errorf("invalid {{$type}} %d", {{$m}}) } // Implements encoding.TextUnmarshaler func ({{$m}} *{{$type}}) UnmarshalText(data []byte) error { switch string(data) { {{- range $i, $val := $.Values }} case "{{ if .String }}{{.String}}{{else}}{{.Name}}{{end}}": *{{$m}} = {{ .Name }} {{- range .AltString }} case "{{.}}": *{{$m}} = {{ $val.Name }} {{- end }} {{- end }} default: return fmt.Errorf("invalid {{$type}} %q", string(data)) } return nil } // Implements fmt.Stringer func ({{$m}} {{$type}}) String() string { if b, err := {{$m}}.MarshalText(); err != nil { return err.Error() } else { return string(b) } } // Implements database/sql/driver.Valuer func ({{$m}} {{$type}}) Value() (driver.Value, error) { return {{$m}}.String(), nil } // Implements database/sql.Scanner func ({{$m}} *{{$type}}) Scan(src interface{}) error { switch src := src.(type) { case int64: *{{$m}} = {{$type}}(src) return nil case []byte: return {{$m}}.UnmarshalText(src) case string: return {{$m}}.UnmarshalText([]byte(src)) } return fmt.Errorf("unable to convert %T to {{$type}}", src) } // Implements json.Marshaler func ({{$m}} {{$type}}) MarshalJSON() ([]byte, error) { return json.Marshal({{$m}}.String()) } // Implements json.Unmarshaler func ({{$m}} *{{$type}}) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { return fmt.Errorf("failed to parse '%s' as {{$type}}: %s", string(data), err) } return {{$m}}.UnmarshalText([]byte(s)) } // Implements yaml.Marshaler func ({{$m}} {{$type}}) MarshalYAML() (interface{}, error) { return {{$m}}.String(), nil } // Implements yaml.Unmarshaler func ({{$m}} *{{$type}}) UnmarshalYAML(unmarshal func(interface{}) error) error { var s string if err := unmarshal(&s); err != nil { return fmt.Errorf("failed to unmarshal {{$type}} from YAML: %s", err) } return {{$m}}.UnmarshalText([]byte(s)) } {{- end}} {{- end}} easygen-4.1.0/test/enum_java.tmpl 0000664 0000000 0000000 00000000636 13502324010 0016764 0 ustar 00root root 0000000 0000000 {{- if .EnumComments -}} /** {{- range .EnumComments }} * {{.}} {{- end }} */ {{- else -}} /** {{ cls2uc .EnumName }} is the representation of {{.EnumName}} */ {{- end }} public enum {{cls2uc .EnumName}} { {{- range $i, $val := .Values -}} {{- if .Comment }} {{- if gt $i 0 }} {{ end }} // {{.Comment}} {{- end }} {{ .Name }}{{if eq (len $.Values|minus1) ($i)}};{{else}},{{end}} {{- end }} } easygen-4.1.0/test/enum_multiple_data_files.ref 0000664 0000000 0000000 00000000200 13502324010 0021634 0 ustar 00root root 0000000 0000000 // Simplified enumeration of available RAID devices enum raid_type { RAID0 = 100, RAID1, }; enum raid_driver { HW, SW, }; easygen-4.1.0/test/enum_multiple_template_and_data.ref 0000664 0000000 0000000 00000000776 13502324010 0023211 0 ustar 00root root 0000000 0000000 // Simplified enumeration of available RAID devices enum raid_type { RAID0 = 100, RAID1, }; /** Stringer function for raid_type. */ const char * raid_type_to_str(const enum raid_type val) { switch (val) { case RAID0: return "RAID0"; case RAID1: return "RAID1"; } } enum raid_driver { HW, SW, }; /** Stringer function for raid_driver. */ const char * raid_driver_to_str(const enum raid_driver val) { switch (val) { case HW: return "Hardware-RAID"; case SW: return "Software-RAID"; } } easygen-4.1.0/test/enum_multiple_template_files.ref 0000664 0000000 0000000 00000001250 13502324010 0022544 0 ustar 00root root 0000000 0000000 // Simplified enumeration of available RAID devices enum raid_type { RAID0 = 100, RAID1, }; /** Try to extract an enum raid_type value from @str; fall back to "RAID0". */ const enum raid_type str_to_raid_type(const char const *str) { if (strcasecmp(str, "RAID0") == 0) { return RAID0; } else if (strcasecmp(str, "RAID-0") == 0) { return RAID0; } else if (strcasecmp(str, "RAID1") == 0) { return RAID1; } else if (strcasecmp(str, "RAID-1") == 0) { return RAID1; } return RAID0; } /** Stringer function for raid_type. */ const char * raid_type_to_str(const enum raid_type val) { switch (val) { case RAID0: return "RAID0"; case RAID1: return "RAID1"; } } easygen-4.1.0/test/example.yaml 0000664 0000000 0000000 00000000271 13502324010 0016433 0 ustar 00root root 0000000 0000000 ColorRed: red ColorBlue: blue ColorWhite: white Colorlist: red blue white Colors: - red - blue - white Cars: - Make: Ford Module: T1 - Make: GM Module: T2 easygen-4.1.0/test/html-Checkbox-Group.tmpl 0000664 0000000 0000000 00000011160 13502324010 0020573 0 ustar 00root root 0000000 0000000
This extends the Multiple Checkbox Select/Deselect Using JQuery which has an Online Demo here, which demonstrates the functionality of selecting multiple items from a list to process them.
This extends the demo further -- it now includes several groups instead merely a single one.
FYI, this full working html source code is generated automatically by easygen with this template. This html test code is the reason that I wrote easygen, to make it easy to write whatever test cases whatever the way I like. Further, changing is a breeze, you just change once and the script will do a "replace-all" for you, however complicated it can be. No any other tools can do such complicated "replace-all" for you.
easygen-4.1.0/test/html-Checkbox-Group.yaml 0000664 0000000 0000000 00000000441 13502324010 0020561 0 ustar 00root root 0000000 0000000 phone: - Type: Android Modules: - Samsung Galaxy - Droid X - HTC Desire - Type: iPhone Modules: - Apple iPhone 4 - Apple iPhone 5 - Apple iPhone 6 - Type: BlackBerry Modules: - BlackBerry Bold 9650 - BlackBerry 10 easygen-4.1.0/test/html-Checkbox-Post.tmpl 0000664 0000000 0000000 00000005535 13502324010 0020435 0 ustar 00root root 0000000 0000000Module A | Module B | Module C |
---|---|---|
Samsung Galaxy A | Samsung Galaxy B | Samsung Galaxy C |
Droid X A | Droid X B | Droid X C |
HTC Desire A | HTC Desire B | HTC Desire C |
Module A | Module B | Module C |
---|---|---|
Apple iPhone 4 A | Apple iPhone 4 B | Apple iPhone 4 C |
Apple iPhone 5 A | Apple iPhone 5 B | Apple iPhone 5 C |
Apple iPhone 6 A | Apple iPhone 6 B | Apple iPhone 6 C |
Module A | Module B | Module C |
---|---|---|
BlackBerry Bold 9650 A | BlackBerry Bold 9650 B | BlackBerry Bold 9650 C |
BlackBerry 10 A | BlackBerry 10 B | BlackBerry 10 C |
Module A | Module B | Module C |
---|---|---|
{{.}} A | {{.}} B | {{.}} C |