2013/05/02


日本語向け grep コマンド、jvgrep は今まで go-iconv という cgo を使った iconv モジュールに依存していたのだけど、mahonia というキャラクタセットライブラリを使って非依存にした。
mattn/jvgrep - GitHub
https://github.com/mattn/jvgrep
mahonia - Mahonia character-set conversion library for Go - Google Project Hosting

Mahonia is a character-set conversion library implemented in Go. All data is compiled into the execu...

https://code.google.com/p/mahonia/
jvgrep 自体はちょっとファイルサイズが大きくなったけど、ランタイムだと iconv が乗らなくなる分だけメモリ使用量は減ったし、なによりポータブルになった。
ただし mahonia には cp932 などのエイリアスが無いので、JVGREP_ENCODINGS 環境変数を指定していた方は、cp932 を sjis に直す必要があります。

今のところ、dev ブランチですが数日以内には master へブランチにマージします。
Posted at by



2013/04/12


DSAS開発者の部屋:gitでバイナリファイルを気軽に扱えるフィルターを作りました

gits3 は Python でプロトタイプを作った後、 go で作りなおしました。

http://dsas.blog.klab.org/archives/52105107.html
S3、1年たったらタダちゃうし、Dropbox 使いたいよ... ってことで作ってみました。
mattn/git-dropbox - GitHub

Simulate hg largefile on git with dropbox Introduction When we want to add lar...

https://github.com/mattn/git-dropbox
使い方は DSAS さんのブログと同じです。まずインストール。 $ go get github.com/mattn/git-dropbox ~/.gitconfig.git/config にフィルタを登録します。 [filter "dropbox"]
    clean = git-dropbox store
    smudge = git-dropbox load
そしてリポジトリに .gitattributes というファイルを作り、以下の様にフィルタを割り当てます。 *.png  filter=dropbox
*.jpeg filter=dropbox
*.jpg  filter=dropbox
*.gif  filter=dropbox
あとは普通に git add するだけで、dropbox の Apps/git-store というフォルダに格納されていきます。
初回だけ、ブラウザが自動で起動しますのでそこで許可ボタンを押して頂く必要があります。
ローカルにもキャッシュを持っているので、他のユーザと共有する場合は、~/.gitasset/data というフォルダを rsync しておけばOKです。
もしくは dropbox 側で共有するというのもアリかもしれません。
なお、git-dropbox には -nocache というオプションもあるので、上記フィルタの登録時に [filter "dropbox"]
    clean = git-dropbox -nocache store
    smudge = git-dropbox -nocache load
-nocache を指定しておけばディスク容量が気になる方には良いかもしれません。

ちなみにコマンドラインから
$ git dropbox store fugafuga.txt < fugafuga.txt
$ git dropbox load fugafuga.txt
$ git dropbox drop fugafuga.txt
$ git dropbox list
という使い方も出来ます。
どうぞお役立て下さい。
Posted at by



2013/04/11


golang_bot 先日、Lingr がとてもホットなので「Go言語」部屋を作ったのですが、Lingr のしきたりとして、その開発言語でbotを書くというのがあったので(要出典)、go言語でbotを書いた。
mattn/go-lingrbot - GitHub
https://github.com/mattn/go-lingrbot
機能としては3つ。
  • URL が貼り付けられたらそのページのタイトルをお知らせする
  • !godoc math という発言があれば、math パッケージの説明とドキュメントの URL をお知らせする
  • mattn++ などという発言があれば、カウントアップして通算++数をお知らせする
Google AppEngine で動いてます。

URLボット

まず URL のタイトルをお知らせする部分、Go言語は内部エンコーディングが utf-8 であり、オフィシャルからはキャラクタセットを扱えるライブラリが提供されていません。かつ、Google AppEngine 上で動かすので CGO を使った物も動かせません。しかし mahonia というパッケージが CGO 無しでキャラクタセットを扱えるのでそれを使う事にしました。
mahonia - Mahonia - a character-set conversion library for Go - Google Project Hosting

