Proto
Proto

Reputation: 774

Understanding Parsing YAML

I'm trying to understand how YAML works and I'm working from examples in a book to learn it. Here's the code I'm using:

require "yaml"

def savelist(songs, playlist)
    File.open playlist, 'w' do |f|
        f.write(songs.to_yaml)
    end
end

def openlist(playlist)
    loadlist = File.read playlist
    YAML::load loadlist
end

podcasts = Dir['C:/Users/7/Music/Amazon MP3/*.mp3']

puts "Welcome to the Playlist Maker!"

list = 'playlist.txt'

savelist(podcasts, list)

openlist(list)

I thought the second method, openlist, would actually call the file to the screen and print out its contents. I read it as "create a loadlist object then load the object to the screen with YAML". I expected it to print the file contents (YAML::load).

The program works, but I don't really understand how it works. I'm also not really sure what the second method is there for if it doesn't actually open the file.

Thanks for your insight. I sorta get what YAML does, but I don't really know how or why this works.

Upvotes: 1

Views: 469

Answers (2)

the Tin Man
the Tin Man

Reputation: 160551

Consider this:

require "yaml"

def savelist(songs, playlist)
  File.write(playlist, songs.to_yaml)
end

def openlist(playlist)
  YAML::load_file(playlist)
end

Learning how YAML works is easier if you look at what it's emitting, and play with it in IRB:

>> require 'yaml'
false
>> songs = ['foo', 'bar']
[
    [0] "foo",
    [1] "bar"
]
>> puts songs.to_yaml
---
- foo
- bar
nil
>>
>> yaml = songs.to_yaml
"---\n- foo\n- bar\n"
>> YAML::load(yaml)
[
    [0] "foo",
    [1] "bar"
]

YAML is just text, so writing a YAML file is simple if you use write, as I did above. YAML has a convenient method load_file to read a file, then parse it back into the equivalent Ruby object. If you've already read the file into a variable, then use load to parse it and return the Ruby object.

Playing with YAML this way, by converting an array or hash to YAML, then using load to mess with it, is a great way to learn it. The YAML spec is useful once you start to get an idea how it works, but doing the "round-trip" thing is how to boot-strap yourself. (This is also useful when learning about JSON.)

We actually use a variation of this when initially defining complex YAML files. I'll write a bit of Ruby code with the object defined inside it, then save that to a file. From that point on we can tweak the YAML, or, as I prefer, we tweak the Ruby and re-create the YAML. Using the Ruby code to recreate the file means we've got a fall-back if someone hoses the configuration. At least we can rebuild our default setup.

Upvotes: 2

Jonah
Jonah

Reputation: 17958

Let's step through this and see how we might learn what a block of code does.

def openlist(playlist)
    loadlist = File.read playlist
    YAML::load loadlist
end

For starters we're passing some playlist object to File.read. We can look up the File class but we won't find a read method on it. We will however see that File is a subclass of IO and if we look at IO we will find IO.read

read(name, [length [, offset]] ) → string

So read takes a file name and an optional length and offset and returns a string. loadlist is then just a string containing the contents of this file. Useful but not easy for us to work with yet.

If we look up the YAML module we learn that it is a wrapper around Psych where we can finally find load

load(yaml, filename = nil)
Load yaml in to a Ruby data structure...

So load takes some string and returns a Ruby data structure created by parsing the YAML syntax it contains.

Now we see why this example is using two different methods, one to load the contents of a file and one to parse those into a Ruby data structure. While we're looking at Psych we might also notice the load_file method which gives us another way to do the same thing as @the-tin-man suggested.

Upvotes: 1

Related Questions