Home‎ > ‎ProgramTool‎ > ‎Ruby‎ > ‎

Jruby

090326_01_04

うまくいった。
さて、ここでまた問題再燃。
例によってスタイルのワークシート間コピーの良い方法が思い浮かばない。




090325_15_10

動いてたと思ったのもつかの間、今朝試してみたらやっぱりダメだった。
ヨーク考えてみたら、こういうことなんじゃないかと。
usermodel.HSSFxxxxx ってのは、データを取り出すためのAPIを提供するラッパーで
実際のデータが保持されているクラスじゃないんだよね。
で、getXxxx i で呼び出されたときにインスタンスが生成されて、用がなくなるとGCされちゃうと。
だから、再度呼び出したタイミングで、たまたま残っていたら、再利用されてるんじゃないかね。

というわけで、最初からやり直し。
とおもったのだけど、getXxxx i されるときにインスタンスは生成されるわけで、
そのタイミングで設定してやれば良いだけじゃん、ということに気がついた。
試してみる。

090324_23_59

POI を 使うためにやってるJrubyだったが、変なところではまってしまった。

POIは、1つのHSSFWorkbookをいじっている分にはいい。
しかし、複数のHSSFWorkbook間のデータのコピーというのは、元々あまり想定されていないらしくて、
結局のところ、Sheet > Rows > Cell のレベルまで落としてコピーするということになるようだ。
更に、セルのスタイルは、ワークブック直属のHSSFCellStyle にひもづいている。
幸い、HSSFCellStyle だけは、clone という別のブックのスタイルシートにコピーを生成してもっていけるメソッドが用意されている。
しかし、ブックにひもづけられるセルスタイルの数の上限はあまり大きくないので、すべてのセルのスタイルを単純に cloneすると
すぐいっぱいになってしまい、普通にExcelで開こうとすると、アラートがでてしまう。
同じスタイルのモノは、ちゃんと一つにまとめておく必要があるわけ。

そこで、あるセルAのデータを、別のブックのセルBにスタイル毎コピーしようとすると、
セルの所属するブックを探して、スタイルの情報を見つけて比較して…みたいなことをやったり、
例えば、シート丸ごとコピーしたいとなると、Rows > Cell とループしつつ、スタイルをチェックしてやることになる。

SheetもRowもCellも自分がどのBookに所属するかは知っているにきまっているのだが、それを取り出すメソッドがない。
で、HTTPSheet 以下に、自分を含むオブジェクトを覚えておくためのアクセサをつけてやることにしたわけ。

copy_sheet(sheetA,sheetB) ってかんじで、ワークブック間だろうが、ワークブック内だろうが
気にせずにコピーができたら素敵だよねってわけ。

明示的に new する場合はともかく、ファイルから読み込む場合には、ブックが作られる中でシート以下のオブジェクトも
つくられるので、initialize 時に調べて 変数をセットすることにした。

で、Ruby の OpenClass のような感じで、メソッドを追加してみた。

class HSSFWorkbook
    alias :_initialize :initialize
    def initialize input_stream=nil
        if input_stream
            _initialize input_stream
        else
            _initialize
        end
       
        each do |sheet|
            sheet.parent = self
            sheet.workbook = self
            sheet.each do |row|
                row.parent = sheet
                row.workbook = self
               
            end
        end
    end
end

みたいな?

で、なんか動いているようにみえるのだけど、
いつの間にか、sheetやrowに設定した @workbookや@parent変数が消えているのだな。
ループで取り出していくと、ループの途中で消えてしまうのだ。w
しかも消えるところが一定しない。
Heapの設定とか変えると、場所が変わったりする。

sheetやrowに include Enumerable で each とかつけてやるってのは
特に問題なさげに動いちゃったので、いけると思ったのだけど、
include_classでインクルードしたJavaのClassは
本当のRubyのClassではなくて、RubyのClassとほぼ近い形で
扱えるようにしたProxyラッパーみたいなものらしい。
やっぱ JavaのClass にメソッド付け加えるのって無理だったのかなぁと
思いつつ、しかし、なんかあきらめきれなくって。

そもそも、RJBじゃなくって、今まで触ったこともなかった
JRubyでやってみようと思ったのは、
上みたいなコトができそうだと思ったからなんだよねぇ。

で、二日ばかりわかんなかったのだけど、
今日も懲りずに探していたら

 JavaUtilities.extend_proxy
ってのが見つかった。

http://d.hatena.ne.jp/takihiro/20080810/1219216857


下記のような感じで、中身はClassの定義と同じように書いてやる。

JavaUtilities.extend_proxy("org.apache.poi.hssf.usermodel.HSSFWorkbook") do

    #class HSSFWorkbook で書いていた内容とか
    #class定義と同じように メソッドなどを定義

end
#で、後で include_classしてやる
include_class 'org.apache.poi.hssf.usermodel.HSSFWorkbook'

これで、ちゃんとうごいているようにみえる。
やた o/。



Comments