mattn/go-lingrbot - GitHub機能としては3つ。
https://github.com/mattn/go-lingrbot
- URL が貼り付けられたらそのページのタイトルをお知らせする
!godoc math
という発言があれば、math パッケージの説明とドキュメントの URL をお知らせする- mattn++ などという発言があれば、カウントアップして通算++数をお知らせする
URLボット
まず URL のタイトルをお知らせする部分、Go言語は内部エンコーディングが utf-8 であり、オフィシャルからはキャラクタセットを扱えるライブラリが提供されていません。かつ、Google AppEngine 上で動かすので CGO を使った物も動かせません。しかし mahonia というパッケージが CGO 無しでキャラクタセットを扱えるのでそれを使う事にしました。mahonia - Mahonia - a character-set conversion library for Go - Google Project Hosting得られた HTML をパースして meta タグを調べ、キャラクタセットを得た後に、title タグの内容を utf-8 に変換しています。
Mahonia is a character-set conversion library implemented in Go. All data is compiled into the execu...
https://code.google.com/p/mahonia/
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ボット
GoDocgithub からGo言語のパッケージだけを集めてドキュメントを表示してくれるサイトを利用しました。
Popular Packages bitbucket.org/jaybill/sawsij/framework code.google.com/p/biogo code.google.com/p/go...
http://godoc.org/
このサイトは
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, 0, nil)
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時間常駐しています。
お好きな様にお使い下さい。