Go言語製のCUIツールを１行でWeb GUI化するライブラリを作った

## はじめに

皆さん、CUI/CLIツールを使ってますか？
Qiitaを読んでるような人はみんな使ってるでしょうね。
しかし世間一般に視野を広げると、必ずしもそうではないかと思います。
『黒い画面はなんか敷居が高い』
『一応使えるけど面倒』
『信仰している宗教の戒律で固く禁じられている』
『黒い画面に故郷の村を焼かれた』
などなど理由は様々です。

![黒画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33890/f71f5f2d-1d07-ac5a-762c-c0e32083ff8c.png)

## flagstone

使う側にとっては敷居の高いCUIツール。
とはいえGUIのツールを作るのは、我らがGo言語ではなかなかに面倒です。

そこで、Go言語製のCUIツールを１行でWeb GUI化するライブラリを作ってみました。

flagstone
https://github.com/kurehajime/flagstone

これです。
flagstoneは、日本語に訳すと『敷石』です。
舗装して歩きやすくしますよ〜みたいなネーミングです。


![flagstone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33890/ea89ccfa-f537-99ec-efdb-d1a62776448f.png)

使い方はとっても簡単。
例えば、こんなプログラムがあったとします。

```go
package main

import (
    "flag"
    "fmt"
)

var who *string

func main() {
    who = flag.String("who", "world", "say hello to ...")
    flag.Parse()

    fmt.Println("hello " + *who + "!")
}

```

コマンドライン引数で受け取ったパラメータに文字を足して画面に表示するだけの簡単なプログラムですね。

これをコンソールから
`./hello -who "世界"`
と実行すると、
`hello 世界!`
と表示されるわけです。

これをflagstoneを使ってWeb GUI化していきましょう。

```go
package main

import (
    "flag"
    "fmt"

    "github.com/kurehajime/flagstone" //★ ここと… ★
)

var who *string

func main() {
    who = flag.String("who", "world", "say hello to ...")
    flag.Parse()

    flagstone.Launch("helloworld", "flagstone sample") //★ ここを追記する！ ★

    fmt.Println("hello " + *who + "!")
}

```

２行追加しました。
import句の`"github.com/kurehajime/flagstone"`と
flag.Parse()のあとの
`flagstone.Launch("helloworld", "flagstone sample") `
の２行です。
タイトルは「１行でWeb GUI化する」と謳っていますが・・・import文はノーカンです。

これを実行するとどうなるでしょう。
こうなります。

<img width="841" alt="スクリーンショット 2020-02-11 12.10.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33890/c1470b42-116d-6991-5290-67611eaeabb3.png">

Web UIが出てきます。
実行ボタンと、パラメータの名前、入力欄、説明まで出てきます。
これは一番シンプルな例ですが、たくさんコマンドライン引数を受け取るプログラムでは、たくさん入力欄が出てきます。
テキストボックスに文字を入れて、Runボタンを押せばコマンドが実行されます。

付け足したのは実質

`flagstone.Launch("helloworld", "flagstone sample") `

この１行だけなのに、コマンドライン引数の欄まで作られてます。
なぜでしょうか。

この魔法はGo言語標準のflagパッケージにあります。
flagパッケージを使って定義されたコマンドライン引数はflagstoneで全部ぶっこ抜かれ、自動的にWeb UIが組み立てられます。
型のチェックまで行っているので、数字の入力欄に文字を入れると弾かれます。

完全にWebGUI化してしまうとコマンドラインツールとして使いたいときに不便なので、必須の引数を省略された際のフォールバックとしてのみ利用する使い方がおすすめです。

いくつかの[オプション](https://github.com/kurehajime/flagstone#options)も用意しています。

## 中身
ここから先はflagstoneがどのように実装されているか解説していきます。

### flag

Go言語のflagパッケージを使って指定されたコマンドライン引数は、`flag.CommandLine.VisitAll`を使うことで、コールバック形式でflagオブジェクトを取得できます。

```
flag.CommandLine.VisitAll(func(f *flag.Flag) {
    // fがflagオブジェクト
})
```

このflagオブジェクトは「Name」「DefValue」「Usage」でそれぞれ名前、初期値、説明文を取得できます。
`f.Value.Set('hoge')`と書けば、値のセットもでき、型に一致しない不適切な値がセットされた場合はerrorが返ります。

この機能を使えばflagの中身を全部ぶっこ抜けるわけです。

### gowut

flagstoneのWeb UIは[gowut](https://github.com/icza/gowut)というライブラリで実装しています。
これはコントロールの定義もイベント定義も全部Go言語で書けるWeb UIツールキットです。

[公式のサンプルのソースはこんな感じ](https://github.com/icza/gowut/blob/master/_examples/simple/simple_demo.go)です。
作り込めば[こういうの](https://gowut-demo.herokuapp.com/show)も作れるようです。
デザインがイケてないと感じたら、任意のCSSやHTMLを挿入することもできます。

GoのGUIライブラリはまだ決定版と言えるものがなく、クロスプラットフォームに難があったり、コンパイルする際の敷居が高くなったりするものも多かったりします。
flagstoneはあくまで『オマケ』として利用されるものですので、足を引っ張らないことを重視してこれを選択しました。 [^1]

## おわりに

というわけで、Go言語製のCUIツールを１行でWeb GUI化するライブラリを作ってみました。
本格的なGUIアプリを作る労力をかけたくないけれど、CUIを使いたくない人にも裾野を広げたい場合などご利用ください。
まだ全然機能も貧弱ですので、プルリクも歓迎です。


[^1]: 最近npmでJavascriptのライブラリをインストールしようとした時、PythonとC++コンパイラが必須のライブラリが依存関係にあって色々面倒くさかったのが理由です。[こいつ](https://qiita.com/search?utf8=%E2%9C%93&sort=&q=node-gyp+%E3%82%A8%E3%83%A9%E3%83%BC)のせいです。