(ヽ´ω`) < 助けてほしいマン

わからないことを助けてほしいマンが書くブログ

(ヽ'ω`) < RubyでPythonのpickleを読み込む

(ヽ'ω`) < 何するの?

rubypythonのcPickleライブラリの.pckファイルを読み込む。

(ヽ'ω`) < ライブラリがあるはず

pickleのフォーマット自体は公開されているので、当然Rubyで読み込むためのライブラリなんてのは、どこかの頭のいい人が作ってくれてるはず。 そういう風に考えていた時期が私にもありました…

kuroneko/unpickle-rb · GitHub いや、あるにはあるんだけど、サポートしてるのがプロトコル0までなので、作者さんの言うとおりvery limited

This is a very limited tool to unpickle python 'pickle' objects.

(ヽ'ω`) < どうしようか

自分でライブラリを作成する?  → (ヽ'ω`) < 無 理

というわけで、直接読み込むのではなく、PythonRubyの中で実行してその結果を受け取るという斜め上の発想に行き着く。

(ヽ'ω`) < 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オンリーでした