Fork me on GitHub

2011/11/16


このエントリーをはてなブックマークに追加
最近バージョン1リリースを目標にガチャガチャと凄い勢いでパッケージ構成が見直されていますが、その中でGo言語向けに新しいパッケージが入りました。
これまででもsqlite3やmysql向けに何人もの人が個性的なドライバを書き、インタフェースも揃わず、中には開発をやめ、それを使ったアプリケーションの開発も止まるという悪循環になろうとしていました。
そんな中入ったのがexp/sqlです。expなのでまだ実験段階なのですが、Go言語としてはデータベースの枠組みだけ提供し、ドライバはサードパーティに作ってもらうというもくろみです。これによりデータベースに関してはドライバを構成通りに開発すれば使用者側は同じインタフェースで呼び出せるという物です。PerlでいうDBIですね。

誰もあまり手を付けてなさそうだったので、3本ばかしドライバを書かせて頂きました。

SQLite3

mattn/go-sqlite3 - GitHub

sqlite3 driver for go that using exp/sql

https://github.com/mattn/go-sqlite3
ご存知、みんな大好きSQLite3ですね。golang-gonutsに放流した時にはなかなか反響がよろしくて良かったです。
ちなみにこれを使ってデータベースを扱うコードを書くと、こんな感じになります。
package main

import (
    "exp/sql"
    "fmt"
    _ "github.com/mattn/go-sqlite3"
    "os"
)

func main() {
    os.Remove("./foo.db")

    db, err := sql.Open("sqlite3""./foo.db")
    if err != nil {
        fmt.Println(err)
        return
    }

    sqls := []string{
        "create table foo (id integer not null primary key, name text)",
        "delete from foo",
    }
    for _, sql := range sqls {
        _, err = db.Exec(sql)
        if err != nil {
            fmt.Printf("%q: %s\n", err, sql)
            return
        }
    }

    tx, err := db.Begin()
    if err != nil {
        fmt.Println(err)
        return
    }
    stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer stmt.Close()

    for i := 0; i < 100; i++ {
        _, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
        if err != nil {
            fmt.Println(err)
            return
        }
    }
    tx.Commit()

    rows, err := db.Query("select id, name from foo")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer rows.Close()

    for rows.Next() {
        var id int
        var name string
        rows.Scan(&id, &name)
        println(id, name)
    }
}

Microsoft ActiveX Object DataBase

mattn/go-adodb - GitHub

Microsoft ActiveX Object DataBase driver for go that using exp/sql

https://github.com/mattn/go-adodb
まだまだCOMは死んでない。いまだに使われてるADODBをCGOを使わずに実装したgo-oleを使い、データベース操作出来る様にしました。
mattn/go-ole - GitHub

win32 ole implementation for golang

https://github.com/mattn/go-ole
ちなみにこれを使うと、AccessのMDBファイルを弄れたりCSVファイルにSQLを流せたり出来ます。便利!
こちらについては1人だけでしたが「Cool!」を頂きました。良かったですね。そうですね。

Yahoo! Query Language

mattn/go-yql - GitHub

YQL database driver for golang.

https://github.com/mattn/go-yql
これを使うとSQLでRSSがセレクト出来たりして嬉しいのですが...
package main

import (
    "exp/sql"
    "fmt"
    _ "github.com/mattn/go-yql"
)

func main() {
    db, _ := sql.Open("yql""")

    stmt, err := db.Query(
        "select * from rss where url = ?",
        "http://blog.golang.org/feeds/posts/default?alt=rss")
    if err != nil {
        fmt.Println(err)
        return
    }
    for stmt.Next() {
        var data map[string]interface{}
        stmt.Scan(&data)
        fmt.Printf("%v\n", data["link"])
        fmt.Printf("  %v\n\n", data["title"])
    }
}
いかんせん、Googleプロダクトの言語なので、「YQLドライバ作ったよ!」なんて言えずにおそらくお蔵入りするかと思います。

追記
ちなみに僕の思惑では、おそらく今後Google App EngineはRDBMSを採用する事になって(有料かもね)、そのエンジン構成としてこれを使わせるんじゃないかなと思っています。例えばappspotではGoogleが提供する(中身は何かは知らない)RDBMSで、ローカルの開発環境向けにはSQLiteみたいな...。
Posted at 21:09 in ソフトウェア::lang::go
Tagged as: ado, adodb, golang, sqlite, yql
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2011/08/19


