0

I have a YAML file looks like this:

--- !ruby/object:Hi
num: 1
--- !ruby/object:Hi
num: 2

and my ruby code:

require 'yaml'
class A
 attr_accessor :num
 def initialize num
  @num=num
 end
end
a=A.new 1
b=A.new 2
File.open 'test.yml', 'r+' do |f|
 f.write YAML.dump a
 f.write YAML.dump b
 f.seek(0)
 #c=obj a
 #d=ojb b
end

and i want to make p c and p d output like:

#<A:0x00000 @num=1>
#<A:0x00001 @num=2>
ader
  • 5
  • 5

3 Answers3

4

I'm not sure why certain people are so adamant that you can't put more than one YAML document in a single file, since the YAML format was explicitly designed to accommodate that particular use case. In Ruby, you can parse multiple documents using YAML.load_stream, which will return the deserialized objects as an array:

require "yaml"

class A
  attr_accessor :num
  def initialize num
    @num = num
  end
end

a = A.new 1
b = A.new 2

File.open "test.yml", "r+" do |f|
  f.write YAML.dump(a)
  f.write YAML.dump(b)
  f.seek(0)

  c, d = YAML.load_stream(f)

  p c
  # => #<A:0x000055d423387cd0 @num=1>
  p d
  # => #<A:0x000055d423387528 @num=2>
end

You can also pass a block to YAML.load_stream, in which case it'll be called for each document:

YAML.load_stream(f) do |obj|
  p obj.num
end
# => 1
# => 2

You can see both in action at repl.it: https://repl.it/@jrunning/FavorableElderlyAddition

Jordan Running
  • 102,619
  • 17
  • 182
  • 182
-1
object = JSON.parse(YAML::load_file("./test.yaml").to_json, object_class: OpenStruct)

Not 100% sure what format these will come out in, but it'll give you a good place to start

Mark
  • 6,112
  • 4
  • 21
  • 46
  • What is JSON doing here? – Sergio Tulentsev Mar 12 '18 at 14:53
  • It should turn it into a JSON that OpenStruct can create an object from? Was taking the answer from: https://stackoverflow.com/questions/28521571/create-nested-object-from-yaml-to-access-attributes-via-method-calls-in-ruby – Mark Mar 12 '18 at 14:57
  • That answer is not applicable here, as the question is different. Look closer at the input file(s), you may spot a critical difference. – Sergio Tulentsev Mar 12 '18 at 15:01
  • @Mark, Also, if you copy code from somewhere else, please add some attribution. This is one of the few requirements you HAVE to apply when using code form StackOverflow. See https://stackoverflow.blog/2009/06/25/attribution-required/ – Holger Just Mar 12 '18 at 18:32
-1

I would prefer to write objects into separate files but your way of serialization is also ok. Here is the solution for your case;

RUBY_OBJECT = '--- !ruby/object:'

def load_objects(file_content)
  object_contents = file_content.split(RUBY_OBJECT)

  object_contents.map do |object_content|
    YAML.load(RUBY_OBJECT + object_content)
  end.compact
end

##########

File.open 'test.yml', 'r+' do |f|
  f.write YAML.dump(a)
  f.write YAML.dump(b)

  f.seek(0)
  file_content = f.read
  c, d = *load_objects(file_content)

  puts c
  puts d
end

You can also run regex against the file content to get individual object definitions.

If using one file for serialization is a strict requirement, you could serialize an array of objects to the file like so;

require 'yaml'

class A
  attr_accessor :num

  def initialize(num)
    @num = num
  end
end

a = A.new(1)
b = A.new(2)

File.open('test.yml', 'w+') do |f|
  f.write YAML.dump([a, b])
end

objects = YAML.load_file('test.yml')
Foo Bar Zoo
  • 206
  • 3
  • 10
  • "but your way of serialization is also ok" - No-no-no, it's NOT ok. What _would_ be ok is generating a valid yaml file (like in your second snippet). Then you wouldn't need to supplement `YAML.load` with additional string mangling (which is fragile at best) – Sergio Tulentsev Mar 12 '18 at 17:23
  • 1
    You never know what his requirements are. You can write the output of the `YAML.dump` to a file which is not supposed to be a valid YAML file, at the end it's your own serialization schema. Would you prefer to load every time millions of objects into the memory to be able to serialize an array to generate a valid yaml file? This is why people are saying, ruby is slow and consuming lots of memory. **Of course**, serializing objects into the separate files is more appropriate way but **not always**! To be able to say "No-no-no, it's NOT ok", you have to **understand** the requirements. – Foo Bar Zoo Mar 12 '18 at 19:42
  • I was mistaken, it appears. It _is_ a valid yaml file. You live, you learn ¯\\_(ツ)_/¯ But if it _weren't_, then I stand by my point, writing a broken format is never an answer. Except when you do it on purpose, to interface with an equally broken system. But then it's the system's task to parse this. – Sergio Tulentsev Mar 13 '18 at 07:24
  • "But if it weren't, then I stand by my point, writing a broken format is never an answer. Except when you do it on purpose, to interface with an equally broken system". You already know that there are cases and still saying "never". The only time you can say never is, **never** say never ;) – Foo Bar Zoo Mar 13 '18 at 10:33