📄

【Go】cobraとtext/templateを使って、ファイル作成の効率化を目指す

2025/02/20に公開

例えばDDDに基づく開発では、ValueObjectやEntityなどファイルを作成することが

多く、手動でファイルを作成することが手間です。

今回はその対策として、自作したコマンドでファイルを作成する ということを調べながらやっていきたいと思います。

今回作成したもの

Cobraを使う

CLIツールを作成するためのライブラリとしてCobraが人気なようです。
https://github.com/spf13/cobra

readmeを見てインストールを行います。

go get -u github.com/spf13/cobra@latest
go install github.com/spf13/cobra-cli@latest

cobra-cliはcobra-cliはcobraアプリケーションとコマンドファイルを生成するコマンドラインプログラムで、作業を効率化してくれるそうです。

https://github.com/spf13/cobra-cli/blob/main/README.md#cobra-cli-init

cobra-cli init

を実行し、初期化を行い試しにコマンドを追加していきます。

cobra-cli add hello

以下のようなコードがcmd配下に作成されます。

package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// helloCmd represents the hello command
var helloCmd = &cobra.Command{
	Use:   "hello",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("hello called")
	},
}

func init() {
	rootCmd.AddCommand(helloCmd)
}

コマンドを実行し、fmt.Println("hello called")が実行されていることが確認できました。

go run main.go hello

hello called

text/templateを使う

標準パッケージになります。
テンプレートとなるtxtファイルを作成し、{{.ValueName}}の部分を置換していくことにします。

valueObjectTemplate.txt
package vo

type {{.ValueName}}Vo struct {

}

func New{{.ValueName}}Vo() {{.ValueName}}Vo {
	return {{.ValueName}}Vo{}
t, err := template.New("valueObjectTemplate.txt").ParseFiles("valueObjectTemplate.txt")
	
	if err != nil {
		fmt.Println(err)
	}

	if err = t.Execute(
		os.Stdout, 
		map[string]string{"ValueName": "Email"}); err != nil {
		fmt.Println(err)
	}

注意点はNewの部分。記事がありました。
https://qiita.com/taqm/items/79e2d3cf32589ec7d4c7

実行結果

package vo

type EmailVo struct {

}

func NewEmailVo() EmailVo {
        return EmailVo{}
}

このままだとターミナル上に表示されているだけなので、ファイルを作成し内容を書き出すことにします。

Executeの定義が

func (t *template.Template) Execute(wr io.Writer, data any) error

io.Writerなので、以下のようにしてあげることにより、
テンプレート内容を置換した内容が新しいファイルの内容として反映されます。

+ file, err := os.Create("vo/emailVo.go"); if err != nil {
+		fmt.Println(err)
+	}
+	defer file.Close()
	
	t, err := template.New("valueObjectTemplate.txt").ParseFiles("valueObjectTemplate.txt")

	if err != nil {
		fmt.Println(err)
	}

	if err = t.Execute(
-       os.Stdout, 
+		file, 
		map[string]string{"ValueName": "Email"}); err != nil {
		fmt.Println(err)
	}

組み合わせる

コマンドの追加

cobra-cli add makeVo

テンプレート作成

#text%2Ftemplate%E3%82%92%E4%BD%BF%E3%81%86
上記で作成したテンプレートを修正し、置換部分をvalueName、ValueNameの2種類に変更しました。

package vo

type {{.valueName}}Vo struct {

}

func New{{.ValueName}}Vo() {{.valueName}}Vo {
	return {{.valueName}}Vo{}
}

コマンド処理実装

makeVo.go
package cmd

import (
	"fmt"
	"os"
	"strings"
	"text/template"

	"github.com/spf13/cobra"
)

var makeVoCmd = &cobra.Command{
	Use:   "makeVo",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1{
			fmt.Println("ValueObjectNameを入力してください")
			return
		}
		firstLower := strings.ToLower(string(args[0][0])) + args[0][1:]
		firstUpper := strings.ToUpper(string(args[0][0])) + args[0][1:]

		file, err := os.Create("vo/"+firstLower+"Vo.go"); if err != nil {
		fmt.Println(err)
	}
		defer file.Close()
		
		t, err := template.New("valueObjectTemplate.txt").ParseFiles("valueObjectTemplate.txt")

		if err != nil {
			fmt.Println(err)
		}

		if err = t.Execute(
			file, 
			map[string]string{
				"ValueName": firstUpper,
				"valueName": firstLower,
				}); err != nil {
			fmt.Println(err)
		}
		},
}

func init() {
	rootCmd.AddCommand(makeVoCmd)
}

コマンド実行

以下ファイルが生成されました!

vo/emailVo.go
package vo

type exampleVo struct {

}

func NewExampleVo() exampleVo {
	return exampleVo{}
}

今回のケースは簡単なものでしたが、コマンドからファイル生成まで実装できました。
コマンドの引数や処理、テンプレートを複雑にすることでより自由で便利なコマンドを作ることが可能だと感じました。

参考記事

https://qiita.com/hiro_nico/items/61a5ae7138c6918bc6b5

https://ken-aio.github.io/post/2019/01/27/golang-cobra/

https://speakerdeck.com/kazukihayase/godetenpuretokarahuairuwozi-dong-sheng-cheng-surucliwozuo-ru

Discussion