@@ -56,16 +56,21 @@ person := Person{
5656
5757## Installation
5858
59- Install ** gobetter** and its dependency :
59+ Install ** gobetter** as standalone utility :
6060
6161``` bash
62- # Install goimports (for code formatting)
63- go install golang.org/x/tools/cmd/goimports@latest
64-
65- # Install gobetter
6662go install github.com/mobiletoly/gobetter@latest
6763```
6864
65+ or (even better) install ** gobetter** to use as tool in your go.mod:
66+
67+ ```
68+ tool (
69+ github.com/mobiletoly/gobetter
70+ )
71+ ```
72+
73+
6974## Quick Start
7075
7176### 1. Annotate Your Structs
@@ -75,52 +80,64 @@ Add annotations to your Go structs:
7580``` go
7681package main
7782
83+ // Put on top of the file
7884// go:generate gobetter -input $GOFILE
7985
8086type Person struct { // +gob:Constructor
81- firstName string // +gob:getter
82- lastName string // +gob:getter
83- dob string // +gob:getter +gob:acronym
84- Score int
85- Description string // +gob:_
87+ FirstName string
88+ LastName string
89+ email string // +gob:getter
90+ dob string // +gob:getter +gob:acronym
91+ Score int
92+ Description string // +gob:_
8693}
8794```
8895
96+ IMPORTANT: +gob: getter annotation must be used for private fields (starting with lowercase letter)
97+ only.
98+
8999### 2. Generate Code
90100
91- Run the generator:
101+ Run the generator to generate all annotated structs :
92102
93103``` bash
94104go generate ./...
95105```
96106
107+ it will result in creating files with suffix ` _gob.go ` for each of your file that contains
108+ annotated structs.
109+
97110### 3. Use the Generated Builder
98111
99112``` go
100113person := NewPersonBuilder ().
101114 FirstName (" John" ).
102115 LastName (" Doe" ).
116+ Email (" john.doe@example.com" ).
103117 DOB (" 01/01/1990" ).
104118 Score (85 ).
105119 Build ()
106120
107121// Set optional fields after building
108122person.Description = " Software engineer"
109123
110- // Access private fields through getters
111- fmt.Println (person.FirstName ()) // "John"
112- fmt.Println (person.DOB ()) // "01/01/1990" (acronym handling)
124+ fmt.Println (person.FirstName ) // "John"
125+ fmt.Println (person.LastName ) // "Doe"
126+ fmt.Println (person.Email ()) // "john.doe@example.com" (getter function to call from outside)
127+ fmt.Println (person.DOB ()) // "01/01/1990" (getter function, acronym is DOB instead of dob)
128+ fmt.Println (person.Score ) // 85 (public field, no function needed)
129+ fmt.Println (person.Description ) // "Software engineer"
113130```
114131
115132## 📝 Annotations Reference
116133
117- | Annotation | Description | Example |
118- | ------------| -------------| ---------|
119- | ` //+gob:Constructor ` | Generate builder for struct | ` type Person struct { //+gob:Constructor ` |
120- | ` //+gob:constructor ` | Generate package-level builder | ` type person struct { //+gob:constructor ` |
121- | ` //+gob:getter ` | Generate getter for private field | ` name string //+gob:getter ` |
122- | ` //+gob:acronym ` | Treat field as acronym (DOB vs Dob) | ` dob string //+gob:getter +gob:acronym ` |
123- | ` //+gob:_ ` | Mark field as optional (skip in builder) | ` description string //+gob:_ ` |
134+ | Annotation | Description | Example |
135+ | ---------------------- | ------------------------------------------ | ---------------------------------- ---------|
136+ | ` //+gob:Constructor ` | Generate builder for struct | ` type Person struct { //+gob:Constructor ` |
137+ | ` //+gob:constructor ` | Generate package-level builder | ` type person struct { //+gob:constructor ` |
138+ | ` //+gob:getter ` | Generate getter for private field | ` name string //+gob:getter ` |
139+ | ` //+gob:acronym ` | Treat field as acronym (DOB vs Dob) | ` dob string //+gob:getter +gob:acronym ` |
140+ | ` //+gob:_ ` | Mark field as optional (skip in builder) | ` description string //+gob:_ ` |
124141
125142## 🏗️ Nested Structs Support
126143
@@ -155,16 +172,22 @@ config := NewConfigBuilder().
155172 Build ()
156173```
157174
175+ Run:
176+
177+ ``` bash
178+ go generate ./...
179+ go test -bench . -benchmem -run ^$ -count 5 ./...
180+ ```
181+
158182## Configuration Options
159183
160184### Command Line Flags
161185
162- | Flag | Values | Description |
163- | ------| --------| -------------|
164- | ` -input ` | ` <file> ` | Input file to process |
165- | ` -output ` | ` <file> ` | Output file (default: ` <input>_gob.go ` ) |
166- | ` -generate-for ` | ` all\|exported\|annotated ` | Which structs to process |
167- | ` -constructor ` | ` exported\|package\|none ` | Constructor visibility level |
186+ | Flag | Values | Description |
187+ | -----------------| ----------------------------| ------------------------------|
188+ | ` -input ` | ` <path> ` | Input file or directory |
189+ | ` -generate-for ` | ` all\|exported\|annotated ` | Which structs to process |
190+ | ` -constructor ` | ` exported\|package\|none ` | Constructor visibility level |
168191
169192### Examples
170193
@@ -179,11 +202,11 @@ gobetter -input=models.go -generate-for=exported
179202gobetter -input=models.go -generate-for=all -constructor=package
180203```
181204
182- ## IDE Integration
205+ ## Optional IDE Integration
183206
184207### IntelliJ IDEA / GoLand
185208
186- Set up a File Watcher for automatic generation:
209+ Set up a File Watcher for automatic generation (no need to run ` go generate ` ) :
187210
1882111 . Go to ** Preferences → Tools → File Watchers**
1892122 . Add ** Custom** watcher:
@@ -193,4 +216,67 @@ Set up a File Watcher for automatic generation:
193216 - ** Arguments** : ` generate `
194217 - ** Scope** : Create scope with pattern ` file:*.go&&!file:*_gob.go `
195218
196- Now builders regenerate automatically when you save Go files!
219+ Now builders regenerate automatically when you save Go files
220+
221+
222+ ## Performance
223+
224+ ** Summary:** For typical structs, gobetter’s step-builder is * as fast* as direct struct
225+ initialization and has the * same* allocation profile.
226+
227+ - ** CPU:** Direct literal ~ 19.8–20.8 ns/op; Builder chain ~ 20.1–24.1 ns/op in our latest run (
228+ averages ≈ ** 20.18 ns/op** vs ** 21.64 ns/op** , respectively). The single-digit ns delta is within
229+ typical microbenchmark variance and both approaches remain essentially equivalent for real
230+ workloads.
231+ - ** Allocations:** ** 1 alloc/op** (the single ` *T ` instance you ultimately build), ** ~ 96 B/op** for
232+ the ` Person ` example. Step structs are tiny (a single pointer to the root) and stay on the ** stack
233+ ** .
234+ - ** Why it’s fast:**
235+ - Setters are trivial field assignments that the compiler ** inlines** .
236+ - Step structs are returned ** by value** and typically do ** not escape** (escape analysis keeps
237+ them on stack).
238+ - ` Build() ` returns the same ` *T ` allocated once at the start of the chain — identical to
239+ ` &T{...} ` .
240+
241+ ### Reproduce the benchmark
242+
243+ ``` go
244+ func BenchmarkDirectLiteral (b *testing .B ) {
245+ b.ReportAllocs ()
246+ for i := 0 ; i < b.N ; i++ {
247+ p := &Person{firstName: " John" , lastName: " Doe" , dob: tDOB, Email: " john.doe@example.com" }
248+ sink = p
249+ }
250+ }
251+
252+ func BenchmarkBuilderChain (b *testing .B ) {
253+ b.ReportAllocs ()
254+ for i := 0 ; i < b.N ; i++ {
255+ p := NewPersonBuilder ().
256+ FirstName (" John" ).
257+ LastName (" Doe" ).
258+ DOB (tDOB).
259+ Email (" john.doe@example.com" ).
260+ GobFinalizer ().
261+ Build ()
262+ sink = p
263+ }
264+ }
265+ ```
266+
267+ ** Sample results (one machine):**
268+
269+ ```
270+ BenchmarkDirectLiteral-12 57792015 20.02 ns/op 96 B/op 1 allocs/op
271+ BenchmarkDirectLiteral-12 59628193 19.77 ns/op 96 B/op 1 allocs/op
272+ BenchmarkDirectLiteral-12 59373484 20.78 ns/op 96 B/op 1 allocs/op
273+ BenchmarkDirectLiteral-12 57435504 19.94 ns/op 96 B/op 1 allocs/op
274+ BenchmarkDirectLiteral-12 55259538 20.38 ns/op 96 B/op 1 allocs/op
275+ BenchmarkBuilderChain-12 58040876 20.08 ns/op 96 B/op 1 allocs/op
276+ BenchmarkBuilderChain-12 57155670 21.04 ns/op 96 B/op 1 allocs/op
277+ BenchmarkBuilderChain-12 49360202 22.16 ns/op 96 B/op 1 allocs/op
278+ BenchmarkBuilderChain-12 54273560 24.14 ns/op 96 B/op 1 allocs/op
279+ BenchmarkBuilderChain-12 55646794 20.80 ns/op 96 B/op 1 allocs/op
280+ ```
281+
282+ (Results vary by CPU/Go version and flags; use multiple runs with ` -count ` for stability.)
0 commit comments