Reputation: 774
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
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
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