このエントリーをはてなブックマークに追加
日本語を扱っていて困るのがgrep。正規表現パターンにマルチバイト文字を混ぜられなかったり、windowsで動かすと"表"の様に2バイト目にbackslashが混じる文字で動作しなくなったりします。
さらに複数のエンコーディングで書かれたファイルが散らばっていると一度のgrepで検索出来なかったりもします。
vimに限っては、内蔵のvimgrepを使う事で解決出来ますが、見つかったファイルをバッファに開いてしまうという挙動がある為、grepオリジナルの動作を求めている人にとっては都合の悪い物だったりもします。

vimgrepの様に複数のエンコーディングに対応していて、検索パターンにマルチバイト文字を含んだ正規表現が使えて、windowsでもちゃんと動いて、ついでといっちゃあなんだが、"**/*.txt"で再帰検索してくれる様なgrep無いかなぁと思ってたんですが、やっぱり無いので作りました。
こういう処理、実はGo言語が得意でして、意外と短いコードで書けてしまったりします。
もちろんバイナリが吐けるので配布も簡単。
mattn/jvgrep - GitHub

grep for japanese vimmer

https://github.com/mattn/jvgrep
内部ではgo-iconvという、元々別の方が作ったiconvモジュールをwindowsでダイナミックローディング対応させ使っています。もちろんスタティックリンクなので別途調達する必要もありませんが。なお、windows上での動作にはiconv.dllかlibiconv.dllが必要です。
Go言語の開発環境を持っていらっしゃる方ならば、最新までバージョンを上げて頂いた後
# goinstall github.com/mattn/jvgrep
として頂いたらインストールしてくれます。go-iconvが依存物としてインストールされますが、linux等ではiconvのヘッダおよびライブラリが必要になりますので注意です。windowsはダイナミックローディングしているので必要ありません。
ちなみに、win32版のみ最新版のjvgrepをダウンロード出来る様にしてあります。上記リンクから"Downloads"をクリックして"jvgrep-win32.tar.gz"を落とし、解凍して下さい。iconv.dllを同梱しています。ウィルスチェック済み。

使い方は普通のgrepです。
# jvgrep 表[現示] *.txt
この様に日本語で、しかもwindowsだと誤動作するダメ文字にも対応しています。
まぁGo言語は内部では全てutf-8なので、当たり前ですが。
尚、Goのregexpパッケージがまだ発達途上なので":alpha:"の様な文字クラスは使えません。使いたい人は今すぐGo Developer Teamに参加してpatchを書いて下さい。(使える様になりました)

vimmer向けに
# jvgrep 表[現示] **/*.txt
という使い方も出来ます。 オプションは現状ありません。出力結果はgrepで"-n"オプションを付けた時の出力内容に合わせてあります。
サポートしているエンコーディングは
  • iso-2022-jp-3
  • iso-2022-jp
  • euc-jisx0213
  • euc-jp
  • utf-8
  • ucs-bom
  • euc-jp
  • eucjp-ms
  • cp932
