( ´∀｀) ＜ モナーがechoしてくれる `monaco`って言うコマンドを作りました

# モナーって知ってますか？
モナーは某ネット掲示板の2ちゃんねる（今は5ちゃんねる）で愛されているアスキーアートの１つで
「お前が言うな」 や 「お前も一緒やろ」 的なニュアンスで使われているやつです

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/8f26427f-1629-a4cf-dded-f30c8a97bdbf.png" width="30%">

# 制作に至った経緯
〜ある日の深夜〜
私 「モナーがechoしたら面白いんじゃね？」
私 「モナーがecho、モナーがエコー、モナーエコー、モナコ、monaco でええやん」
と言う思いつきと深夜テンションのままに作ったコマンドになります
開発してから結構な日数が経っているんですが供養させてください👻

ただ、1つだけ問題がMSのOSSの [Monaco Editor](https://microsoft.github.io/monaco-editor/) と名前が被ってるんですよね

## リポジトリはこちら
https://github.com/chihiros/monaco

## インストール方法
インストールはGoからにしか対応していません...orz <ｽﾐﾏｾﾝ

```sh
go install github.com/chihiros/monaco@latest
```

## 使い方

```
$ monaco オマエモナー

 ∧___∧   /‾‾‾‾‾‾‾‾‾‾
( ´∀ `) < オマエモナー
(     )  \__________
|  |  |
(__)__)
```

- 普通の `echo` と同じように変数の中身を表示することもできます
- 会話の吹き出しなんですが、長い文章を入力した場合は長さが足らなくなる場合がありますm(_ _;)m
    - 特に日本語と英語が交じるとダメです
- レイアウトが崩れるのを防ぐため、改行には対応できていませんm(_ _;)m
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/4d79bf8a-f7f1-7579-86ff-95f672c40fd8.png)


# 技術スタック
言語：Go
フレームワーク：[cobra](https://github.com/spf13/cobra)

# コードの概要
monacoの構成はざっくりとこのような感じになっています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/f5921f5c-a110-be55-d918-b8b978c220a2.png)

`asciiart/ascii_art.go` ってやつでAAを作成しています
コード全体としてはこんな感じ
```go:asciiart/ascii_art.go
package asciiart

import (
	"bytes"
	"embed"
	"fmt"
	"log"
	"os/exec"
	"text/template"
)

//go:embed template/*.tpl
var templates embed.FS

type AsciiArt struct {
	Name string
	Args []string
}

func NewAsciiArt(args []string) *AsciiArt {
	return &AsciiArt{
		Name: "mona_front",
		Args: args,
	}
}

func getAaTemplate() *template.Template {
	funcMap := template.FuncMap{
		"printOverLine": func(args []string) string {
			return printLine("‾", args)
		},
		"printUnderLine": func(args []string) string {
			return printLine("_", args)
		},
		"echo": func(args []string) string {
			cmd := exec.Command("echo", args...)
			var out bytes.Buffer
			cmd.Stdout = &out
			err := cmd.Run()
			if err != nil {
				log.Fatal(err)
			}
			return out.String()
		},
	}

	TEMPLATE_PATH := "template/*.tpl"
	tpl := template.Must(template.New("").Funcs(funcMap).ParseFS(templates, TEMPLATE_PATH))

	return tpl
}

func (a *AsciiArt) Print() {
	tpl := getAaTemplate()
	var buf bytes.Buffer

	err := tpl.ExecuteTemplate(&buf, a.Name, a.Args)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(buf.String())
}
```

## 部分的に解説
```go
//go:embed template/*.tpl
var templates embed.FS
```
- ビルドしたときに、テンプレートの中身をバイナリに入れ込みたいので `go:embed` しています

```go
type AsciiArt struct {
	Name string
	Args []string
}
```
- `Name` は何種類かのAAに対応させたかったので用意しています（用意しているだけですorz）
- `Args` にはTerminalで入力された引数が入ります

```go
funcMap := template.FuncMap{
    "printOverLine": func(args []string) string {
        return printLine("‾", args)
    },
    "printUnderLine": func(args []string) string {
        return printLine("_", args)
    },
    "echo": func(args []string) string {
        cmd := exec.Command("echo", args...)
        var out bytes.Buffer
        cmd.Stdout = &out
        err := cmd.Run()
        if err != nil {
            log.Fatal(err)
        }
        return out.String()
    },
}
```
- テンプレート内で利用できる関数の定義をしています

```
{{ block "mona_front" . }}
 ∧___∧   /{{ printOverLine . }}
( ´∀ `) < {{ echo . -}}
(     )  \{{ printUnderLine . }}
|  |  |
(__)__)
{{ end }}
```
- テンプレートの中ではこのような感じで関数を利用することができます

```go
func (a *AsciiArt) Print() {
	tpl := getAaTemplate()
	var buf bytes.Buffer

	err := tpl.ExecuteTemplate(&buf, a.Name, a.Args)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(buf.String())
}
```
- Printメソッド：AAの作成から表示まで行ってくれる関数です

```go:cmd/root.go
aa := asciiart.NewAsciiArt(args)
aa.Print()
```
- こちらのコードからPrintメソッドが読み出されてAAが表示されます

# 最後に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674343/00347744-1bfc-403f-5340-c60223332939.png)