Giter Site home page Giter Site logo

gen's Introduction

What’s this?

gen is a code-generation tool for Go. It’s intended to offer generics-like functionality on your types. Out of the box, it offers offers LINQ/underscore-inspired methods.

It also offers third-party, runtime extensibility via typewriters.

Changelog

Hey, a video

‼️

This project is deprecated. It won't work with recent versions of Go, and...Go now has proper generics! Treat this project as a historical curiosity.

Typewriters

There is a list of open-source typewriters in TYPEWRITERS.md. Please add your own.

Contributing

There are three big parts of gen.

gen

This repository. The gen package is primarily the command-line interface. Most of the work is done by the typewriter package, and individual typewriters.

typewriter

The typewriter package is where most of the parsing, type evaluation and code generation architecture lives.

typewriters

Typewriters are where templates and logic live for generating code. Here’s set, which will make a lovely Set container for your type. Here’s slice, which provides the built-in LINQ-like functionality. Here’s stringer, a fork of Rob Pike’s tool.

Third-party typewriters are added easily by the end user. You publish them as Go packages for import. Learn more...

We’d love to see typewriter packages for things like strongly-typed JSON serialization, Queues, Pools or other containers. Anything “of T” is a candidate for a typewriter.

gen's People

Contributors

aybabtme avatar bryant1410 avatar clipperhouse avatar drathier avatar francoishill avatar freeeve avatar heijmans avatar ikarishinjieva avatar infogulch avatar mjibson avatar toqueteos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gen's Issues

gen again

A command which re-generates all the _gen.go files in the current folder.

Each gen file currently includes the command used to generate it as the first-line comment.

gen again might, in its simplest implementation, simply iterate all *_gen.go files, extract the command from the comment, and re-run it.

An enhancement might add the ability to take a wildcard (regex?), to only re-gen a subset of files. Something like gen again movie*

Another enhancement might include a -r flag to recurse down the folder hierarchy.

typewriters require build pkg files, not just source

New typewriter gen requires that there are build package files (.a files in $GOPATH/pkg) to run. Otherwise it panics: "panic: tsdb.go:21:2: could not import github.com/StackExchange/slog (can't find import: github.com/StackExchange/slog)".

Reproduce by rm -rf $GOPATH/pkg. Run gen to see the error. Then go install . in whatever the missing package was. Rerun gen to see it work.

Should ignore generate files

When generating files, it would be convenient if gen -all would ignore files that match .*_gen.go, otherwise :

bash-3.2$ gen -*all
  generated Movies, yay!
  generated Movieses, yay!
  generated Things, yay!
  generated Thing2s, yay!
  generated Thing2ses, yay!
  generated Thingses, yay!
  generated tests, yay!
  generated testses, yay!
bash-3.2$ gen -*all
  generated Movies, yay!
  generated Movieseses, yay!
  generated Things, yay!
  generated Thing2s, yay!
  generated Thing2ses, yay!
  generated Thingses, yay!
  generated Thingseses, yay!
  generated tests, yay!
  generated testseses, yay!
  generated Movieses, yay!
  generated Thing2seses, yay!
  generated testses, yay!
bash-3.2$ gen -*all
  generated Thingseseses, yay!
  generated tests, yay!
  generated Movies, yay!
  generated Movieses, yay!
  generated Movieseses, yay!
  generated Movieseseses, yay!
  generated Thing2ses, yay!
  generated Thing2seses, yay!
  generated testses, yay!
  generated testseseses, yay!
  generated Things, yay!
  generated Thing2seseses, yay!
  generated Thingses, yay!
  generated Thing2s, yay!
  generated Thingseses, yay!
  generated testseses, yay!
bash-3.2$

Questions and Ideas

I think templating (parameterization) by type at the package/import level is better than at the function level. Although you seem to have not exactly done either, or both. In any case it looks much better than the C++ style of templates.

  1. How would one do a variety of in-order, depth-first et cetera walking of trees or graphs and putting elements or their pointers into a linear list or array? Or fed to a channel?
  2. I was imagining something like:
    import "redblack".{{Goober}} with Type {{Thing}} as Type Goober, const {{Max}} as 512
    This could have several things as parameters, which would be useful. Being careful not to have multiple generated packages with the same name.
  3. Supporting containers and algorithms but leaving aside meta-programming seems like the right idea.

Plain Sort for ordered types

Currently (on the projection branch), we have a standard method for SortBy, which takes a func to define less.

Many types can simply be evaluated as greater or less (‘ordered’ in Go’s terminology). Create a Sort method, which does not require a passed func, for types that pass the test of being ordered.

This will not require the big re-implemented Sort template; rather just satisfy the sort package’s Interface for these types, and wrap in a simple method that returns a sorted copy (instead of sorting in place).

Pull in typewriter package

See the typewriter branch for context.

On this branch, we split out a typewriter package which subsumes most of gen’s core functionality.

I think the name is good and the concept is clear, but it doesn’t need to be in a separate package, does it? I suggest we just bring all that functionality back into the main gen package.

The types and concept remain, they’ll just be gen.TypeWriter instead of typewriter.TypeWriter. gen will be an install and an import.

It’s one less thing to keep in sync, too.

Individual typewriters (“codecs”) remain their own packages and can live anywhere.

Thoughts?

error message (import)

In my package github.com/pierrre/geohash
I try to create a slice of Point (https://github.com/pierrre/geohash/blob/master/geohash.go#L113-L116).

But gen returns an error:

➜  geohash git:(master) ✗ gen
geohash_benchmark_test.go:6:18: could not import github.com/Codefor/geohash (can't find import: github.com/Codefor/geohash)
exit status 1

or

➜  geohash git:(master) ✗ gen
cstest_test.go:6:2: could not import github.com/pierrre/cstest (can't find import: github.com/pierrre/cstest)
exit status 1

gen panics

Hi. Not quite sure what is going on here. I'm using go 1.3.3 on a very very simple file:

main.go

package main

import "fmt"

// +gen
type MyStruct struct {
Name string
}

func main() {
fmt.Println("hello world")

}

Any thoughts??? Much appreciated.

panic: no Config.Import or DefaultImport (missing import _ "golang.org/x/tools/go/gcimporter"?) [recovered]
panic: no Config.Import or DefaultImport (missing import _ "golang.org/x/tools/go/gcimporter"?)

goroutine 16 [running]:
runtime.panic(0x244380, 0x2085dcc00)
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/runtime/panic.c:279 +0xf5
code.google.com/p/go.tools/go/types.(_Checker).handleBailout(0x208614f70, 0x220878e7f8)
/Users/dw/Documents/Code/getfastbar.server/src/code.google.com/p/go.tools/go/types/check.go:218 +0xcd
runtime.panic(0x244380, 0x2085dcc00)
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/runtime/panic.c:248 +0x18d
code.google.com/p/go.tools/go/types.(_Checker).collectObjects(0x208614f70)
/Users/dw/Documents/Code/getfastbar.server/src/code.google.com/p/go.tools/go/types/resolver.go:134 +0xb0
code.google.com/p/go.tools/go/types.(_Checker).Files(0x208614f70, 0x208628130, 0x1, 0x1, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/code.google.com/p/go.tools/go/types/check.go:228 +0xb7
code.google.com/p/go.tools/go/types.(_Config).Check(0x208684540, 0x2085dca40, 0x4, 0x208627240, 0x208628130, 0x1, 0x1, 0x0, 0x23932, 0x0, ...)
/Users/dw/Documents/Code/getfastbar.server/src/code.google.com/p/go.tools/go/types/api.go:336 +0xbf
code.google.com/p/go.tools/go/types.Check(0x2085dca40, 0x4, 0x208627240, 0x208628130, 0x1, 0x1, 0x0, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/code.google.com/p/go.tools/go/types/api.go:42 +0xa2
github.com/clipperhouse/gen/typewriter.getPackage(0x208627240, 0x2086844e0, 0x220878ec10, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/typewriter/package.go:29 +0x1e5
github.com/clipperhouse/gen/typewriter.getTypes(0x311640, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/typewriter/parse.go:24 +0x1e3
github.com/clipperhouse/gen/typewriter.NewAppFiltered(0x311640, 0x4, 0x0, 0x0, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/typewriter/app.go:37 +0x86
github.com/clipperhouse/gen/typewriter.NewApp(0x311640, 0x4, 0xffffffffffffffff, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/typewriter/app.go:28 +0x4c
main.runStandard(0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/run.go:21 +0x54
main.execute(0x415218, 0x208684150, 0x3, 0x3, 0x41d0d0, 0x26b, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/execute.go:25 +0x195
main.run(0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/run.go:17 +0xa7
main.runMain(0x2085dc000, 0x1, 0x1, 0x0, 0x0)
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/main.go:21 +0x44
main.main()
/Users/dw/Documents/Code/getfastbar.server/src/github.com/clipperhouse/gen/main.go:15 +0x8d

A more explicit API?

The current gen API is designed to get you going with a minimum of effort. Simply by adding a // +gen directive above your type, you get a whole bunch of Linq-y (underscore-y) methods right out of the box.

While that’s a nice demo and first experience, I am thinking it’s not ideal.

First, it creates a bunch of methods you may never use, which is bloat.

Second, it’s not very Go-ish. I think we value explicitness over magic. You can subset them, // +gen methods:"Any,Count,Where", but…

If you also want projection methods, you use a special tag, indicating types, eg projections:"int,Foo". This tag then looks at the methods you’ve specified (or not) and basically multiplies the types and the methods.

Combinatorially, it can be a lot. Explaining (and implementing) the interaction of methods × types is messy.

I propose that all methods should be explicit (no magic) and combined into a single tag. It would look something like:

// +gen slice:"Count,Where,GroupBy<Foo>,SortBy<int>"

This is a breaking change, but perhaps better for the long term. Thoughts?

Change the generated methods to operate on pointers to reduce copying

gen currently creates code that uses a value receiver, for example

func (rcv Things) All(fn func(Thing) bool) bool {
    for _, v := range rcv {
        if !fn(v) {
            return false
        }
    }
    return true
}

Every time the All method is invoked, the collection is copied and the method is applied to the copy. This is fine for small collections, but imposes a copy overhead that will become increasingly significant for larger collection sizes.

We can solve this using pointer receivers, for example

func (rcv *Things) All(fn func(Thing) bool) bool {
    for _, v := range *rcv {
        if !fn(v) {
            return false
        }
    }
    return true
}

The call sites don't need to be changed to use this.

Remove _gen files that are not gen'd

If a user removes the +gen tag for a previously gen’d type, the gen’d file should go away on the next gen. Maybe a command line flag or prompt for safety.

Negative subsetting

Subsetting is currently “positive”-only, which is to say, if any subsetting is indicated, it will only gen those methods.

One might wish instead to gen everything “except for” indicated methods. Allow something like methods:"-Sort,-Count" or perhaps methods:-"Sort,Count" to indicate everything except Sort and Count.

(Can only support positive xor negative in a given tag; can’t do both, that’s an ambiguous syntax.)

-watch flag

Using (presumably) fsnotify, offer a -watch flag to automatically run gen on file changes.

This would be nice for having directive changes be immediately implemented. It might cover some use cases mentioned in #65.

We will probably desire some throttling because text editors like Sublime fire a lot of events for a simple file change. See https://github.com/go-fsnotify/fsnotify/issues/17.

Error message that code must be compilable before gen will work

It seems that gen will not if the current package is not compilable. This caused me some confusion as I was refactoring some hand-duplicated code to use gen. I first tried it with one type and it worked. So then I deleted all my hand implementations and added the annotations to generate them.

But now gen would fail with what looks like a compile error that my types I wanted to generate were not found (because the rest of my original package depended on what I now wanted gen to generate for me). Confusing to be told that it is failing because Foo is not defined when gen is supposed to generate Foo.

Finally I figured out that gen must be parsing the Go code to read out the annotations and that was what was failing.

It'd be nice to get an error message that gen needs a compilable project before it can generate code instead of just getting what looks like a Go build error.

On the bright side, overall gen is easy to use and extend. Even with this I was able to refactor my hand-duplicated code to use gen (including a custom typewriter) in about an hour and a half.

clipperhouse/typewriter/template.go Parse should allow to use FuncMap

I created a typewriter for my needs, however I run into issues with import as the typewriter doesn't allow currently to inject a function to a template like the following:

{{ .Type | ToLower }}.{{.Type}}

So that the generated file looks like something like contact.Contact.

However I was able to copy the ByTagValue function and created the local function:

func CustomByTagValue(ts typewriter.TemplateSlice, t typewriter.Type, v typewriter.TagValue) (*template.Template, error) {
....
funcMap := template.FuncMap{
"ToLower": func(t typewriter.Type) string {
return strings.ToLower(t.Name)
},
}
// eagerly return on success
return template.New(tmpl.Name).Funcs(funcMap).Parse(tmpl.Text)
....

}

If you change your clipperhouse/typewriter/template.go Parse method to take FuncMap as argument, it won't be a problem, at least for me. Thanks for the great work.

Plain Max & Min for ordered types

Currently, we have standard methods for MaxBy and MinBy, which take func’s to define less.

Many types can simply be evaluated as greater or less (‘ordered’ in Go’s terminology). Create methods, which do not require a passed func, for types that pass the test of being ordered.

Add deprecation messaging

Two API features have been deprecated in favor of #23. Would like to add messaging for users if they attempt to use them.

  • Types are no longer specified at the command line. If a command argument looks like a type, give a message.
  • Struct tags gen:"..." for custom methods have been deprecated. If detected, give a message.

Organized system for user-added algorithms and containers.

If I want to add or invent, a priority-queue or arithmetic-coding or something, for my project, which conceivably could be closed-source, I'll need an organized, documented and supported place to put my templates. At least.

If gen is limited to canned code then its usefulness is curtailed.

Great stuff so far.

Generate comments that won't make `go lint` cry

Go lint will complain if the comments of func/methods doesn't follow the MethodName does something something, as defined in Effective Go:

http://golang.org/doc/effective_go.html#commentary

And enforced by the tool:

https://github.com/golang/lint/blob/master/lint.go#L485

// Add does the addition of a with b
func Add(a, b int) int {
    return a + b
}

I'm opening the issue so that:

  1. If you care and want to do it, you can.
  2. If you care but don't want to do it, I can.
  3. If you don't care, then at least that will settle the question ^^.

Import errors

It seems that if my package imports a 3rd-party (i.e., not standard lib) package, the importer can't handle it:

$ cd $GOPATH/src/code.google.com/p/go.tools/imports
$ gen

error: fix.go:19:2: could not import code.google.com/p/go.tools/astutil (can't find import: code.google.com/p/go.tools/astutil)

go get failed

There is a problem after commit 1947dfa. Command

go get github.com/clipperhouse/gen
ends with error:
package github.com/clipperhouse/gen
    imports gen/inflect: unrecognized import path "gen/inflect"
because real path is _github.com/clipperhouse/gen/inflect_

Plans [spring 2014]

Just an update and request for feedback. Have a look at the typewriter branch for context.

gen will become a small shell and specific codegen libraries are included like “codecs” or “drivers”, mirroring the pattern in image and database/sql packages in the standard library.

My immediate milestone is to achieve parity with the existing gen under this new pattern. If users don’t see the change, great. Probably 90% there (on the branch).

It opens up the possibility of people making their own ‘gen’ with any code generator they want. Maybe Json? Trees? Fork it and change a few imports. Then the choice of ‘blessed’ typewriters not up to me! :)

But I have some even more-evil plans here – the typewriters would live as imports in the user’s codebase, not in the gen binary. That’ll be some voodoo.


Update: that latter bit of evil has been implemented on the typewriter branch thanks to @wfreeman. Experimental.

Webpage on iphone

image

How your site looks on an iphone when I try to zoom in to read the text :(

Fix would be appreciated.

gen get

See the typewriter branch for context.

Because the new architecture of gen depends on external typewriters, the user must get them prior to using gen. This is true for the default typewriters too.

Support a gen get [-u] command. As is done in main() now, the the files are written to a temp directory, but instead of invoking go run (via os.Command), invoke go get.

go test broke: can't find foowriter

With a fresh checkout:

% go test
_gen_test.go:4:4: could not import github.com/clipperhouse/gen/typewriters/foowriter (can't find import: github.com/clipperhouse/gen/typewriters/foowriter)
exit status 1
--- FAIL: TestList (1.01 seconds)
    list_test.go:60: exit status 1
    list_test.go:65: standard list should output 4 lines, got 0
  Writing dummy_gen_test.go
_gen_test.go:4:4: could not import github.com/clipperhouse/gen/typewriters/foowriter (can't find import: github.com/clipperhouse/gen/typewriters/foowriter)
exit status 1
--- FAIL: TestRun (0.97 seconds)
    run_test.go:63: exit status 1
    run_test.go:68: open dummy_foo_test.go: no such file or directory
FAIL
exit status 1
FAIL    github.com/clipperhouse/gen 2.144s

API change: markup only, don’t specify type at command line?

An idea occurred to me, that perhaps specifying a type at the command line is not necessary, and can be completely specified by marking up the type.

Currently, to gen for package.Type, you’d use gen package.Type. What if instead we used a comment along the lines of:

// +gen
type MyType struct{}

…and then simply type gen at the command line, which will pick up the type? Subsetting and projection could happen as usual, if desired:

// +gen methods:"Any,Where,Count" projections:"string"
type MyType struct{}

This is attractive because re-gen’ing is simpler. Just change the markup and gen.

A few things to work out.

How to specify a pointer? Currently it’s gen *package.Type, which is intuitive. Maybe:

// +gen pointer methods:"Any,Where,Count" projections:"string"

or

// +gen *

The above would also imply deprecation of the -all tag.

Also attractive because this give us room to grow by adding tags such as containers as has been suggested: #14

Thoughts?

v4

v3 is out the door, some goals for v4.

Primarily, I want to deprecate the current genwriter and replace it with a more explicit slicewriter, see here for details.

I’ll rename genwriter to classic. It will continue to be a built-in typewriter in this release, outputting a deprecation warning when it’s used.

I’ll recommend that users who wish to continue using it include it as a custom typewriter in _gen.go. It will remain available on GitHub indefinitely, but will be removed as a built-in typewriter in a future release.

Another possible feature is to add a Tags() method to the typewriter interface. Typewriters will be required to explicitly declare which Tags & Items that they support.

Since this is a custom syntax, we need to know what values are valid. If some tag or value is unknown to the registered typewriters, gen should return an error. Currently we can’t, since we lack the information.

This will also prevent a class of validation errors where a typewriter is called even though it will not write anything. We currently depend on the typewriter's Validate() method being correct, a potential quality issue. Would rather put the burden on typewriters to declare what they intend.

Also, the docs need an update to reflect the notion of typewriters, the new commands, and _gen.go.

Containers

Although the LINQ-like features are useful, I find myself more often desiring and building containers to hold my structs. container/list provides stack and queue-like functions, although I've always just done it myself because it's not too complicated and I'd prefer to not type assert. There is no set or hash container, so I use maps to achieve the same functionality. Would it make sense to have gen able to generate such containers? I'm opening this up as more of an idea discussion than a feature request.

Generic Generics

I'm trying to figure out how to create a map[String]Generic where different generic types can be contained in one map exposing their Where(), Count(), Any(), Select(), etc, functions.

Is this something feasible using this Go generics implementation or am I just asking a nonsense question?

Add 'Equals' function to compare two Things.

There is no easy way to compare two collections of Things.

It is not hard to write a loop by hand that does it, and reflect.DeepEqual could be used. However, gen is harder to use without a generated Equals method.

Also, the generated code will be compile-time type checked, so will run ever so slightly faster than the reflect approach.

Verbose output

Create a -v(erbose) command-line flag to give output describing the steps and methods being created. This will be helpful for troubleshooting, e.g., to explain why certain methods are not generated for, e.g., non-numeric or non-ordered types.

Invalid generation for structs with map fields

Given the test program:

package main

// +gen
type T struct {
    B map[string]interface{}
}

func main() {

}

gen currently generates invalid go code. Specifically these errors:

./t_gen.go:97: invalid operation: a != b (struct containing map[string]interface {} cannot be compared)
./t_gen.go:111: invalid operation: rcv[i] != rcv[m] (struct containing map[string]interface {} cannot be compared)
./t_gen.go:176: invalid operation: a != b (struct containing map[string]interface {} cannot be compared)

Each one is an attempt to compare two values of type T with !=. This is invalid because of the map field. They are generated in IsSortedByDesc, MaxBy, and SortByDesc.

Code with conditional compile is not supported.

If both A_linux.go and A_windows.go have a function with same name, gen will report redeclared function.

With -f option, gen will gen an empty []A type.

In my case, the "conditional" part have no impact on gen output.

If the "conditional" part have impact on gen output, maybe gen should gen code with conditional compile

Parse type-level comments for use similar to tags

We’re using struct tags to allow a user to specify custom methods at the field level. We’d like the ability to mark up the struct type with similar metadata to, e.g., specify which standard methods to gen, or to override the pluralization.

I propose to do this with comments of a standard format. I propose that the format be the same as the struct tags, looking something like this:

type Thing struct {
    // gen:"Count,Where"                         <-- proposed
    Field1 string `gen:"Average,GroupBy"`        <-- already supported
}

Take first n elements

Today I encountered a case where I wanted to take the first n elements from a slice.
With the slice[low:high] notation you have to first check, whether the slice has n elements, which makes this simple operation rather long.

thingsToTake := 7
if len(things) > thingsToTake {
  things = things[0:thingsToTake]
}

Do you think, such a feature would be appropriate for gen?

Implement a real parser for tags

Tags, of the pattern foo:"Bar,Baz" are currently parsed with regex. It’s reasonably correct but not good.

Bar & Baz above are returned as Tag.Items, which is simply a []string. The individual typewriters are then free to interpret them, as (say) a method or a type.

v4 will require an extended syntax that will not play well with the current regex and so it’s a good time to create a real parser.

The new syntax is foo:"Bar,Baz[int]", adding one type parameter between brackets. (Regex gets a bit desperate here trying to distinguish commas between items, and commas within [ ].)

Tag.Items will probably need to become []Item, where an item is:

type Item struct {
  Name string,
  TypeParameters []string,
}

The parser doesn’t need to know if the type parameters are meaningful, it simply needs to understand the syntax. The need to be valid Go identifiers. They are passed to individual typewriters for further evaluation.

Project fields or types?

Projections present a bit of an issue in gen, which we’ve addressed with custom methods. These work well in allowing projection for specific member fields of a struct.

But now I am thinking that projecting specific members by name is not the future, and that projecting by type is better.

For one, projection by field can feel very redundant. If your struct has several string fields, projecting each of those results in nearly-identical methods.

Secondly, one can only project on one field at a time. What if we have a FirstName and LastName field and want to ad-hoc project on a full name, which concatenates them?

Thirdly, it only works for structs! gen wants to expand to other types.

Fourthly, it’s not idiomatic gen. gen is about passing in ad-hoc funcs to get want you want, offering functionality to a type. The above ain’t that.

Have a look at what we do now, and compare to:

// gen:"Where,GroupBy,Select" project:"string,OtherType"
type Thing struct {
    Name string
    Country string
    Score int
}

...which would result in:

func (rcv Things) SelectString(func (*Thing) string) []string
func (rcv Things) GroupByString(func (*Thing) string) map[string]Things

func (rcv Things) SelectOtherType(func (*Thing) OtherType) []OtherType
func (rcv Things) GroupByOtherType(func (*Thing) OtherType) map[OtherType]Things

In a nutshell, field tags (specifying methods) go away, replaced with a new project tag (specifying types). All methods move to the gen tag. So, grouping by country would be:

tisOfThee := myThings.GroupByString(func (t *Thing) string {
    return t.Country
})

Thoughts?

Regenerate `movie_gen.go` at every test run

In test/, movie_gen.go is tested by movie_test.go. However the file is not regenerated at each run of go test, so it's easy to miss errors introduced in the tool when running the tests.

Allow code generation for primitive types

It would be nice to have an easy way to generate collections of strings, ints etc.

Even though there is only a small set of Go primitive types, generating the collections for them using gen would be a bit better than hand-coding because future developments of gen could be made use of with very little effort (just run gen again).

Asterisk in file names

If I use gen to create a type on a pointer like so:

// +gen *
type T struct {
    A int
}

The file that is generated is called *t_gen.go. This works fine with the standard go build system, but on Google AppEngine those files are not compiled into the final binary, so you end up with undefined type errors anywhere you use the new type.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.