と、ほぼ全ての日本人向けエンコーディングに対応出来ています。
仕組みはvimと同じです。 vimからは
set grepprg=jvgrep
とvimrcに書けば使えます。
:grep 表[現示] **/*.txt
といった感じにお使い下さい。
Posted at 20:52 in ソフトウェア::lang::go
Tagged as: grep, jvgrep, vim
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2011/08/04


このエントリーをはてなブックマークに追加
最近はクラウドサーバ等、割と色んな所で見かける様になったuWSGIですが...
uWSGI

uWSGI is a fast, self-healing and developer/sysadmin-friendly application container server coded in pure C.

http://projects.unbit.it/uwsgi/
Perlだとhirataraさんが書いた記事や
Hokkaido.pmでuWSGIについてLTした - a geek born in Tomakomai

uWSGI はデフォルトではhttpではなくuwsgiプロトコルを喋るので、uwsgiプロトコルを喋れるフロントエンドを立ち上げます...

http://d.hatena.ne.jp/hiratara/20110718/1310950381
Plack::App::uWSGIが参考になります。
hiratara/p5-Plack-App-uWSGI - GitHub

Plack::App::uWSGI - a PSGI frontend of uwsgi.

https://github.com/hiratara/p5-Plack-App-uWSGI
こちらはuwsgiに付属のpsgiプラグインを使っています。なお、uwsgiのcontribフォルダにはPlack::Handler::Uwsgiが同梱されているので、例えばnginx.confに
server {
  listen 8082;
  location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:9999;
  }
}
と書いておき
use Plack::Handler::Uwsgi;

my $app = sub {
    return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Hello World' ] ];
};
Plack::Handler::Uwsgi->new(host=>'127.0.0.1'port=>9999)->run($app)
こんな感じに走らせると、"http://server:8082/" で"Hello World"が表示されます。もちろんフロントエンドであるnginxの設定を弄ればキャッシュやタイムアウトも変更出来るという仕組みです。

ちなみにcontribフォルダにはrubyやjavaのコードも置いてあります。つまりuWSGIプロトコルを実装すれば、言語を問わずフロントエンドをnginxとしたワーカーが作れるって事ですかね。

Go言語も仲間に入れてよ!って事でuWSGIリスナを書いてみました。
mattn/go-uwsgi - GitHub

uwsgi implement for go

https://github.com/mattn/go-uwsgi
あくまでリスナという位置づけなので、unixドメインソケットのファイルや、tcpソケットなど、goでnet.Listenerとして扱える物であれば何でもokです。これを使うとファイルサーバがほんの数行で書けてしまいます。

nginx.confが
server {
  listen 8081;
  location / {
    include uwsgi_params;
    uwsgi_pass unix:///var/run/go-uwsgi/socket;
  }
}
であれば
package main

import (
    "net"
    "http"
    "github.com/mattn/go-uwsgi"
    "os"
)

func main() {
    s := "/var/run/go-uwsgi/socket"
    os.Remove(s)
    l, e := net.Listen("unix", s)
    if e != nil { panic(e.String()) }
    http.Serve(&uwsgi.Listener{l}, http.FileServer(http.Dir(".")))
}
これだけですね。簡単です。
初めてのPerl 第5版 初めてのPerl 第5版
Randal L. Schwartz
オライリージャパン / ¥ 3,780 (2009-10-26)
 
発送可能時間:在庫あり。

Posted at 03:16 in ソフトウェア::lang::go
Tagged as: golang, uwsgi
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2011/07/25


このエントリーをはてなブックマークに追加
Go言語は例外発生時にdeferを使いrecover()を呼び出す手法で例外補足する事ができ、よくこれは「特殊なので分かり辛い」とか「try/catch/finallyを実装しない理由」と言われる事があります。
確かに一般的な例外補足と比べるとチープに見えたりもします。
なんとなく、以前書いたjsdeferredのGo言語版godeferredを使えば出来るんじゃないかと思ったので書いてみた。
mattn/go-try - GitHub

try/catch/finally for go

https://github.com/mattn/go-try
これを使うとこんな感じに書けます。
Try(func() {
    panic(1)
}).Catch(func(n int) {
    println("int exception:", n)
})
制御構文ではないので、メソッドチェインを使って実現しています。実際にはTry関数からCatchメソッドもしくはFinallyメソッドしか呼び出せないCatchOrFinallyオブジェクトを返しています。CatchメソッドはまたCatchOrFinallyオブジェクトを返すという仕組みですね。いわゆるMaybeモナドといった所でしょうか。
int例外だけでなく
Try(func() {
    panic("foo")
}).Catch(func(s string) {
    println("string exception:", s)
})
string例外や他の型も扱えます。またpanicの例外補足だけでなく
package main

import (
    . "github.com/mattn/go-try/try"
    "fmt"
)

func main() {
    Try(func() {
        v := 0
        println(1 / v)
    }).Catch(func(n int) {
        // not pass
        println("Caught int exception:", n)
    }).Catch(func(s string) {
        // not pass
        println("Caught string exception:", s)
    }).Catch(func(e RuntimeError) {
        fmt.Println("Caught runtime exception:", e)
        for _, st := range e.StackTrace {
            fmt.Printf("  %s:%d\n", st.File, st.Line)
        }
    }).Finally(func() {
        println("finalize")
    })
}
この様なランタイムエラーも補足出きるようになっていて、RuntimeErrorオブジェクトのStackTraceフィールドからスタックトレースも参照出来ます。
ただ残念ながらスタックトレースの行番号は、関数呼び出し位置になるので、上記の例でいうとTryブロックのどの位置で例外が発生してもTry関数の呼び出し位置になってしまっています。
追記
修正しました。こんな感じに出力されます。
Caught runtime exception: runtime error: integer divide by zero
  /home/mattn/dev/go-try/try/foo.go:11
  /home/mattn/dev/go/src/pkg/reflect/value.go:583
  /home/mattn/dev/go/src/pkg/reflect/value.go:433
  /home/mattn/dev/go-try/try/try.go:51
  /home/mattn/dev/go-try/try/foo.go:15
  /home/mattn/dev/go/src/pkg/runtime/386/asm.s:94
  /home/mattn/dev/go/src/pkg/runtime/proc.c:244
finalize

まぁGo言語でちょっとリッチな書き方したいなって人向けです。
# 誰だよそれ
Posted at 02:00 in ソフトウェア::lang::go
Tagged as: golang
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip