Google App Engine の Datastore 上で動く PStore 互換ライブラリを作ってみた (2)
先日の日記の続き。 GAE/JRubyの環境で、 Datastore を PStore のように使えるライブラリを作った。 こんどはちゃんとテスト (RSPEC) とドキュメントを書いて、 GitHub に公開した。 ついでに RubyGem 化にも挑戦している。
使い方
これだけ。
require 'appengine-pstore' # Datastore にデータを保存する db = AppEngine::PStore.new('database.pstore') db.transaction do |db| db[:key1] = "value1" db[:key2] = "value2" end # Datastore に保存したデータを取り出す db.transaction do |db| puts db[:key1] # => "value1" end
PStore のファイル名が、 Datastore のテーブル名(のようなもの)に相当する。 そして、 db の key と value が、テーブル内の key と value (のようなもの)に相当する。 Datastore に格納されているイメージは以下の通り。 dbname が親キーとなって、その子として、 key/value のペアを保存している。
キー | 値 |
PStore('datastore.pstore')::PStore(:key1) | "value1" |
PStore('datastore.pstore')::PStore(:key2) | "value2" |
実際には、Datastore のキーに Ruby のシンボルは登録できないので、 Marshall.dump でシリアライズしている。
それから、データの保存先が Datastore なので、 Datastore の制約の影響を受けている。
- 1つのデータベースに登録できるキーは最大で1000個まで。(実際には1000個以上登録できるけど、 PStore#roots メソッドで1000個のキーしか返ってこない)
- 1つのキーに登録できる値は最大で 1MB まで。
とはいえ、 PStore を保存先に選ぶような用途なら、この制約は問題にならないはず。 逆に言うと、この制約が問題になるような用途なら、 Datastore や DataMapper を使う方がいい。
インストール
GitHub で RubyGems として公開しているので、 gem コマンドでインストールできる。
$ sudo gem install machu-appengine-pstore --source http://gems.github.com
このライブラリ (AppEngine::PStore) を書いた目的
(1) 小さなアプリで簡単にデータを永続化したい
「Sinatra on GAE/JRuby でデータを永続化する」にも書いたように、 GAE の環境でデータを永続化するには Datastore という GAE 独自のデータベースに保存する必要がある。 Datastore にデータを保存するには、 Low Level API である AppEngine::Datastore を使うか、 O/Rマッパーの DataMapper へのアダプタである dm-datastore を使うことになる。
本格的なアプリを作る場合には、これらのライブラリを活用するんだけど、ちょっとしたアプリを作りたいというときには、もう少しシンプルにデータを保存できたほうが便利だったりする。 そういう場合に、 PStore のように簡単に使えるストレージがあると便利だと思ったのが、1つ目の理由。
(2) CGI 環境向けに書いたアプリを GAE/JRuby 上で動かしたい
GAE 環境ではローカルへのファイルの読み書きができないので、 CGI で動かすことを前提にしているアプリ (例えば tDiary ) はそのままでは GAE 上で動かすことができない。 でも、そのアプリがデータを PStore に保存するようになっていれば、素の PStore の代わりに AppEngine::PStore を使うことで、互換性を保ったまま GAE/JRuby で動かせる(かもしれない)。 他にも、 rack など考慮することはたくさんあるけど。 これが2つ目の理由。
(3) Datastore の挙動を学びたい
GAE 環境でのアプリ開発方法を理解するには、 Datastore は避けて通れない。 GAE/JRuby 環境の DataMapper を使うにしても、 GAE/Java 環境の JDO, JPA を使うにしても、その背後で動いている Datastore を理解していないと、トラブル時に対応できなくなる。
理解するためには使ってみるのが一番、という訳で、 Datastore のラッパーライブラリを書いてみた。 特に、キーを使った親子関係(AppEngine::PStore の場合は dbname と key が親子関係になっている)の構築と、トランザクションの概念を把握できたかな。
GitHub で公開し、 RubyGem 化するまで
jeweler というツールを使うことで、プロジェクトのひな形の作成から RubyGem 化、さらには GitHub への公開までをサポートしてくれる。
まずはインストール。
$ sudo gem install jeweler
次にひな形の作成。ライブラリ名を引数にして jeweler コマンドを実行する。
$ jeweler --rspec --create-repo appengine-pstore
これで、 appengine-pstore というフォルダの下に、 RubyGem 化に必要な各種ファイルのひな形 (README.rdoc, Rakefile, lib, specディレクトリなど) が作られる。 さらに --create-repo オプションをつけると、いきなり GitHub 上にひな形の状態でファイルがアップされる。
lib/appengine-pstore.rb に作成したライブラリをコピーして、 spec/appengine-pstore_spec.rb に SPEC ファイルを書いていく。 README.rdoc にライブラリの説明を書いて、 Rakefile の Jeweler::Tasks.new ブロックに RubyGem の説明を書く。
rake コマンドでマイナーバージョンを1つ上げる。 (初期値が 0.0.0 なので、 0.1.0 になる)
$ rake version:bump:minor
これで VERSION ファイルの中身が書き換わる。
さらに gemspec ファイルを作成。 Rakefile の Jeweler::Tasks.new ブロックに書いた内容が使われる。
$ rake gemspec
ここまででコミット。
$ git commit -A
テストしたり、ローカル環境に作成した RubyGem ライブラリをインストールしたり。
$ rake spec $ rake install
キリがいいタイミングで GitHub にアップロード。
$ git push
GitHub のプロジェクトページで、 RubyGems にチェックを入れておけば自動的に gem 化してくれる。 しばらくすると GitHub から gem 化が完了したとのメールが届く。 gem コマンドで見えるようになってる。
$ gem search -r machu-appengine-pstore
と、ざっとこんな感じ。 詳しくは、(次回試そうと思っている)GitHubでRubyGemを公開する手順 - 岩本隆史の日記帳が参考になる。
感想
思った以上に簡単に、 RubyGem 化や GitHub での公開ができた。 最初は SPEC やドキュメントを書くのが面倒だと思ったけど、書いてみると逆に無いと不安になる。 特に SPEC ファイルを書くことで、当面のゴールを明確にできた。
英語はかなり怪しいけどね…。 でも、書いて恥をかかないとうまくならない。きっと。
次は
GAE/JRuby + Sinatra + AppEngine::PStore で簡単なアプリを作ってみよう。