2011-05-11 3 views
4

Rubyでは、「to_yaml」メソッドの出力をファイルに保存することによって、オブジェクトをYAMLドキュメントに転送、つまりシリアル化することができます。その後、YAML::loadメソッドを使用して、このYAMLファイルを再度読み取る、つまり逆シリアル化することができます。さらに、基になるクラス/オブジェクトのすべてのメンバーにフルアクセスできます。外部ソースからYAMLドキュメントをどのように非直列化し、クラスメンバーにフルアクセスできますか?

これはすべて、Rubyを単一のプラットフォームとして使用している限り有効です。 Javaでオブジェクトをシリアル化してRubyでデシリアライズすると、NoMethodError例外のためにオブジェクトにアクセスできなくなりました。これは、オブジェクト/ローカル・データ型の名前が異なるシステムの名前に起因するためです。

考えるとRubyのクラス "自動車":

# A simple class describing a car 
# 
class Car 
    attr :brand, :horsepower, :color, :extra_equipment 

    def initialize(brand, horsepower, color, extra_equipment) 
    @brand = brand 
    @horsepower = horsepower 
    @color = color 
    @extra_equipment = extra_equipment 
    end 
end 

シンプルインスタンスの作成:

# creating new instance of class 'Car' ... 
porsche = Car.new("Porsche", 180, "red", ["sun roof", "air conditioning"]) 

次の出力でporsche.to_yaml結果の呼び出し:

--- !ruby/object:Car 
brand: Porsche 
color: red 
extra_equipment: 
- sun roof 
- air conditioning 
horsepower: 180 

は私がで直列化復元をテストしますYAML出力をロード:

# reading existing yaml file from file system 
sample_car = YAML::load(File.open("sample.yaml")) 
puts sample_car.brand # returns "Porsche" 

これは期待通りに動作しますが、今度は、YAMLドキュメントが別のシステムによって生成され、YAML-準拠オブジェクトの記述を有するが、ルビーへの参照を欠いたと仮定する、「!Car」、代わりに「!ruby/object:Car」の:

--- !Car 
brand: Porsche 
color: red 
extra_equipment: 
- sun roof 
- air conditioning 
horsepower: 180 

このコード:

# reading existing yaml file from file system 
sample_car = YAML::load(File.open("sample.yaml")) 
puts sample_car.brand # returns "Porsche" 

戻りこの例外:

/path/yaml_to_object_converter.rb.rb:27:in `<main>': 
undefined method `brand' for #<YAML::DomainType:0x9752bec> (NoMethodError) 

「外部」YAML文書で定義されたオブジェクトを処理する方法はありますか? IRBシェル内sample_carがあると評価私にとって

+0

多分これは役立ちます。http://blog.bytemine.net/2009/12/07/yaml-in -java-and-ruby-welcome-yamlbeans –

+0

(タイトルの)「クラスメンバー」はJava用語ですか? –

+0

@Andrew:私はこれがむしろJavaの用語であり、このRubyの文脈では少し不正確であると認めます。私はクラス変数とクラスメソッドを意味しました。 – Bionicman303

答えて

0

=> #<Syck::DomainType:0x234df80 @domain="yaml.org,2002", @type_id="Car", @value={"brand"=>"Porsche", "color"=>"red", "extra_equipment"=>["sun roof", "air conditioning"], "horsepower"=>180}> 

それから私は​​を発行:

=> {"brand"=>"Porsche", "color"=>"red", "extra_equipment"=>["sun roof", "air conditioning"], "horsepower"=>180} 

ハッシュはどれ。これは、あなたがそうのようCarにクラスメソッドを追加することにより、あなた Carオブジェクトを構築することができることを、意味:

porsche_clone = Car.from_hash(sample_car.value) 

返さ:

def self.from_hash(h) 
    Car.new(h["brand"], h["horsepower"], h["color"], h["extra_equipment"]) 
end 

は、その後、私はそれを試してみました

=> #<Car:0x236eef0 @brand="Porsche", @horsepower=180, @color="red", @extra_equipment=["sun roof", "air conditioning"]> 

それはそれを行うのが最も醜い方法です。他にもあるかもしれない。=)

EDIT(19月 - 2011年):ところで、ちょうど考え出しずっと簡単な方法:このため

def from_hash(o,h) 
    h.each { |k,v| 
    o.send((k+"=").to_sym, v) 
    } 
    o 
end 

は、あなたのコンストラクタは、パラメータを必要としてはならない、あなたのケースで動作します。そして、あなたは簡単に行うことができます。

foreign_car = from_hash(Car.new, YAML::load(File.open("foreign_car.yaml")).value) 
puts foreign_car.inspect 

...あなたを与える:

#<Car:0x2394b70 @brand="Porsche", @color="red", @extra_equipment=["sun roof", "air conditioning"], @horsepower=180> 
+0

私はそれが醜いとは本当に考えていません。私はオブジェクトを基底型に減らして送信する防御プログラミングと考えています。オブジェクトを送ることによって私たちを助けようとしているYAMLのケーキの上にアイシングが施されていますが、その機能もまた途中で取り込まれます。基本的な値に移動すると、データは問題なく移動します。 –

+0

私は、クラスメソッドを追加しなくても、プロセスをさらに自動化できるGemがあると確信しています。 ;)そうでなければ、メソッドはきれいです。 – dimitarvp

+0

ええ、宝石は、それを呼び出すコードを合理化しますが、ケーキが塊であるという事実を隠すために、より多くの氷結でケーキを砕いていると思います。私はあなたに同意しますが、宝石を再利用することは良い方法です。おそらく問題のクラスに 'to_yaml'メソッドを追加したでしょうが、それは私の多くの脳の欠陥の一つです。 –

関連する問題