Goライブラリもウルトラ簡単に作れる!

RubyGemはめっちゃ簡単に作れる! - 酒と泪とRubyとRailsとRubyライブラリの公開方法が紹介されていました。

Goライブラリも知らないとハードル高そうに見えますが、実はかなり簡単につくれます。 これから積極的にGoライブラリを作ってOSSの世界に貢献していきたいので簡単な作り方をまとめました。

1. ファイルを用意する

今回はテスト的にHello World!と出力するようにします。hello.goを以下のように作成します。

package hello
func Greet() { println("Hello World!")}

2. 公開する

GitHubなどのpublicなリポジトリを作成。

# gitのリモートリポジトリを設定
git remote add origin git@github.com:doloopwhile/hello.git
# add & commit & push
git add . -A && git commit -m 'first commit' && git push

ライブラリはgo get github.com/doloopwhile/helloでダウンロードできるようになります。

今回のサンプルソースは以下のリポジトリにあります。良ければForkして試してみてください!

doloopwhile/hello - Github

go-gitconfigで自作ツールの設定を~/.gitconfigに書く

Goプログラマ必携のGoライブラリ管理ツールghqは、 インストール先などを~/.gitconfigから取得するようになっています*1

まぁ、非開発者はどうするかとか、そもそも他ツールの設定ファイルに相乗りするのはどうなのかとかは問題ですが、開発者用と割り切れば、~/.gitconfigはVCSで管理しているだろうし*2、フォーマットも周知なので、専用の設定ファイルを作らせるより便利。

というわけで、ghqの真似をしたい人は go-gitconfigを使えばOK。

github.com

*1:正確にはgit configコマンドから。~/.gitconfig以外からも取得する場合もあります。

*2:管理してますよね?Git使ってない人はともかく。

PythonのfileinputをGoで実装してみた

Pythonの○○をGoで実装してみたシリーズ

fileinputは、行単位で処理を行うコマンド(特にUNIXフィルタ)を作るときなどに便利なライブラリ。

import fileinput
for line in fileinput.input():
    process(line)
  • コマンドライン引数で与えられたファイルの行に順番にアクセス
  • 引数が空の場合は標準出力の行にアクセス
  • ファイル名として '-' が与えられたときも標準出力の行にアクセス

github.com

使用例

sc := fileinput.Lines(os.Args[1:])
for sc.Scan() {
    process(sc.Text()) // 行を処理
}
if sc.Err() != nil {
    os.Stderr.WriteString(sc.Err().Error() + "\n")
    os.Exit(1)
}

// なお、ファイルハンドラを閉じる処理は.Scan()や.Err()の中で自動で行われる

Python版との違い

Go版はbufio.Scannerを真似たインターフェースにしました。 そのため、Pythonほどシンプルではありません(Pythonはfor文に渡すだけで使えるが、Go版は覚えるべきメソッドが3つもある)。

行をchan stringで返せば、Python版に近い書き心地になるような気もしましたが、 標準に合わせたいことと、チャネルを返そうとするとGoroutineを1つ余分に消費してしまうことがあり、 あきらめました。

#リハビリを兼ねて、チョチョイと書くつもりが、なぜか半日もかかってしまった・・・

ソースに一行追加するだけで実行時にバイナリをバルスできるモジュールを書いた

バズーカが弾切れ、絶対絶命のピンチ、メガネの小悪党がmain関数を実行する前に実行ファイルを削除したいというのはよくあることです。

使用例

たとえばこういうコードに・・・

// get.go
package main

func main() {
   println("ハハハハハ!飛行石を手に入れたぞー!!")
}

importをくわえるだけで・・・

// get.go
package main

import (
  _ "github.com/doloopwhile/go-balse"
)

func main() {
   println("ハハハハハ!飛行石を手に入れたぞー!!")
}

たったこれだけでバルスします!

$ go build get.go
$ ./get
panic: _人人人人人_
      > バルス!<
        ̄Y^Y^ Y^Y^ ̄

goroutine 16 [running]:
runtime.panic(0x44cc20, 0xc208000120)
    /usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/doloopwhile/go-balse.init·1()
    /home/kenjiomoto/gocode/src/github.com/doloopwhile/go-balse/balse.go:9 +0x87
github.com/doloopwhile/go-balse.init()
    /home/kenjiomoto/gocode/src/github.com/doloopwhile/go-balse/balse.go:10 +0x4b
main.init()
    /home/kenjiomoto/Downloads/get.go:10 +0x46

