at posts/single.html

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 で簡単なアプリを作ってみよう。

関連する日記