Как десериализовать документы YAML из внешних источников и иметь полный доступ к ученикам? - PullRequest
4 голосов
/ 11 мая 2011

В Ruby любой объект можно перенести, т.е. сериализовать, в документ YAML, сохранив выходные данные метода "to_yaml" в файл.После этого этот файл YAML можно снова прочитать, т. Е. Десериализовать, используя метод YAML::load.Более того, у каждого есть полный доступ ко всем членам базового класса / объекта.

Все это действует, пока я использую Ruby в качестве единой платформы.После сериализации объектов в Java и десериализации их в Ruby я больше не могу получить доступ к объекту из-за исключения NoMethodError.Это связано с тем, что объекты / локальные типы данных именуются в разных системах.

Для класса Ruby "Car":

# 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 был создан другой системой, и в нем отсутствует какая-либо ссылка на Ruby, хотя в нем есть описание объекта, соответствующее yaml, "!Car" вместо "!ruby/object:Car":

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

Thiscode:

# 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?

1 Ответ

0 голосов
/ 11 мая 2011

Для меня sample_car в оболочке IRB оценивается как:

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

Затем я выдал sample_car.value:

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

Что является хешем.Это означает, что вы можете создать ваш объект Car, добавив метод класса к Car примерно так:

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

Затем я попробовал это:

porsche_clone = Car.from_hash(sample_car.value)

Что вернуло:

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

Это самый уродливый способ сделать это.Там могут быть другие.=)

РЕДАКТИРОВАТЬ (19-May-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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...