geotools.rb

Geotools, for CRuby + JRuby

Rjbをつなぎとして利用する方法がある。(中略)ここで言うつなぎは、時間上のつなぎだ。つまり、JRubyがより高速化されるまでのつなぎ、という意味。(中略)
Rjbを利用するか、JRubyを利用するかを、環境に依存した特殊な処理と考えることで、差の部分をアプリケーションのメインの処理から分離し、隔離する。
このとき、Rubyの場合、オープンクラスという特徴を利用して、特別なラッパオブジェクト(プロクシ)は作らないですませるようにする。単に分離した初期化モジュールの中で、クラス定義式を直接記述できるからだ。

http://arton.no-ip.info/diary/20070911.html#p02

arton さんにいただいたアイディアを使って、for CRuby + JRubyGeotools 利用モジュールを作ってみたいと思いました。geotools.rb
そこで、(Java-Ruby 連携の話から話題がずれてしまいますが、)まずはこのモジュールの作成方針を決めることにしました。

Geotools (Java) のこんなところをどうにかしたい

geotools.rb は Geotools (Java) を利用するためのものですが、単に Ruby から Geotools へのブリッジとなるだけではなくて、Geotools の使いにくさを改善する「グッドラッパー」を目指したいと思っています。
そこで、私が感じている「Geotools の使いにくさ」を整理します:

  1. Geotools は (Version 2.3 で) 2393 ものクラスがある。
  2. パッケージ階層もかなり深い。あまりに深いので、私の場合必要なクラスは JavaDoc ドキュメントの All classes リストから検索していた。どちらかというと作成者のためのパッケージ階層で、ユーザの利便性を高めるパッケージ階層ではない。
  3. 日常的に使うほとんどのクラスはファクトリから作成しなければならない。ファクトリの名前も *Factory であったり *Builder であったり *s であったりまちまち。
  4. 再設計が頻繁で、deprecated なクラスがごろごろしている。

こんなモジュールにしたい

これらの使いにくさを Ruby に持ち込みたくないので、以下のような対策をとりたいと思っています。

  1. Geotools をブリッジしたクラスの上に、必要に応じて、相対的に大クラス主義なグッドラッパークラス*1を少しずつ、モジュール Geo 上に作成していく。ラッパクラスの入出力は原則 Java オブジェクトではなくて plain Ruby オブジェクトとする*2。Coordinate や Feature のような構造体的オブジェクトは排除し、例えば座標には配列、属性にはハッシュを使うように工夫し、Ruby から見えるクラス数を減らす。JRuby と Rjb の (java.lang.Integer や java.lang.Float などの) 型変換の違い*3も、グッドラッパークラスの中で吸収する。
  2. パッケージの階層はフラット化する。すべての Geotools(Java) クラスを Geo::Tools モジュールの下にロード。
  3. 基本的にファクトリは Ruby グッドラッパークラスには導入しない。効率のためのファクトリであれば、ラッパである Ruby の上ではファクトリパターンである必要はない。原則すべて .new かクラスメソッドでインスタンスを作成させる。
  4. deprecated なクラスは Geo::Tools モジュールにはロードしない。(ロードさせようとしても、パッケージ階層をフラット化するので名前が衝突してしまうことがある。パッケージ移動で deprecated になったクラスがあるので。)

その他、以下の点を設計方針としようと思います。

  • 実際に手元でやっている作業を簡単に片付けることを目的にしてモジュール Geo のグッドラッパークラスを設計する。Geotools が求めているような汎用性は求めない。モジュール Geo は想定用途の8割を簡潔に実現できることを目指す。Geo::Tools から Geotools を直接扱えるので、Geo でできないことは Geo::Tools に降りて実現してもらうというスタンスをとる。

実装は

肝心の実装については、別途エントリします。

*1:例えば既出の FeatureReader や FeatureWriter がそういうラッパクラスになります。

*2:JTS の機能をふんだんに使いたい Geometry クラスは例外。これは plain Ruby オブジェクトにしない。

*3:きちんと整理して把握していないので、後で整理します。