Loading variables from a file [Noob Question]

Discussion in 'Ruby' started by Richard Mccormack, Nov 28, 2010.

  1. Hey everyone,
    I've been working on some sort of a test-based game to learn ruby (and
    programming in general :) and I got stuck with my saving/loading system.
    To show you what I mean, this is what I used to save the game. (I want
    the code to be as modular as I can, I have some sort of an addon system
    planned...)

    def savegame(name, varstosave)
    savegame = File.new(name + ".tsl", "w")
    savegame.puts varstosave.to_s
    while varstosave.length != 0
    savegame.puts varstosave[0]
    savegame.puts eval(varstosave[0]).to_s
    varstosave.delete_at(0)
    end
    savegame.close
    end

    So, now I am trying to to load the variables from the file. I came up
    with the start of a function:

    def loadgame(name, varstoload)
    puts "Loading..."
    loadgame = File.open(name + ".tsl", "r")
    while varstoload.length != 0
    # ?
    end
    loadgame.close
    end

    Where varstoload/varstosave is an array. Problem with the loading is
    that I assumed there was a way to take the first variable name from the
    array and actually use it as a variable. So, if the array is
    ["$intellect", "$strength"], I thought I would be able somehow to turn
    a[0] into a variable object. It seems that there isn't a way to do this,
    so I was wondering if there was a better way to manage the
    saving/loading.
    - Thanks in advance! :)

    --
    Posted via http://www.ruby-forum.com/.
     
    Richard Mccormack, Nov 28, 2010
    #1
    1. Advertising

  2. On Sun, Nov 28, 2010 at 6:44 PM, Richard Mccormack
    <> wrote:
    > Hey everyone,
    > It seems that there isn't a way to do this,
    > so I was wondering if there was a better way to manage the
    > saving/loading.


    Ruby 1.8.x ships with YAML, while Ruby 1.9.x includes JSON. Both
    formats allow you to save variables to file, and reload them.

    require "yaml"
    require "json"

    [1,2,3,4,].to_yaml
    [1,2,3,4,].to_json

    If you need something more complex, Marshall#dump and #load can be useful.

    All of this should be covered by the Ruby docs, too (at least YAML and
    Marshall are, JSON at 1.9.x, as I've mentioned).

    Mind, you still have to do the assignment and such yourself, but you
    get the data back in a Ruby-friendly format. ;)

    --
    Phillip Gawlowski

    Though the folk I have met,
    (Ah, how soon!) they forget
    When I've moved on to some other place,
    There may be one or two,
    When I've played and passed through,
    Who'll remember my song or my face.
     
    Phillip Gawlowski, Nov 28, 2010
    #2
    1. Advertising

  3. Re: Loading variables from a file

    Phillip Gawlowski wrote in post #964503:
    > On Sun, Nov 28, 2010 at 6:44 PM, Richard Mccormack
    > <> wrote:
    >> Hey everyone,
    >> It seems that there isn't a way to do this,
    >> so I was wondering if there was a better way to manage the
    >> saving/loading.

    >
    > Ruby 1.8.x ships with YAML, while Ruby 1.9.x includes JSON. Both
    > formats allow you to save variables to file, and reload them.
    >

    Ah, exactly what I was looking for! Thanks a ton, I can't believe I
    didn't know about that ^^
    Thanks again! :D
    -Richard

    --
    Posted via http://www.ruby-forum.com/.
     
    Richard Mccormack, Nov 28, 2010
    #3
  4. On Nov 28, 5:44 pm, Richard Mccormack <>
    wrote:
    > Hey everyone,
    > I've been working on some sort of a test-based game to learn ruby (and
    > programming in general :) and I got stuck with my saving/loading system.
    > To show you what I mean, this is what I used to save the game. (I want
    > the code to be as modular as I can, I have some sort of an addon system
    > planned...)
    >
    > def savegame(name, varstosave)
    >   savegame = File.new(name + ".tsl", "w")
    >      savegame.puts varstosave.to_s
    >      while varstosave.length != 0
    >         savegame.puts varstosave[0]
    >         savegame.puts eval(varstosave[0]).to_s
    >         varstosave.delete_at(0)
    >      end
    >   savegame.close
    > end
    >
    > So, now I am trying to to load the variables from the file. I came up
    > with the start of a function:
    >
    > def loadgame(name, varstoload)
    >   puts "Loading..."
    >   loadgame = File.open(name + ".tsl", "r")
    >     while varstoload.length != 0
    >         # ?
    >     end
    >   loadgame.close
    > end
    >
    > Where varstoload/varstosave is an array. Problem with the loading is
    > that I assumed there  was a way to take the first variable name from the
    > array and actually use it as a variable. So, if the array is
    > ["$intellect", "$strength"], I thought I would be able somehow to turn
    > a[0] into a variable object. It seems that there isn't a way to do this,
    > so I was wondering if there was a better way to manage the
    > saving/loading.
    >  - Thanks in advance! :)
    >
    > --
    > Posted viahttp://www.ruby-forum.com/.


    Not sure if it helps, but here are a few tips.

    First, if you simply want to dump all the data in a file and get it
    back have a look at things like the YAML library: you can take your
    objects, and just with one line of code dump it into a file. (you can
    alternatively use Marshal but then the file will be written in binary
    format: great if you need to save space but not if you want to be able
    to open the file with a text editor to have a look).

    Second, and possibly more relevant. :)
    A common way to do what you are trying to do would be to read a line
    at a time from the file, analyse it and store the result. Here a
    couple of useful functions may be:

    File::read (it reads the whole file and returns a String object)
    File::readlines (it reads the whole file and returns an Array of
    String with one line of the file per element of the Array)

    Note that in both cases these are class methods, similar to the
    File.open you used.

    A maybe more elegant method, and more similar to what you were trying
    to do would be to use File#gets, which returns the "next" line. Then
    you could modify your code so:

    loadgame = File.open(name + ".tsl", "r")
    while !loadgame.eof? # i.e. until it reaches the end of file
    line = loadgame.gets
    # more code
    end
    loadgame.close

    Now, assuming you manage to get a line, you need to parse it to get
    the data you want. The most generic way would be to use a regexp, but
    for simple cases you can simply split the line into smaller Strings
    via the function String#split. This would make it easier to pick the
    name and the value.

    So far I've assumed that you want to load all the variables in the
    file. If you only want to load some, i.e. only those in the Array
    varstoload you can use Array#include, for example:


    loadgame = File.open(name + ".tsl", "r")
    while !loadgame.eof? # i.e. until it reaches the end of file
    line = loadgame.gets
    elements = line.split
    if varstoload.include? elements[0]
    # add elements[0] and elements[1] to some variable/object
    end
    end
    loadgame.close

    Hope that help.

    Feel free if you have other questions.
    Diego
     
    Diego Virasoro, Nov 28, 2010
    #4
  5. Richard Mccormack

    w_a_x_man Guest

    On Nov 28, 11:44 am, Richard Mccormack <>
    wrote:
    > Hey everyone,
    > I've been working on some sort of a test-based game to learn ruby (and
    > programming in general :) and I got stuck with my saving/loading system.
    > To show you what I mean, this is what I used to save the game. (I want
    > the code to be as modular as I can, I have some sort of an addon system
    > planned...)
    >
    > def savegame(name, varstosave)
    >   savegame = File.new(name + ".tsl", "w")
    >      savegame.puts varstosave.to_s
    >      while varstosave.length != 0
    >         savegame.puts varstosave[0]
    >         savegame.puts eval(varstosave[0]).to_s
    >         varstosave.delete_at(0)
    >      end
    >   savegame.close
    > end
    >
    > So, now I am trying to to load the variables from the file. I came up
    > with the start of a function:
    >
    > def loadgame(name, varstoload)
    >   puts "Loading..."
    >   loadgame = File.open(name + ".tsl", "r")
    >     while varstoload.length != 0
    >         # ?
    >     end
    >   loadgame.close
    > end
    >
    > Where varstoload/varstosave is an array. Problem with the loading is
    > that I assumed there  was a way to take the first variable name from the
    > array and actually use it as a variable. So, if the array is
    > ["$intellect", "$strength"], I thought I would be able somehow to turn
    > a[0] into a variable object. It seems that there isn't a way to do this,
    > so I was wondering if there was a better way to manage the
    > saving/loading.


    Use a hash (associative array).


    def save_game( name, hash )
    open( name + ".tsl", "w" ){|f|
    f.puts hash.to_a.join( "\n" )
    }
    end

    def load_game( name )
    hash = {}
    open( name + ".tsl", "r" ){|f|
    while key = f.gets
    hash[ key.strip ] = f.gets.to_i
    end
    }
    hash
    end

    status = {}
    status[ 'intellect' ] = 140
    status[ 'strength' ] = 120

    save_game( 'foo', status )
    p load_game( 'foo' )
     
    w_a_x_man, Nov 29, 2010
    #5
  6. Richard Mccormack

    Josh Cheek Guest

    [Note: parts of this message were removed to make it a legal post.]

    On Sun, Nov 28, 2010 at 11:44 AM, Richard Mccormack <
    > wrote:

    > def savegame(name, varstosave)
    > savegame = File.new(name + ".tsl", "w")
    > ...
    > savegame.close
    > end
    >
    >

    The preferred way to open a file is with the block syntax because it ensures
    the file gets closed after the block is evaluated, even if an error gets
    raised.

    File.open( name + '.tsl' , 'w' ) do |savegame|
    ...
    end


    > savegame.puts eval(varstosave[0]).to_s
    >
    >

    For simple things like numbers and strings, this may work (you will probably
    have to do some conversions). But for more complex data, like objects, you
    will have difficulty because you aren't using any well understood
    representation of objects as Strings (others suggested yaml, json,
    marshalling).

    Use of eval is generally frowned upon because it is rarely necessary and can
    introduce security risks. In this case, it is enabling the bad practice of
    global variables (I'll explain that a bit further down). Rather than evaling
    your global variable strings to get their value, try passing them in to the
    function. If you need to keep track of both the name of the variable, and
    its value, then try using a hash table.

    def savegame(vars)
    vars.each do |name,value|
    puts "savegame has access to #{name} which has a value of #{value}"
    end
    end

    intellect = 3
    strength = 4

    savegame 'intellect' => intellect , 'strength' => strength

    # output
    # >> savegame has access to intellect which has a value of 3
    # >> savegame has access to strength which has a value of 4


    >
    > Where varstoload/varstosave is an array. Problem with the loading is
    > that I assumed there was a way to take the first variable name from the
    > array and actually use it as a variable. So, if the array is
    > ["$intellect", "$strength"], I thought I would be able somehow to turn
    > a[0] into a variable object. It seems that there isn't a way to do this,
    > so I was wondering if there was a better way to manage the
    > saving/loading.
    >


    Having a hard time understanding what you are looking for here (it sounds
    like you want it to return $intellect, the variable, rather than the object
    that the variable is pointing to -- if that is the case, there is no way to
    do that)

    I will just point out that variables that begin with dollar signs are global
    variables in Ruby. Here are the different kinds of variables you can use:

    # The colon at the front of the results means that they are Symbols.
    # Symbols are basically immutable Strings. In earlier versions of Ruby,
    # this would have returned the results as Strings instead of Symbols.

    search_pattern = /strength|intelligence/i

    $strength = 3
    $intelligence = 4
    global_variables.grep(search_pattern) # => [:$strength, :$intelligence]

    strength = 3
    intelligence = 4
    local_variables # => [:search_pattern, :strength, :intelligence]

    @strength = 3
    @intelligence = 4
    instance_variables # => [:mad:strength, :mad:intelligence]

    # this one is a little weird since we are in the main object
    @@strenght = 3
    @@intelligence = 4
    self.class.class_variables # => [:mad:@strenght, :mad:@intelligence]

    STRENGTH = 3
    INTELLIGENCE = 4
    self.class.constants.grep(search_pattern) # => [:STRENGTH, :INTELLIGENCE]
     
    Josh Cheek, Nov 29, 2010
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. avidfan
    Replies:
    1
    Views:
    292
  2. Replies:
    14
    Views:
    514
    Marcus Kwok
    Oct 20, 2006
  3. John Maclean

    Files and variables (noob alert)

    John Maclean, Jan 27, 2006, in forum: Ruby
    Replies:
    3
    Views:
    96
    John Maclean
    Jan 27, 2006
  4. bingo bob
    Replies:
    7
    Views:
    93
    Gregory Brown
    Aug 13, 2009
  5. Angel Marques
    Replies:
    1
    Views:
    101
    Philliam Auriemma
    Dec 19, 2009
Loading...

Share This Page