Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

io.ioutilを使って一時ファイルをつくる

ツールを作る際、何かと必要な一時ファイル。
GO言語では、io.ioutilを使ってつくる事ができます。

実際のところ

一時ファイルを作る場合はioutil.TempFileを使います
ioutil - The Go Programming Language

公式サンプルを元に、一通りの挙動をするスクリプトは以下の通り。

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

func main() {
	content := []byte("temporary file's content")
	tmpfile, err := ioutil.TempFile("", "example")
	if err != nil {
		log.Fatal(err)
	}

	defer os.Remove(tmpfile.Name())
	defer tmpfile.Close()

	if _, err := tmpfile.Write(content); err != nil {
		log.Fatal(err)
	}

	fpath := tmpfile.Name()
	fmt.Println(fpath)
	if f, err := ioutil.ReadFile(fpath); err != nil {
		log.Fatal(err)
	} else {
		fmt.Println(string(f))
	}
}

ファイルを読み込む際、どこかの莫迦のようにTempFileを生成した変数でReadFile関数を読まないようにして下さいね(白目


実行してみると、都度都度ファイルを作ってるらしい事がわかります

$ go run ioutilTest.go 
/var/folders/02/546lp7s57l93kzydhj2dtyzr0000gn/T/example782409817
temporary file's content

$ go run ioutilTest.go 
/var/folders/02/546lp7s57l93kzydhj2dtyzr0000gn/T/example076921445
temporary file's content

if構文の中だけで通用する変数を別途設定できる

GO言語ではif文の中だけで通用する変数を別途設定できます。

実際のところ

公式サンプルから。
指定数分、乗数を掛けるが最後の引数を突破した場合はそれに従う……みたいな
ある種フィルターめいた関数は以下の通り。

package main

import (
	"fmt"
	"math"
)

func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
}

func main() {
	fmt.Println(
		pow(3, 2, 10),
		pow(3, 3, 20),
	)
}

従属するelseでも変数は利用可能です。

参考もと

A Tour of Go

Bash環境において"$_"は最後にマッチした変数を拾う

Bash環境において"$_"は最後にマッチした変数を拾います。

実際のところ

以下のようなコマンドを叩いたとします。

 $ mv ~/tmp/hoge /Users/shuzo_kino/dev/src/
$ cd $_

この時、"$_"がマッチするのはどっちでしょうか?
……正解は後者。
これならmvした後に移動先に飛ぶことができるので便利ですね。

testingパッケージの"Example~"記法だと実行例をドキュメントに記載できる

testingパッケージの"Example~"記法だと実行例をドキュメントに記載できます。
ユーザが頻繁に利用するタイプの関数なら、付けておくと親切で良いかと思います。

実際のところ

実行対象の内容は前回のと同じです。

func ExampleSomething() {
	fmt.Println(Something(1, 4))
	// Output: 5
}

実行すると、こんな感じ

$ go test hoge
ok  	hoge	0.007s

駄目なバージョンとして
先程の"Output: 5"を、
正しい"Output: 6"にしてみると……

$ go test hoge
--- FAIL: ExampleSomething (0.00s)
got:
5
want:
6
FAIL
FAIL	hoge	0.007s

これだと何の旨みがあるのか全く分かりませんね。
godocと連携すると、公式で見られるような"ドキュメント中に記載できる実行例"として扱う事ができます。
f:id:shuzo_kino:20170419224148p:plain
テストもドキュメント化も兼ねていて実際便利!

Golangでテストを始める

GoLangでテストをやるには"testing"パッケージをつかいます。
公式では、余計な外部パッケージを使わずデフォのものを推奨しているので、それに従っておきます。

実際のところ

デフォでは"$GOPATH/src"以下にあるフォルダを対象に実行されます。
今回は"hoge"を対象に。
外部パッケージ化する場合、"github.com/USERNAME/PACAKGENAME"みたいなディレクトリ構造がお作法のようです。

$ cd $GOPATH/src
$ tree -L 3 hoge/
hoge/
├── hoge.go
└── hoge_test.go

0 directories, 2 files