Mahonia is a character-set conversion library implemented in Go. All data is compiled into the execu...

https://code.google.com/p/mahonia/
得られた HTML をパースして meta タグを調べ、キャラクタセットを得た後に、title タグの内容を utf-8 に変換しています。 if charset == "" && n.Type == html.ElementNode && n.Data == "meta" {
    kv := make(map[string]string)
    for _, a := range n.Attr {
        kv[strings.ToLower(a.Key)] = strings.ToLower(a.Val)
    }
    if v, ok := kv["http-equiv"]; ok && v == "content-type" {
        if v, ok = kv["content"]; ok {
            for _, t := range strings.Split(v, ";") {
                tt := strings.Split(strings.TrimSpace(t), "=")
                if len(tt) == 2 && strings.ToLower(tt[0]) == "charset" {
                    charset = tt[1]
                    break
                }
            }
        }
    }
    if v, ok := kv["charset"]; ok {
        charset = v
    }
}
if n.Type == html.ElementNode && n.Data == "title" {
    if charset == "" {
        charset = "utf-8"
    }
    title = mahonia.NewDecoder(charset).ConvertString(n.FirstChild.Data)
}

Godocボット

GoDoc

Popular Packages bitbucket.org/jaybill/sawsij/framework code.google.com/p/biogo code.google.com/p/go...

http://godoc.org/
github からGo言語のパッケージだけを集めてドキュメントを表示してくれるサイトを利用しました。
このサイトは Accept: text/plain ヘッダを付けて要求すると、テキスト形式で応答してくれる機能があったので、その結果からパッケージの説明を抽出しています。

プラスプラスボット

まず発言から mattn++
mattn--
mattn+=3
mattn-=5
などという発言を抽出します。 var rePlus = regexp.MustCompile(`^\s*([a-zA-Z0-9_{^}]+)\+\+\s*$`)
var reMinus = regexp.MustCompile(`^\s*([a-zA-Z0-9_{^}]+)--\s*$`)
var rePlusEq = regexp.MustCompile(`^\s*([a-zA-Z0-9_{^}]+)\+=([0-9])\s*$`)
var reMinusEq = regexp.MustCompile(`^\s*([a-zA-Z0-9_{^}]+)\-=([0-9])\s*$`)
func parsePlusPlus(message string, callback func(nick string, plus int)) bool {
    if rePlus.MatchString(message) {
        m := rePlus.FindStringSubmatch(message)
        callback(m[1], 1)
        return true
    } else if reMinus.MatchString(message) {
        m := reMinus.FindStringSubmatch(message)
        callback(m[1], -1)
        return true
    } else if rePlusEq.MatchString(message) {
        m := rePlusEq.FindStringSubmatch(message)
        callback(m[1], atoi(m[2]))
        return true
    } else if reMinusEq.MatchString(message) {
        m := reMinusEq.FindStringSubmatch(message)
        callback(m[1], -atoi(m[2]))
        return true
    }
    return false
}
そしてそこから呼ばれるコールバックで、GAE のデータストアに格納します。 parsePlusPlus(event.Message.Text, func(nick string, plus int) {
    plusplus := &PlusPlus{nick, 0}
    key := datastore.NewKey(c, "PlusPlus", nick, 0nil)
    err := datastore.Get(c, key, plusplus)
    if err == nil || err == datastore.ErrNoSuchEntity {
        plusplus.Count += plus
        _, err = datastore.Put(c, key, plusplus)
        results += fmt.Sprintf("%s (%d)\n", plusplus.Nickname, plusplus.Count)
    }
})
最後に通算++数を応答します。


これでだいたい、一般的な bot としての機能は満たせました。Lingr のGo言語部屋に24時間常駐しています。
お好きな様にお使い下さい。
Posted at by