Marshal is a library that converts all data from an object/objects into a byte stream, permitting the scripter to save this object into a file (outside the Ruby Interpreter´s memory) and recover it later on. Some objects cannot be dumped: if the objects to be dumped include bindings, procedure objects, instances of class
IO, or singleton objects, a
TypeError will be raised, so take care with what you dump. I have tried once to save an entire Bitmap for example, and the game crashed xD
Usage is fairly simple. This library has only two methods and they´re simple and very straightforward.
- Marshal.dump(object, [anIO, [limit]])
This method converts all the objects´ data into a byte stream. object is te object to be serialized.
anIO is not necessary, but if passed it must be an instance of the IO class (this is an special object that can be saved as an ordinary file, for you to know). In this case, Marshal.dump will dump the object´s stream into this IO object. Otherwise, it will return a string with the serialized object.
In Marshal.dump, more than one object can be dumped into an IO object, and in this case the user can make the process check to see the number of dumps made in this IO object. limit[/b] represents the maximum number of objects that can be inside the IO object. -1 is the default value, and if it is that value, no ckeck will be made. As anIO, this argument is not necessary.
- Marshal.load(object, [proc])
Marshal.load is the part responsible for recovering the dumped object´s data. object must be an instance of IO class, a String or any class that responds to the to_str method.
This method returns the recovered object. If an IO object is passed and if it has more than one object dumped, it will load the objects in the same order they were dumped (the first dumped object will be the first to be loaded), and will return only ONE object each time you ask for it to load objects from that IO class. This operation must be done in order, so take care.
proc is a Proc object that can be passed to be executed each time you load an object. Don´t really care with it since it´s a bit complicated for most scripters ^^ (if you want i can explain about Procs later).
So... The two methods are explained, so let´s take some examples for you to understand about them:
Suppose we have those two classes:
# Class that will hold some text...
class Text
attr_accessor :data
def initialize
@data = "Hi"
end
end
# Class that will be the real object we´ll use
class Handler
def initialize
@text = Text.new
end
def say_something
return @text.data
end
def record_this_text(txt)
@text.data = txt
end
end
So, we need new instances of them to start explaining anything.
myObject = Handler.new
print myObject.say_something => "Hi"
# Changing some data
myObject.record_this_text("Hello World!")
As you can see we changed the object´s data and wants to store it. Suppose we can´t do it with IO objects, the only way to do is with Strings:
# Serializing the object and getting the result
string = Marshal.dump(myObject)
Now our object is serialized inside string. To recover it we call Marshal.load:
recoveredObject = Marshal.load(string)
print recoveredObject.say_something => "Hello World!"
As you can see it´s very easy. Now let´s get more in depth... We will save it into a file. First, create a new IO object for that:
filename = "Handler.rxdata"
mode = "wb" # in this case the file will be in the write mode only
file = File.open(filename, mode)
* NOTE: File.open opens the file specified in filename and returns a IO object that contains the bytes of it. If the file doesn´t exists it creates a new file with the name passed. Note that filename must contain the complete path and filename, but in our case we just used the default Game folder (supposing we´re writing it in RMXP). So, the new file will appear in the same place where Game.exe is.
Pass it to Marshal.dump...
# In this case Marshal.dump returns nothing.
Marshal.dump(myObject, file)
# It´s REALLY important to close the IO object, otherwise
# the object won´t be saved correctly. Make this after dumping
# all the needed objects.
file.close
Now, to recover our object, first open the file:
filename = "Handler.rxdata"
mode = "rb" # in this case the file will be in the read mode only
file = File.open(filename, mode)
Next, call Marshal.load:
recoveredObject = Marshal.load(file)
recoveredObject.say_something => "Hello World!"
The magic is done ^^
Now your saved and recovered myObject is in recoveredObject. And sure, you can dump more than one object into a file. Take RMXP for example:
SAVING:
file = File.open(filename, "wb")
Marshal.dump($game_system, file)
Marshal.dump($game_switches, file)
Marshal.dump($game_variables, file)
Marshal.dump($game_self_switches, file)
Marshal.dump($game_screen, file)
Marshal.dump($game_actors, file)
Marshal.dump($game_party, file)
Marshal.dump($game_troop, file)
Marshal.dump($game_map, file)
Marshal.dump($game_player, file)
file.close
LOADING:
file = File.open(filename, "rb")
$game_system = Marshal.load(file)
$game_switches = Marshal.load(file)
$game_variables = Marshal.load(file)
$game_self_switches = Marshal.load(file)
$game_screen = Marshal.load(file)
$game_actors = Marshal.load(file)
$game_party = Marshal.load(file)
$game_troop = Marshal.load(file)
$game_map = Marshal.load(file)
$game_player = Marshal.load(file)
file.close
Note that it´s just the condensated and simplified Scene_Save and Scene_Load most important code. I gave focus only to the Marshal methods. Note that the files are saved and loaded at the same order, that´s very important.
Now, if your object can´t be saved by Marshal library bu default, you can create a serialization method for the specific object. For that, and for more informations about Marshal, check here. (Sorry i´m so tired, i will explain the serialization method in another time ^^)
And magic, our object is saved inside Handler.rxdata ^^
I REALLY hope you understand what i´m trying to explain, and i´m sorry if i was too obvious and pointless in any part.