Saving hashes to file on Ruby

2019-01-28 07:59发布

问题:

I'm just giving my first steps in programming. I have just finished another class in Code Academy. This time I was asked to create a small movie catalog. Here is my question: How could I save/load the hashes with the movies titles and ratings in a file instead of the own code?

Here is how the code looks like right now (a few sentences in Portuguese, but you may just ignore it:

    movies = {
    Memento: 3,
    Primer: 4,
    Ishtar: 1
    }

    puts "O que você gostaria de fazer?"
    puts "-- Digite 'add' para adicionar um filme."
    puts "-- Digite 'update' para atualizar um filme."
    puts "-- Digite 'display' para mostrar todos os filmes."
    puts "-- Digite 'delete' para deletar um filme."

    choice = gets.chomp.downcase
    case choice
    when 'add'
      puts "Que filme você gostaria de adicionar?"
      title = gets.chomp
      if movies[title.to_sym].nil?
        puts "Qual a nota? (Digite um número de 0 a 4.)"
        rating = gets.chomp
        movies[title.to_sym] = rating.to_i
        puts "#{title} foi adicionado com uma nota de #{rating}."
      else
        puts "Esse filme já existe na lista! Sua nota é #                        {movies[title.to_sym]}."
      end
    when 'update'
      puts "Que filme você gostaria de atualizar?"
      title = gets.chomp
      if movies[title.to_sym].nil?
        puts "Filme não encontrado!"
      else
        puts "Qual é a nova nota? (Digite um número de 0 a 4.)"
        rating = gets.chomp
        movies[title.to_sym] = rating.to_i
        puts "#{title} foi atualizado, sua nova nota é #{rating}."
      end
    when 'display'
      movies.each do |movie, rating|
        puts "#{movie}: #{rating}"
      end
    when 'delete'
      puts "Que filme voce gostaria de deletar?"
      title = gets.chomp
      if movies[title.to_sym].nil?
        puts "Filme não encontrado!"
      else
        movies.delete(title.to_sym)
        puts "#{title} foi deletado."
      end
    else
      puts "Desculpa, não entendo o que você quer."
    end

As you can see, the catalog is included in the hash at the beggining of the code however it does not save the information. How could I make it store everything?

Thank you guys!

回答1:

If they're simple hashes, a YAML file may be an easy way to do it.

require 'yaml'

# write hash out as a YAML file
movies = { Memento: 1, Primer: 4, Ishtar: 1 }
File.write('movies.yml', movies.to_yaml)

# read back in from file
from_file = YAML.load_file('movies.yml')

# use it
from_file[:Memento]
# => 1 
from_file[:Primer]
# => 4 


回答2:

You can simply use JSON, like this

require 'json'

FILE_PATH = "catalogue.json"

def load
  data = nil
  File.open(FILE_PATH) do |f|
    data = JSON.parse(f.read)
  end
  data
end

def save(data)
  File.open(FILE_PATH, "w+") do |f|
    f << data.to_json
  end
end

def process
  catalogue = load

  p catalogue

  catalogue["Memento"] = 4
  save(catalogue)
end

process
# => {"Memento"=>3, "Primer"=>4, "Ishtar"=>1}
catalogue = load

p catalogue
# {"Memento"=>4, "Primer"=>4, "Ishtar"=>1}


回答3:

The best way according to me is using Marshal method as explained here Marshaling The Marshal module dumps an object in a string, which can be written to a file. Reading the file and Marshal.Loading the string gives the original object. Writing to a file can be achieved using Marshal.dump

For example in your code this can be achieved using

movies = {
Memento: 3,
Primer: 4,
Ishtar: 1
}
# dumping:
File.open("test.marshal", "w"){|to_file| Marshal.dump(movies, to_file)}
# retrieving:
p File.open("test.marshal", "r"){|from_file| Marshal.load(from_file)}
#gives you movies = {Memento: 3,Primer: 4,Ishtar: 1}

Another method is explained by @Nick Veys using Yaml it is also used by people a lot.

Similar explanations can be obtained here as well.Closest match I found