Yet Another Ruby Language Post :)

This time, I am back with a post that deals with few interesting aspects of ruby. To begin with, I am going to discuss about YAML (Guess you now know the reason why I gave this title to this post :D ). YAML is an acronym for Yet Another Markup Language. YAML is a way by which data could be serialized in a human readable format. In ruby’s context, YAML could be used to save the state of ruby objects. Ruby makes it really easy to store and retrieve YAML objects. This enables you to accomplish things with a very few lines of code. Conside the following for example:

require 'yaml'
a =['a', 'b']
y(a)

In order to use YAML in ruby, you need to import the YAML library. This is done using the require statement. Then I declare a simple ruby array called ‘a’. Now y is a method from the YAML library that prints the array ‘a’ in the YAML format. The output is given below. The first line --- indicates that this is a YAML serialized data. Then the following lines represent every entry in the array.

---
- a
- b

This technique could also be utilized for saving the state of an instance or a list of instances. Consider the following class and an instance of it.

class Appdata
	attr_accessor :id, :title, :description

	def initialize(p_id, p_title, p_description)
		@id = p_id
		@title = p_title
		@description = p_description
	end
end

i = Appdata.new(1, "Title 1", "Description 1")
y(i)

Executing this snippet would give the following output. The first line as before indicates that this is a YAML serialized data. After —, !ruby/object:Appdata indicates that what follows is an instance of the Appdata object. Following this line, every property of this instance is listed.

>ruby variables.rb

--- !ruby/object:Appdata
description: Description 1
id: 1
title: Title 1
>Exit code: 0

This could very well be put in to a number of useful implementations. For example, an application’s configuration/state could be stored/retrieved using this. Consider the class given below:

require 'yaml'

class Dataclass
	attr_writer :data_id, :data_name

	def initialize(id, name)
		@data_id = id
		@data_name = name
	end

	def getdataid
		@data_id
	end

end

a = Dataclass.new(3,"three")

if (!File.exists?("app_state.config"))
	puts "Dumping app state"
	f = File.new("app_state.config", 'w')
	YAML.dump(a, f)
	f.close
end

$config

if (File.exists?("app_state.config"))
	puts "Reading app state"
	File.open("app_state.config") { |data|
		$config = YAML.load(data)
	}
end

puts $config.getdataid

In the above listing, lines 3 – 15 represent the config class I wish to save. Line 17 creates an instance of Dataclass. Lines 19-24 checks if there is a file named “app_state.config” and if not it creates a new file with the same name and then uses the YAML.dump method to dump the instance a in to the file created using the handle f. Then to demonstrate the fact that this serialized data can be loaded back, I am using the YAML.load method. This is demonstrated using lines 28 – 33. Before this, I have defined a variable $config to store the configuration object stored. In order to do this, the file is opened using the File.open method. The data read from the file is made available to the block that will executed after the read operation using the |data| variable. Then I call YAML.load method to load the Dataclass instance in to the $config variable.

From this point onwards, $config can be used in the application as shown in line 35. I have put YAML in to use in my to-do list application. I use YAML to save / load tasks added by the user. Check out this file to see what I mean. A sample file generated by this application is here.

This greatly simplifies the amount of code required to do this. This is evident when you compare the amount of code involved in text manager which save’s / load’s the tasks in to a text file. Code for this is here. A sample file generated by this application is here.

The next thing I would like to discuss is about class & instance variables and class methods. When I was getting myself acquainted with ruby, I was stumped once even though I knew the difference between a class and instance variable, as it didn’t register well enough in my mind. After identifying the mistake it’s going to be etched forever in my memory! To begin with, in ruby, an instance variable is prefixed with ‘@’ and a class variable is prefixed with ‘@@’. A class method is similar to a c# static method and so an instance is not required to call this method. So, a class variable is similar to a static field.

I am sure you are aware about classes and objects. A class is a blueprint of an object, it’s a collection of properties (representing state) and methods (representing behavior). And, an object is an instance of a class. Every instance variable is specific to an instance as the name suggests and a class variable is common across all the instances and so is specific to the class. Let me make it clear with an example.

class Sampleclass
	@@no_instances = 0

	attr_accessor :initialMessage 

	def initialize(initMessage)
		@@no_instances = @@no_instances + 1
		@initialMessage = initMessage
	end

	def print
		puts "Hello from Sampleclass #{self.inspect}"
	end

	def Sampleclass.printInstanceCount
		puts @@no_instances
	end
end

In the above snippet, line 2 represents a class variable and line 4 represents an instance variable. And line 15 represents a class method, which is similar to a C# static method. A ruby class method, just like other instance methods, starts with the def keyword. Then the method is named in the format ClassName.MethodName as shown in the snippet above. In this case, @@no_instances is used to maintain a count of the number of instances of Sampleclass created so far. The class method in this case is used to print the number of instances created for this object. Line 2 initializes the class variable to 0. Whenever an instance of Sampleclass is created, this counter is incremented. Notice that it is not reset for every instantiation of this class. The class method provides a way by which the user can get to know the number of instances created so far. The snippet below demonstrates this.

a = Sampleclass.new("Hello")
a.print

b = Sampleclass.new("Hello")
b.print

Sampleclass.printInstanceCount

c = Sampleclass.new("Hello")
c.print

Sampleclass.printInstanceCount

When the above snippet is executed, the following is the output.

>ruby variables.rb
Hello from Sampleclass #<Sampleclass:0x5d8a78 @initialMessage="Hello">
Hello from Sampleclass #<Sampleclass:0x5d8988 @initialMessage="Hello">
2
Hello from Sampleclass #<Sampleclass:0x5d8898 @initialMessage="Hello">
3
>Exit code: 0

Notice lines 3 and 5, these are due to the calls to the class method and it displays the number of instances created. Hope this post was informative / refreshing!

Do post your comments!

Share