2010年10月9日土曜日

Ruby1.9.2で日本語を含むYAMLを出力する時、バイナリ文字列化されないようにする

RubyのYAML

Ruby(1.8以上)ではYAMLライブラリが標準添付ライブラリです。
そのため、YAMLを扱うには「require 'yaml'」とするだけです。

これでYAML.load(YAML形式から読み込み)、YAML.dump(YAML形式への出力)、
さらに様々なオブジェクトで to_yaml メソッドが使えるようになります。


日本語を含むYAMLを出力

しかしこのままでは、日本語文字列を含んだオブジェクトを
YAMLドキュメントとして出力すると、日本語部分がバイナリ文字列になってしまいます。
これでは人間にも読みやすいというYAMLの特徴が台なしです。

# -*- coding: utf-8 -*-
require 'yaml'

puts YAML.dump({'あ' => 'い'}) 


# 【出力結果】
# --- 
# "\xE3\x81\x82": "\xE3\x81\x84"

これを解消する方法を軽く検索してみると、
gemで違うYAMLライブラリを入れるとか、パッチをあてるなどの情報が出てきます。

Ruby1.9.2では:Psych

Ruby1.9.2からは、PsychというYAMLパーサも標準添付ライブラリになっています。
(以前からあるのは、Syckというライブラリ)
このPsychは「require 'yaml'」するだけでは有効にならないので、以下のようにします。

# -*- coding: utf-8 -*-
require 'yaml'

YAML::ENGINE.yamler = 'psych'

puts YAML.dump({'あ' => 'い'})


# 【出力結果】
# ---
# あ: い

今度は日本語がバイナリ文字列化されませんでした。


この方法はTwitter上で @sakuro さんに教えて頂きました。
ありがとうございました!

(2010年10月9日夜に追記↓)

YAML::ENGINE.yamlerを使わなくとも、「yamlの前にpsychがロードされていればOK」とのことです。
つまり以下の方法でも良いということになります。

# -*- coding: utf-8 -*-
require 'psych' # 追加
require 'yaml'

puts YAML.dump({'あ' => 'い'})


# 【出力結果】
# ---
# あ: い

上記の追記はTwitterで @n0kada さんに教えて頂きました。感謝です!

ちょっと実験

require 'psych'だけではどうでしょうか。

# -*- coding: utf-8 -*-
require 'psych'

puts YAML.dump({'あ' => 'い'})

# 【出力結果】
# uninitialized constant Object::YAML (NameError)

エラーになります。YAMLは使えません。

ではrequire 'yaml'が先で、require 'psych'が後だったら?

# -*- coding: utf-8 -*-
require 'yaml'
require 'psych'

puts YAML.dump({'あ' => 'い'})

# 【出力結果】
# --- 
# "\xE3\x81\x82": "\xE3\x81\x84"

Syckが使われてしまうようです。

1.9.2なのにPsychが使えないよ?

Ruby1.9.2なのにPsychが使えない場合は、 libyaml-dev を入れてからRubyを再コンパイルしましょう(パッケージ名は、Ubuntu 等の場合)。

Psychという名前

PsychであってPsyckじゃないんですね。
前のライブラリがSyckなのでちょっと紛らわしい。

Ruby1.9.3では(2011年11月28日追記)

コメントで教えて頂いた情報によると、
Ruby1.9.3からは、Psychの方がデフォルトになっているようです。
ですので、require 'yaml' 以外に余計な事を書かなくても、日本語を正しく扱うことができます。

逆に Syck を使いたい場合は、YAML::ENGINE.yamler='syck' としなければなりません。

2 件のコメント:

  1. よしのぼりん2011年11月28日 23:22

    Ruby 1.9.3では、デフォルトでPsychになったようですね。Syckをつかうときは、YAML::ENGINE.yamler=‘syck’と明記する必要があるみたいです。
    Psychはよく知らないのですが、Syckの日本語文字の扱いには手を焼いていたので、期待しています。

    返信削除
  2. >よしのぼりんさん

    情報ありがとうございます!
    確かに、require 'yaml' 以外に何もつけなくても、
    日本語をきちんと表示してくれました。

    記事の方にも追記しておきました!

    返信削除

フォロワー