goroutine 17 [runnable]:
runtime.MHeap_Scavenger()
    /usr/local/go/src/pkg/runtime/mheap.c:507
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445

goroutine 18 [runnable]:
bgsweep()
    /usr/local/go/src/pkg/runtime/mgc0.c:1976
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445

goroutine 19 [runnable]:
runfinq()
    /usr/local/go/src/pkg/runtime/mgc0.c:2606
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445

$ ./get
bash: ./get: そのようなファイルやディレクトリはありません

doloopwhile/go-balse

あとがき

最初は「importするだけでカレントディレクトリのファイルを全て削除」という仕様にしたところ、うっかり「README.mdがー!!README.mdがー!!」となってしまったので、実行ファイルを削除するだけのオトナシイ仕様にしました。

「ソースに一行追加するだけで・・・」は本来もっと真面目な目的で利用できるものです。

Goplay: Goで手軽に書捨て環境を作るツール

goreの説明を追記。

f:id:doloopwhile:20040712133434j:plain

LLから、Goに移るときの不満の一つに「標準のREPL(インタラクティブシェル)が無い」があります。

「ポインタはmapのキーになるんだっけ?」のような、つまらない(けど、ありがちな)疑問を解消するには、ドキュメントを漁るより、コードを書いてしまう方が、手っ取り早いですよね?

goplayを作った!

goplayは、書捨てGoコードを書くためのシンプルなツールです。

https://camo.githubusercontent.com/db725471459165d7d24b6e6f234b02267b187746/68747470733a2f2f7261772e6769746875622e636f6d2f646f6c6f6f707768696c652f676f706c61792f6d61737465722f64656d6f2e676966

やっているのは、 1. 一時ディレクトリを/tmp/goplay/以下に作る 2. main.goを一時ディレクトリに作る 3. 一時ディレクトリで新しいシェルを起動 4. 環境変数GOPATHに一時ディレクトリを追加。 これだけです。

インストールはgo getするだけです。

go get github.com/doloopwhile/goplay

他の方法との比較

ちゃんとしたREPL(gore)を使う

いや、正直、普通はgoreのほうがいいと思います。良い子はgoreを使いましょう。

エディタで書捨てコードを書きたい子はgoplayを使いましょう。

github.com

Go Playground

Go Playgroundはブラウザ上でGoを書いて実行できます。 しかし、

  • 外部ライブラリをimportできない
  • 好きなエディタが使えない という欠点があります。

goplayは、ローカルで実行するので、外部ライブラリもエディタも自由に使えます。

その場でvi a.goする

まぁ、それでも動くは動くんですが、

package main*.goファイルが同一ディレクトリに複数あると、 エディタのシンタックスチェッカーが、

「main redeclared in this block」

を出してくるのが五月蝿い。

そして、作ったスクリプトを削除するのも面倒くさい。

Let's go!

Go-GTKでCUIとGUIをつなぐ的なアプリを書いてみた

プログラマーは往々にしてCUI世界の住人なのですが、

ごくたまに、ファイルをドラッグ&ドロップで指定できると便利、ということがあります。

doloopwhile/dap · GitHub

スクリーンショット

f:id:doloopwhile:20141005180042p:plain

インストール

go get github.com/doloopwhile/dap

使い方

ドラッグアンドドロップでファイルをバックアップ・ディレクトリにコピーする

mkdir -p $HOME/backup
dap | xargs cp {} $HOME/backup

なぜ作ったか

Debian系OSには(dragbox)https://packages.debian.org/ja/sid/dragboxというツールがあるようです。しかし、どういうわけか私のXubuntuでは動きませんでした。

そこで、(Go-GTKのD&Dの例)https://github.com/mattn/go-gtk/blob/master/example/dnd/dnd.goを元に作ってみました。Go-GTKは、デモが充実しており、実用的に使えそうな段階に入っているようです。

Goライブラリを作ったら、とりあえずgodocdown

小さなGoライブラリをつくった時、ほとんど自分しか使わないような規模なら、わざわざREADMEに「Usage」「Example」「Functions」なんて書くのは面倒ですよね。

そんな時は、godocdownで自動生成してしまうのがオススメです。 godocと同等の内容をGitHub用Markdownで生成してくれます。

例:doloopwhile/go-merror · GitHub

go get github.com/robertkrimen/godocdown/godocdown
godocdown > README.md

まぁ、わざわざgodocdownでREADMEを作らなくても、 ほっておいてもgodocは、自動で生成されるのですが、READMEを空っぽにしておくのも寂しいので。