Skip to content

Commit d3f11f2

Browse files
committed
Merge pull request #72 from clipperhouse/v4
v4
2 parents a8c0fc4 + fffc790 commit d3f11f2

69 files changed

Lines changed: 410 additions & 6674 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ coverage.out
55
*_bar_test.go
66
*_foo.go
77
*_foo_test.go
8+
9+
_site/*

CHANGELOG.md

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,87 @@
1-
###28 Jun 2014
1+
###30 Nov 2014 (v4)
2+
3+
To get the latest: `go get -u github.com/clipperhouse/gen`. Type `gen help` to see commands.
4+
5+
This release has several substantial changes.
6+
7+
####Type parameters
8+
9+
Tags now have support for type parameters, for example:
10+
11+
// +gen foo:"Bar[qux], Qaz[thing, stuff]"
12+
// type MyType struct{}
13+
14+
Those type paramters (qux, thing, stuff) are properly evaluated as types. Which not only increases safety, but gives more information to typewriters.
15+
16+
####Type constraints
17+
18+
Speaking of above, types are evaluated for Numeric, Ordered and Comparable. Templates, in turn, can have type constraints.
19+
20+
So, you can declare your Sum template only to be applicable to Numeric types, and your Set to Comparable types.
21+
22+
####gen add
23+
24+
Third-party typewriters are added to your package using a new command, `add`. It looks like this:
25+
26+
gen add github.com/clipperhouse/setwriter
27+
28+
That’s a plain old Go import path.
29+
30+
After adding, you can mark up a type like:
31+
32+
// +gen set slice:"GroupBy[string], Select[Foo]"
33+
// type MyType struct{}
34+
35+
As always, it’s up to the third-party typewriter to determine behavior. In this case, a “naked” `set` tag is enough.
36+
37+
We deprecated the unintuitive `gen custom` command, `add` replaces it.
38+
39+
####Explcitness
40+
41+
Previous versions of gen would generate a dozen or so LINQ-style slice methods simply by marking up:
42+
43+
// +gen
44+
// type MyType struct{}
45+
46+
We’ve opted for explicitness moving forward – in the case of slices, you’ll write this instead:
47+
48+
// +gen slice:"Where, SortBy, Any"
49+
// type MyType struct{}
50+
51+
In other words, only the methods you want.
52+
53+
####Projections
54+
55+
Certain methods, such as Select and GroupBy require an additional type parameter. I won’t bore you with the convoluted old way. Now it’s:
56+
57+
// +gen slice:"GroupBy[string], Select[Foo]"
58+
// type MyType struct{}
59+
60+
Those type parameters are properly evaluated, and typewriters get full type information on them.
61+
62+
####slice
63+
64+
The main built-in typewriter used to be called `genwriter`, it is now called `slice`. Instead of the generated slice type being called Things, it’s now called ThingSlice.
65+
66+
[slice](https://github.com/clipperhouse/slice) is now the only built-in typewriter.
67+
68+
We’ve deprecated the built-in container typewriter, instead splitting it into optional [Set](https://github.com/clipperhouse/set), [List](https://github.com/clipperhouse/linkedlist) and [Ring](https://github.com/clipperhouse/ring) typewriters. How to add optional typewriters, you ask?
69+
70+
####Smaller interface
71+
72+
For those developing their own typewriters: the [`TypeWriter` interface](https://github.com/clipperhouse/typewriter/blob/master/typewriter.go) got smaller. It’s now:
73+
74+
type TypeWriter interface {
75+
Name() string
76+
Imports(t Type) []ImportSpec
77+
Write(w io.Writer, t Type) error
78+
}
79+
80+
`Validate` is gone, it was awkward. The easy fix there was to allow Write to return an error. `WriteHeader` is gone, there was little use for it in practice. `WriteBody` is now simply `Write`.
81+
82+
Let me (@clipperhouse) know if any questions.
83+
84+
###28 Jun 2014 (v3)
285

386
To get the latest: `go get -u github.com/clipperhouse/gen`. Type `gen help` to see commands.
487

@@ -12,8 +95,8 @@ Prior to this release, typewriters were simply part of the `gen` binary. Now, by
1295
package main
1396
1497
import (
15-
_ "github.com/clipperhouse/gen/typewriters/container"
16-
_ "github.com/clipperhouse/gen/typewriters/genwriter"
98+
_ "github.com/clipperhouse/containerwriter"
99+
_ "github.com/clipperhouse/typewriters/genwriter"
17100
)
18101
```
19102

README.md

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
## What’s this?
22

3-
`gen` is a code-generation tool for Go. It’s intended to offer generics-like functionality on your types.
3+
`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.
44

5-
Out of the box, it offers LINQ/underscore/js-inspired methods as well as some handy containers.
6-
7-
It also offers third-party, runtime extensibility via [typewriters](http://godoc.org/github.com/clipperhouse/gen/typewriter).
5+
It also offers third-party, runtime extensibility via [typewriters](https://github.com/clipperhouse/typewriter).
86

97
####[Introduction and docs…](http://clipperhouse.github.io/gen/)
108

119
[Changelog](https://github.com/clipperhouse/gen/blob/master/CHANGELOG.md)
1210

13-
[Unstable branch](https://github.com/clipperhouse/gen/tree/v4)
11+
###Contributing
1412

15-
## Contributing
13+
There are three big parts of `gen`.
1614

17-
It’s early days and the API is likely volatile, ideas and contributions are welcome. Have a look at the design principles below. Feel free to [open an issue](//github.com/clipperhouse/gen/issues), send a pull request, or ping Matt Sherman [@clipperhouse](http://twitter.com/clipperhouse).
15+
####gen
1816

19-
## Design principles for contributors
17+
This repository. The gen package is primarily the command-line interface. Most of the work is done by the typewriter package, and individual typewriters.
2018

21-
This library exists to provide readability and reduce boilerplate in users’ code. It’s intended to reduce the number of explicit loops, by instead passing func’s as you would with C#’s Linq, JavaScript’s Array methods, or the underscore library. If it feels like piping, that’s good.
19+
####typewriter
2220

23-
It’s intended to fit well with idiomatic Go. Explicitness and compile-time safety are preferred. For this reason, we are not using interfaces or run-time reflection. (Though if a good case can be made, we’ll listen.)
21+
The [typewriter package](https://github.com/clipperhouse/typewriter) is where most of the parsing, type evaluation and code generation architecture lives.
2422

25-
The goal is to keep the API small. We aim to implement the **least number of orthogonal methods** which allow the desired range of function.
23+
####typewriters
2624

27-
It’s about types. If something would be expressed <T> in another language, perhaps it’s a good candidate for gen. If it would not be expressed that way, perhaps it’s not a good candidate.
25+
Typewriters are where templates and logic live for generating code. Here’s [set](https://github.com/clipperhouse/set), which will make a lovely Set container for your type. Here’s [slice](https://github.com/clipperhouse/slice), which provides the built-in LINQ-like functionality.
2826

29-
We avoid methods that feel like wrappers or aliases to existing methods, even if they are convenient. A good proxy is to imagine a user asking the question ‘which method should I use?’. If that’s a reasonable question, the library should be doing less.
27+
Third-party typewriters are added easily by the end user. You publish them as Go packages for import. [Learn more].
3028

31-
These guidelines are not entirely deterministic! There’s lots of room for judgment and taste, and we look forward to seeing how it evolves.
29+
We’d love to see typewriter packages for things like strongly-typed JSON serialization, `Queue`s, `Pool`s or other containers. Anything “of T” is a candidate for a typewriter.

_gen.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package main
2+
3+
import (
4+
_ "github.com/clipperhouse/slice"
5+
_ "github.com/clipperhouse/set"
6+
)

add.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
8+
"github.com/clipperhouse/typewriter"
9+
)
10+
11+
// add adds a new typewriter import to the current package, by creating (or appending) a _gen.go file.
12+
func add(c config, args ...string) error {
13+
if len(args) == 0 {
14+
return fmt.Errorf("please specify the import path of the typewriter you wish to add")
15+
}
16+
17+
imports, err := getTypewriterImports(c)
18+
19+
if err != nil {
20+
return err
21+
}
22+
23+
for _, arg := range args {
24+
imp := typewriter.ImportSpec{Name: "_", Path: arg}
25+
26+
// try to go get it
27+
cmd := exec.Command("go", "get", imp.Path)
28+
cmd.Stdout = c.out
29+
cmd.Stderr = c.out
30+
31+
if err := cmd.Run(); err != nil {
32+
return err
33+
}
34+
35+
imports.Add(imp)
36+
}
37+
38+
if createCustomFile(c, imports); err != nil {
39+
return err
40+
}
41+
42+
return nil
43+
}
44+
45+
func createCustomFile(c config, imports typewriter.ImportSpecSet) error {
46+
w, err := os.Create(c.customName)
47+
48+
if err != nil {
49+
return err
50+
}
51+
52+
defer w.Close()
53+
54+
p := pkg{
55+
Name: "main",
56+
Imports: imports,
57+
}
58+
59+
if err := tmpl.Execute(w, p); err != nil {
60+
return err
61+
}
62+
63+
return nil
64+
}

add_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/clipperhouse/typewriter"
8+
)
9+
10+
func TestAdd(t *testing.T) {
11+
// use custom name so test won't interfere with a real _gen.go
12+
c := defaultConfig
13+
c.customName = "_gen_add_test.go"
14+
defer os.Remove(c.customName)
15+
16+
if err := add(c); err == nil {
17+
t.Error("add with no arguments should be an error")
18+
}
19+
20+
foo := typewriter.ImportSpec{Name: "_", Path: "github.com/clipperhouse/foowriter"}
21+
before, err := getTypewriterImports(c)
22+
23+
if err != nil {
24+
t.Error(err)
25+
}
26+
27+
// ensure that the custom import is not in the default set
28+
if before.Contains(foo) {
29+
t.Errorf("default imports should not include %s", foo.Path)
30+
}
31+
32+
// adding import which exists should succeed
33+
if err := add(c, foo.Path); err != nil {
34+
t.Error(err)
35+
}
36+
37+
after, err := getTypewriterImports(c)
38+
39+
// the new import should be reflected in imports
40+
if !after.Contains(foo) {
41+
t.Errorf("imports should include %s", foo.Path)
42+
}
43+
}

config.go

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,21 @@ package main
33
import (
44
"io"
55
"os"
6-
"sync"
7-
)
8-
9-
// lock for changing configs below
10-
var mu = &sync.Mutex{}
116

12-
// global state for output; useful with testing
13-
var (
14-
defaultOut io.Writer = os.Stdout
15-
out io.Writer = defaultOut
7+
"github.com/clipperhouse/typewriter"
168
)
179

18-
// with inspiration from http://golang.org/src/pkg/log/log.go?s=7258:7285#L229
19-
func setOutput(w io.Writer) {
20-
mu.Lock()
21-
defer mu.Unlock()
22-
out = w
23-
}
24-
25-
func revertOutput() {
26-
setOutput(defaultOut)
10+
type config struct {
11+
out io.Writer
12+
customName string
2713
}
2814

29-
// global state for custom imports file name; useful with testing
30-
const defaultCustomName string = "_gen.go"
31-
32-
var customName string = defaultCustomName
33-
34-
func setCustomName(s string) {
35-
mu.Lock()
36-
defer mu.Unlock()
37-
customName = s
15+
var defaultConfig = config{
16+
out: os.Stdout,
17+
customName: "_gen.go",
3818
}
3919

40-
func revertCustomName() {
41-
setCustomName(defaultCustomName)
42-
}
20+
// keep in sync with imports.go
21+
var stdImports = typewriter.NewImportSpecSet(
22+
typewriter.ImportSpec{Name: "_", Path: "github.com/clipperhouse/slice"},
23+
)

custom.go

Lines changed: 0 additions & 25 deletions
This file was deleted.

custom_test.go

Lines changed: 0 additions & 45 deletions
This file was deleted.

0 commit comments

Comments
 (0)