Help us understand the problem. What is going on with this article?

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

はじめに

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

黒画面.png

flagstone

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

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

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

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

flagstone.png

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

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化していきましょう。

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 + "!")
}

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

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

スクリーンショット 2020-02-11 12.10.31.png

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

付け足したのは実質

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

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

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

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

いくつかのオプションも用意しています。

中身

ここから先は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というライブラリで実装しています。
これはコントロールの定義もイベント定義も全部Go言語で書けるWeb UIツールキットです。

公式のサンプルのソースはこんな感じです。
作り込めばこういうのも作れるようです。
デザインがイケてないと感じたら、任意のCSSやHTMLを挿入することもできます。

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

おわりに

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


  1. 最近npmでJavascriptのライブラリをインストールしようとした時、PythonとC++コンパイラが必須のライブラリが依存関係にあって色々面倒くさかったのが理由です。こいつのせいです。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした