(ヽ'ω`) < RubyでPythonのpickleを読み込む
(ヽ'ω`) < 何するの?
rubyでpythonのcPickleライブラリの.pckファイルを読み込む。
(ヽ'ω`) < ライブラリがあるはず
pickleのフォーマット自体は公開されているので、当然Rubyで読み込むためのライブラリなんてのは、どこかの頭のいい人が作ってくれてるはず。 そういう風に考えていた時期が私にもありました…
kuroneko/unpickle-rb · GitHub いや、あるにはあるんだけど、サポートしてるのがプロトコル0までなので、作者さんの言うとおりvery limited
This is a very limited tool to unpickle python 'pickle' objects.
(ヽ'ω`) < どうしようか
自分でライブラリを作成する? → (ヽ'ω`) < 無 理
というわけで、直接読み込むのではなく、PythonをRubyの中で実行してその結果を受け取るという斜め上の発想に行き着く。
(ヽ'ω`) < rubypython
rubypythonでrubyからpythonのスクリプトを実行することができる。
halostatue/rubypython · GitHub
基本的なオブジェクトのRuby<=>Pythonオブジェクト変換は可能らしいのだが、 PythonのDictがネストしていたり、Arrayを含んでいるとダメっぽい。 という事がメモしてあったんだけど、ソースを記述するのを忘れてた。 多分Readmeとかに書いてあったと思うんだけど… 今書いてないってことはこのあたりは修正されたのかも。
以下のデータが相互変換が可能 https://github.com/halostatue/rubypython/blob/master/lib/rubypython/rubypyproxy.rb
Only the following Ruby types can be represented in \Python:
* String
* Array
* Hash
* Fixnum
* Bignum
* Float
* Symbol (as a String)
* Proc
* Method
* +true+ (as True)
* +false+ (as False)
* +nil+ (as None)
Pythonスクリプトの実行結果オブジェクトの#rubifyメソッドを呼び出すことで変換ができる。
(ヽ'ω`) < 簡単な使い方
rubypythonインストール
# gem install rubypython
使用は3ステップが基本
require 'rubypython' # startして RubyPython.start # 必要なライブラリをインポートして cPickle = RubyPython.import("cPickle") # ライブラリを利用 p cPickle.dumps("Testing RubyPython.").rubify # stopで止める RubyPython.stop
(ヽ'ω`) < まぁ簡単
(ヽ'ω`) < 実際に使用してみた
今回の自分のケースでは、mailmanが作成したpckファイルを読み込みたい、という状況。 mailmanのpckファイルの中身はdictをpickle化したものと思われるが、先の説明の通り dictがネストしており、arrayも内包しているため、そのままでは正常に値の取得ができなかった。 そこで、一度jsonとして出力したものをRuby側のjsonライブラリで読み込むことで値を取得した。
require 'rubypython' # Pythonインタープリタの開始 RubyPython.start pickle = RubyPython.import('cPickle') json = RubyPython.import('json') # pckファイルを読み込む config_pickle = open(pck_file, 'rb').read # Pythonオブジェクトとしてロード config = pickle.loads(config_pickle) # JSON形式に変換 config_json = json.dumps(config).rubify # RubyのHashに変換 config_hash = JSON.parse(config_json) ## ## config_hashにpickle内のデータが保存されているので色々処理 ## #Pythonインタープリタの終了 RubyPython.stop
(ヽ'ω`) < …最初からPythonでやればいいんじゃ?
(ヽ'ω`) < 当時は若く、Rubyオンリーでした