tinka alpha

Scaffolding

This guide covers creating code with act's generators. You will learn how to:

Overview

A generator writes a new file into the App and adds the line that registers it, such as the route of a new handler. It saves typing the same code each time, and it puts everything where the folder structure says it goes, so every App reads alike.

Generators write files from stubs: Go files with placeholders, such as {{ .Type }}, that the generator fills in. The App can replace any stub with its own.

Create code

Each generator is an act make: Command that takes a singular name:

Terminal
act make:handler post --resource
Output
CREATE app/handlers/posts.go
UPDATE start/routes.go
         + app.Get("/posts", handlers.ListPosts)
         + app.Get("/posts/{id}", handlers.ShowPost)
         + app.Post("/posts", handlers.CreatePost)
         + app.Put("/posts/{id}", handlers.UpdatePost)
         + app.Delete("/posts/{id}", handlers.DeletePost)

| Command | Creates | Registers | |---|---|---| | act make:handler post | app/handlers/post.go, one handler | its route in start/routes.go | | act make:handler post --resource | app/handlers/posts.go, the five handlers of a REST resource | their routes | | act make:provider database | app/providers/database_provider.go | app.Provide in start/app.go | | act make:command posts:publish | app/commands/posts_publish.go | app.Command in start/app.go | | act make:middleware auth | app/middleware/auth.go | nothing, or app.Use in start/kernel.go with --global | | act make:test posts | tests/functional/posts_test.go, an HTTP test | nothing |

In an App created from the core starter kit, every file goes in the App's root package, and the registrations go after tinka.New in the function that creates the App.

Names

A generator derives every name from the one you type, the Go way: post gives the type Post, the file post.go, the plural Posts and the route /posts; user_id gives UserID; and a suffix that repeats the kind is dropped, so make:provider DatabaseProvider still creates DatabaseProvider. When the plural rules get a word wrong, give the plural:

Terminal
act make:handler cactus --resource --plural cacti

A name Go already uses, such as type or string, and one whose file Go would build only on one system, such as legacy_windows, are refused, with the reason.

Check before writing

--dry-run prints what a generator would create and change, and writes nothing:

Terminal
act make:provider database --dry-run

A generator never replaces a file that exists: it stops before writing anything, and --force replaces it. Running a generator twice adds no registration twice: one that's already there is skipped.

Change the stubs

act publish:stubs copies the default stubs into the App's stubs/ directory. From then on, generators use the App's copy:

Terminal
act publish:stubs make/handler
stubs/make/handler.stub
---
to: {{ .Dir }}/{{ .File }}.go
---
package {{ .Package }}

import "github.com/mucolabs/tinka"

// {{ .Type }} answers GET {{ .Path }}.
func {{ .Type }}(c *tinka.Ctx) (string, error) {
	return "{{ .Type }}", nil
}

The front matter's to: is where the file goes, so a stub can also move it. A stub holds placeholders and nothing else: a variant is another stub, such as make/handler_resource.

{{ .Type }}placeholder

The exported name: BlogPost.

{{ .Var }}placeholder

The unexported name: blogPost.

{{ .File }}placeholder

The file name, without .go: blog_post.

{{ .Plural }}placeholder

The exported plural: BlogPosts. {{ .PluralFile }} is blog_posts, and {{ .PluralWords }} is blog posts.

{{ .Route }}placeholder

The resource's route: /blog-posts. {{ .Path }} is the singular one: /blog-post.

{{ .Command }}placeholder

The Command's name: blog-post, or posts:publish as typed.

{{ .Package }}placeholder

The package the file belongs to, such as handlers, and {{ .Dir }} its directory, such as app/handlers.

{{ .Module }}placeholder

The App's module path, for imports of its own packages: blog.

A stub with a placeholder that doesn't exist, or that renders Go that doesn't parse, fails with the stub's path, and writes nothing.

Register by hand

A generator edits start/app.go, start/routes.go and start/kernel.go by adding lines after those of the same kind, and leaves every other line as it was. When it can't find where a line goes, such as when you've moved the App's assembly elsewhere, it still creates the file, writes nothing else, and tells you the exact line to add, and where:

Output
Error: created app/providers/cache_provider.go, but couldn't register it.
  Fix: In start/app.go, in App, after tinka.New (it has no function App that uses tinka), add:

    app.Provide(&providers.CacheProvider{})

and import "blog/app/providers".

Agents get the same steps in error.details, with the code codemod_manual.

Generators match the App's Tinka

The starter kits pin act in the App's go.mod. A globally installed act hands its generators to that copy, so the code they write always matches the version of Tinka the App uses. That copy is built from what the App's go.mod points to, so act does this only for an App you trust; otherwise it uses its own generators and says so.

See also: Folder structure, Commands reference, Creating Commands