とりあえず、最小構成のテスト用スクリプトはこちら。
まずはhoge.go

package hoge

func Something(a int16, b int16) int16 {
	return a + b
}

テストのhoge_test.go。
"パッケージ名_test"という命名規則に従う事で、後述のテストコマンドがスムーズに動きます。

package hoge

import "testing"

//テストをやってみたい
func TestSomething(t *testing.T) {
	if Something(1, 3) != 4 {
		//失敗したケース。
		//GoLangではエラーはすぐに処理という文化らしいので
		t.Fatal("something(1,3) should be 4, but Don't matched")
	}
}

では、実行してみましょう。

$ go test PACKAGENAME

という記法なので、以下のように叩いてみると……はい、返り値の型が不正で駄目ですね。
こういうトコロもみてくれます(白目

$ go test hoge
# hoge
hoge/hoge.go:4: cannot use a + b (type int16) as type int in return argument
FAIL	hoge [build failed]

気を取り直して、intをint16にして再度やると

$ go test hoge
ok  	hoge	0.006s

つづき

ドキュメント化時に実行例つきにしたい場合は、"Example~"記法です。
shuzo-kino.hateblo.jp

GoLang用REPL「gore」

GoLangにはサードパーティ提供のREPL「gore」があります。
毎回毎回コンパイルしなくとも動作検証ができます。

実際のところ

導入

$ go get -u github.com/motemen/gore

公式で周辺ツールの導入も勧められているので、
ついでに導入しておきます。

$ go get -u github.com/nsf/gocode
$ go get -u github.com/k0kubun/pp # or github.com/davecgh/go-spew
$ go get -u golang.org/x/tools/cmd/godoc

動作

試しに動かしてみましょう。

$ gore
gore version 0.2.6  :help for help
gore> var something int16
gore> something = 10
10
gore> something + 20
30
gore> something
10
gore> something = something + 20
30

さらに、現状の内容をGOスクリプトとして吐き出すオプションが備わっています。
ためしに":print"を実行すると、以下のような内容で出てきます。

package main

import "fmt"

func __gore_p(xx ...interface{}) {
    for _, x := range xx {
        fmt.Printf("%#v\n", x)
    }
}
func main() { var something int16; something = 10; something = something + 20 }

中断

中断するには"Ctrl-D"。
Pythonと同じですね。

外部のファイルやパッケージを読み込むには?

$ gore --help
Usage of gore:
  -autoimport
    	formats and adjusts imports automatically
  -context string
    	import packages, functions, variables and constants from external golang source files
  -pkg string
    	specify a package where the session will be run inside

参考もと

github.com

Scrapboxでアイディアや情報を相互に連携させる

Scrapboxはアイディアやメモ書きを溜めておくのに丁度いいツールです。
Google Keepなんかがあるみたいです。

登録はよくある他サービスと連携できるタイプ。
私は仕事で使うことになったので、G-Suiteのを連携しときました。
scrapbox.io
登録すると、こんな画面が。
……なんだか妙に殺風景ですね……。
f:id:shuzo_kino:20170416231908p:plain
通常のユースケースだとチーム毎にページをつくって、
そこに情報を集約する感じなようです。

とはいえ社内のを共有するわけにもいかないので……公式サンプル集の中から、不動産屋さんの想定ページを見てみましょう
カード形式のページ群を確認できます。
f:id:shuzo_kino:20170416233119p:plain
ためしに、そのうちひとつを見てみると……末尾の方にリンクがペタペタ貼られています。
f:id:shuzo_kino:20170416231918p:plain
このリンク集がツールの肝で、数が増えると色々と相互作用がでて凄い事になりそうです。
ある種ブレスト的といいますか……。
方法はカンタンで、他ページとの連携は"[ ]"で囲むか、"#"をつけてあげるだけでOKです。

#すごい思いつき
[すごい思いつき]

他にもアイコンを埋め込んだり更新があったらSlackに通知と色々機能があります。
詳しい方法は公式のサンプルを参照して下さい。
Scrapbox ヘルプ - Scrapbox