{"id":13711742,"url":"https://github.com/cheekybits/genny","last_synced_at":"2025-05-13T22:04:37.082Z","repository":{"id":22501733,"uuid":"25841316","full_name":"cheekybits/genny","owner":"cheekybits","description":"Elegant generics for Go","archived":false,"fork":false,"pushed_at":"2021-08-24T18:48:42.000Z","size":84,"stargazers_count":1718,"open_issues_count":27,"forks_count":126,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-04-09T19:14:20.993Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cheekybits.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-27T22:03:45.000Z","updated_at":"2025-04-04T13:48:49.000Z","dependencies_parsed_at":"2022-07-30T21:18:04.287Z","dependency_job_id":null,"html_url":"https://github.com/cheekybits/genny","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheekybits%2Fgenny","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheekybits%2Fgenny/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheekybits%2Fgenny/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheekybits%2Fgenny/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cheekybits","download_url":"https://codeload.github.com/cheekybits/genny/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251337754,"owners_count":21573429,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T23:01:11.164Z","updated_at":"2025-04-28T15:27:21.024Z","avatar_url":"https://github.com/cheekybits.png","language":"Go","funding_links":[],"categories":["Go Generate Tools","Go 生成工具","Go","Go 代码生成工具","Go生成工具","编辑器插件","Libraries for creating HTTP middlewares"],"sub_categories":["Routers","路由器","代码分析"],"readme":"# genny - Generics for Go\n\n[![Build Status](https://travis-ci.org/cheekybits/genny.svg?branch=master)](https://travis-ci.org/cheekybits/genny) [![GoDoc](https://godoc.org/github.com/cheekybits/genny/parse?status.png)](http://godoc.org/github.com/cheekybits/genny/parse)\n\nInstall:\n\n```\ngo get github.com/cheekybits/genny\n```\n\n=====\n\n(pron. Jenny) by Mat Ryer ([@matryer](https://twitter.com/matryer)) and Tyler Bunnell ([@TylerJBunnell](https://twitter.com/TylerJBunnell)).\n\nUntil the Go core team include support for [generics in Go](http://golang.org/doc/faq#generics), `genny` is a code-generation generics solution. It allows you write normal buildable and testable Go code which, when processed by the `genny gen` tool, will replace the generics with specific types.\n\n  * Generic code is valid Go code\n  * Generic code compiles and can be tested\n  * Use `stdin` and `stdout` or specify in and out files\n  * Supports Go 1.4's [go generate](http://tip.golang.org/doc/go1.4#gogenerate)\n  * Multiple specific types will generate every permutation\n  * Use `BUILTINS` and `NUMBERS` wildtype to generate specific code for all built-in (and number) Go types\n  * Function names and comments also get updated\n\n## Library\n\nWe have started building a [library of common things](https://github.com/cheekybits/gennylib), and you can use `genny get` to generate the specific versions you need.\n\nFor example: `genny get maps/concurrentmap.go \"KeyType=BUILTINS ValueType=BUILTINS\"` will print out generated code for all types for a concurrent map. Any file in the library may be generated locally in this way using all the same options given to `genny gen`.\n\n## Usage\n\n```\ngenny [{flags}] gen \"{types}\"\n\ngen - generates type specific code from generic code.\nget \u003cpackage/file\u003e - fetch a generic template from the online library and gen it.\n\n{flags}  - (optional) Command line flags (see below)\n{types}  - (required) Specific types for each generic type in the source\n{types} format:  {generic}={specific}[,another][ {generic2}={specific2}]\n\nExamples:\n  Generic=Specific\n  Generic1=Specific1 Generic2=Specific2\n  Generic1=Specific1,Specific2 Generic2=Specific3,Specific4\n\nFlags:\n  -in=\"\": file to parse instead of stdin\n  -out=\"\": file to save output to instead of stdout\n  -pkg=\"\": package name for generated files\n  -tag=\"\": build tag that is stripped from output\n```\n\n  * Comma separated type lists will generate code for each type\n\n### Flags\n\n  * `-in` - specify the input file (rather than using stdin)\n  * `-out` - specify the output file (rather than using stdout)\n\n### go generate\n\nTo use Go 1.4's `go generate` capability, insert the following comment in your source code file:\n\n```\n//go:generate genny -in=$GOFILE -out=gen-$GOFILE gen \"KeyType=string,int ValueType=string,int\"\n```\n\n  * Start the line with `//go:generate `\n  * Use the `-in` and `-out` flags to specify the files to work on\n  * Use the `genny` command as usual after the flags\n\nNow, running `go generate` (in a shell) for the package will cause the generic versions of the files to be generated.\n\n  * The output file will be overwritten, so it's safe to call `go generate` many times\n  * Use `$GOFILE` to refer to the current file\n  * The `//go:generate` line will be removed from the output\n\nTo see a real example of how to use `genny` with `go generate`, look in the [example/go-generate directory](https://github.com/cheekybits/genny/tree/master/examples/go-generate).\n\n## How it works\n\nDefine your generic types using the special `generic.Type` placeholder type:\n\n```go\ntype KeyType generic.Type\ntype ValueType generic.Type\n```\n\n  * You can use as many as you like\n  * Give them meaningful names\n\nThen write the generic code referencing the types as your normally would:\n\n```go\nfunc SetValueTypeForKeyType(key KeyType, value ValueType) { /* ... */ }\n```\n\n  * Generic type names will also be replaced in comments and function names (see Real example below)\n\nSince `generic.Type` is a real Go type, your code will compile, and you can even write unit tests against your generic code.\n\n#### Generating specific versions\n\nPass the file through the `genny gen` tool with the specific types as the argument:\n\n```\ncat generic.go | genny gen \"KeyType=string ValueType=interface{}\"\n```\n\nThe output will be the complete Go source file with the generic types replaced with the types specified in the arguments.\n\n## Real example\n\nGiven [this generic Go code](https://github.com/cheekybits/genny/tree/master/examples/queue) which compiles and is tested:\n\n```go\npackage queue\n\nimport \"github.com/cheekybits/genny/generic\"\n\n// NOTE: this is how easy it is to define a generic type\ntype Something generic.Type\n\n// SomethingQueue is a queue of Somethings.\ntype SomethingQueue struct {\n  items []Something\n}\n\nfunc NewSomethingQueue() *SomethingQueue {\n  return \u0026SomethingQueue{items: make([]Something, 0)}\n}\nfunc (q *SomethingQueue) Push(item Something) {\n  q.items = append(q.items, item)\n}\nfunc (q *SomethingQueue) Pop() Something {\n  item := q.items[0]\n  q.items = q.items[1:]\n  return item\n}\n```\n\nWhen `genny gen` is invoked like this:\n\n```\ncat source.go | genny gen \"Something=string\"\n```\n\nIt outputs:\n\n```go\n// This file was automatically generated by genny.\n// Any changes will be lost if this file is regenerated.\n// see https://github.com/cheekybits/genny\n\npackage queue\n\n// StringQueue is a queue of Strings.\ntype StringQueue struct {\n  items []string\n}\n\nfunc NewStringQueue() *StringQueue {\n  return \u0026StringQueue{items: make([]string, 0)}\n}\nfunc (q *StringQueue) Push(item string) {\n  q.items = append(q.items, item)\n}\nfunc (q *StringQueue) Pop() string {\n  item := q.items[0]\n  q.items = q.items[1:]\n  return item\n}\n```\n\nTo get a _something_ for every built-in Go type plus one of your own types, you could run:\n\n```\ncat source.go | genny gen \"Something=BUILTINS,*MyType\"\n```\n\n#### More examples\n\nCheck out the [test code files](https://github.com/cheekybits/genny/tree/master/parse/test) for more real examples.\n\n## Writing test code\n\nOnce you have defined a generic type with some code worth testing:\n\n```go\npackage slice\n\nimport (\n  \"log\"\n  \"reflect\"\n\n  \"github.com/stretchr/gogen/generic\"\n)\n\ntype MyType generic.Type\n\nfunc EnsureMyTypeSlice(objectOrSlice interface{}) []MyType {\n  log.Printf(\"%v\", reflect.TypeOf(objectOrSlice))\n  switch obj := objectOrSlice.(type) {\n  case []MyType:\n    log.Println(\"  returning it untouched\")\n    return obj\n  case MyType:\n    log.Println(\"  wrapping in slice\")\n    return []MyType{obj}\n  default:\n    panic(\"ensure slice needs MyType or []MyType\")\n  }\n}\n```\n\nYou can treat it like any normal Go type in your test code:\n\n```go\nfunc TestEnsureMyTypeSlice(t *testing.T) {\n\n  myType := new(MyType)\n  slice := EnsureMyTypeSlice(myType)\n  if assert.NotNil(t, slice) {\n    assert.Equal(t, slice[0], myType)\n  }\n\n  slice = EnsureMyTypeSlice(slice)\n  log.Printf(\"%#v\", slice[0])\n  if assert.NotNil(t, slice) {\n    assert.Equal(t, slice[0], myType)\n  }\n\n}\n```\n\n### Understanding what `generic.Type` is\n\nBecause `generic.Type` is an empty interface type (literally `interface{}`) every other type will be considered to be a `generic.Type` if you are switching on the type of an object. Of course, once the specific versions are generated, this issue goes away but it's worth knowing when you are writing your tests against generic code.\n\n### Contributions\n\n  * See the [API documentation for the parse package](http://godoc.org/github.com/cheekybits/genny/parse)\n  * Please do TDD\n  * All input welcome\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheekybits%2Fgenny","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcheekybits%2Fgenny","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheekybits%2Fgenny/lists"}