[Basics] 5 Ruby Objects

Ruby Objects Basics

Ruby follows the Object Oriented programming paradigm. An object is a construction in programming which contains any amount of attributes, methods, variables, and constants. Unlike procedural or linear paradigms, object orientation is more concerned with how to perform a procedure than what exactly you want to do. For instance all File objects are created with the same characteristics however it is up to you how you use them in your actual code. Lets say that you decide to write to a file object, WHAT you write is of your concern, however how you write it stays static. Hence the File objects methods for writing are called for writing your data, whatever that may be. The same is true for reading from a File object or any other method which can be performed on files. 

EVERYTHING (almost) is an object in Ruby, so even an Object is an Object. To explain this, one must understand how inheritance works. Every Object in Ruby inherits from the Object Class. More specifically the BaseObject Class, Object is a descendant of BaseObject. The Kernel Object is a descendant of Object, IO Objects descend from Kernel Objects. File and Network Objects descend from IO objects and so on. The Object class provides some awesome methods for inspecting an object. You have likely already observed me calling the "methods" function on objects. This function returns an array of all methods of an object.

#Calling the methods function on the Object constant (yes I said constant, we will talk about that later). [1]

>> Object.methods
=> ["private_class_method", "inspect", "name", "tap", "clone", "public_methods", "__send__", "object_id", "method_defined?", "yaml_as", "instance_variable_defined?", "equal?", "freeze", "extend", "send", "const_defined?", "methods", "instance_method", "pretty_print", "ancestors", "module_eval", "hash", "dup", "ri", "autoload?", "instance_variables", "to_enum", "instance_methods", "public_method_defined?", "class_variable_defined?", "pretty_print_cycle", "eql?", "constants", "id", "instance_eval", "singleton_methods", "module_exec", "const_missing", "taint", "pretty_print_inspect", "yaml_tag_read_class", "instance_variable_get", "frozen?", "enum_for", "private_method_defined?", "public_instance_methods", "display", "instance_of?", "superclass", "yaml_tag_class_name", "method", "to_a", "included_modules", "taguri", "const_get", "instance_exec", "type", "po", "<", "protected_methods", "<=>", "taguri=", "class_eval", "==", "class_variables", ">", "===", "to_yaml", "instance_variable_set", "protected_instance_methods", "protected_method_defined?", "respond_to?", "kind_of?", ">=", "public_class_method", "to_yaml_style", "to_s", "<=", "to_yaml_properties", "const_set", "allocate", "class", "new", "poc", "pretty_print_instance_variables", "private_methods", "=~", "tainted?", "__id__", "yaml_tag_subclasses?", "class_exec", "autoload", "untaint", "nil?", "pretty_inspect", "private_instance_methods", "include?", "is_a?"]

#Calling a method named ancestors, this will look up what classes this object inherits from and return them all as an Array object.

>> Object.ancestors
=> [Object, Kernel]
>> Kernel.ancestors
=> [Kernel]
>> File.ancestors
=> [File, IO, File::Constants, Enumerable, Object, Kernel]

#Each object has a unique Object ID in the Ruby run time. This can be seen by calling the object_id method exposed by the Object Class.

>> File.ancestors.object_id
=> 69828105454280


    The Ancestor classes gives any descendant classes down the chain it's attributes such as  methods, constants and variables. The child class may in turn override some of these inherited attributes or add it's own attributes. The Ruby class system can be viewed as a logical tree hierarchy. 

As such, an Object is actually a class in Ruby, all objects inherit from the Object Class. This in it's self exposes many standard methods to all types of Objects by default. Such as the ability for a method to be called on a object to describe it's type. This method is called "class" and we can call it on any object. Below I will create a file object and call the class method from the Ancestor Object class against it.

>> file = File.new("/tmp/test_file_from_irb.txt", "w+")
=> #<File:/tmp/test_file_from_irb.txt>
>> file.class
=> File

    One may say at this point that other programming languages such as Java Script, Java, Perl, and Python are Object Oriented. The answer is yes they are actually Ruby takes ideology from many of the previous mentioned list of languages. So lets look at exactly how object oriented Ruby is.

#Other languages use the call self. Self references where you are in the current scope. Calling from Self from the top most level of a module should output "Module" (Because a Module is a Class, an instance of the Module Class is a Module object)

>> self.class
=> Object

#Going back to our methods call, we will use it on our self, which is actually an Object. So we return the array of methods for the Object class.

>> self.class.methods
=> ["private_class_method", "inspect", "name", "tap", "clone", "public_methods", "__send__", "object_id", "method_defined?", "yaml_as", "instance_variable_defined?", "equal?", "freeze", "extend", "send", "const_defined?", "methods", "instance_method", "pretty_print", "ancestors", "module_eval", "hash", "dup", "ri", "autoload?", "instance_variables", "to_enum", "instance_methods", "public_method_defined?", "class_variable_defined?", "pretty_print_cycle", "eql?", "constants", "id", "instance_eval", "singleton_methods", "module_exec", "const_missing", "taint", "pretty_print_inspect", "yaml_tag_read_class", "instance_variable_get", "frozen?", "enum_for", "private_method_defined?", "public_instance_methods", "display", "instance_of?", "superclass", "yaml_tag_class_name", "method", "to_a", "included_modules", "taguri", "const_get", "instance_exec", "type", "po", "<", "protected_methods", "<=>", "taguri=", "class_eval", "==", "class_variables", ">", "===", "to_yaml", "instance_variable_set", "protected_instance_methods", "protected_method_defined?", "respond_to?", "kind_of?", ">=", "public_class_method", "to_yaml_style", "to_s", "<=", "to_yaml_properties", "const_set", "allocate", "class", "new", "poc", "pretty_print_instance_variables", "private_methods", "=~", "tainted?", "__id__", "yaml_tag_subclasses?", "class_exec", "autoload", "untaint", "nil?", "pretty_inspect", "private_instance_methods", "include?", "is_a?"]

#Notice that whats returned from this call is an Array Object, as such calling the class method like below on the methods call, lets us know we returned an Array.

>> self.class.methods.class
=> Array

#We can then save this array and perform some Array methods on it from the Array class. Here I call join on the array which kind of converts the array to a string with a separator of choice delimiting each Array Element. I am using a new line character.

>> array = self.class.methods 
>> puts array.join("\n")
private_class_method
inspect
name
tap
clone
public_methods
__send__
object_id
method_defined?
yaml_as
instance_variable_defined?
equal?
freeze
extend
send
const_defined?
methods
instance_method
pretty_print
ancestors
module_eval
hash
dup
ri
autoload?
instance_variables
to_enum
instance_methods
public_method_defined?
class_variable_defined?
pretty_print_cycle
eql?
constants
id
instance_eval
singleton_methods
module_exec
const_missing
taint
pretty_print_inspect
yaml_tag_read_class
instance_variable_get
frozen?
enum_for
private_method_defined?
public_instance_methods
display
instance_of?
superclass
yaml_tag_class_name
method
to_a
included_modules
taguri
const_get
instance_exec
type
po
<
protected_methods
<=>
taguri=
class_eval
==
class_variables
>
===
to_yaml
instance_variable_set
protected_instance_methods
protected_method_defined?
respond_to?
kind_of?
>=
public_class_method
to_yaml_style
to_s
<=
to_yaml_properties
const_set
allocate
class
new
poc
pretty_print_instance_variables
private_methods
=~
tainted?
__id__
yaml_tag_subclasses?
class_exec
autoload
untaint
nil?
pretty_inspect
private_instance_methods
include?
is_a?
=> nil


    Below, I have given a few simple examples of how all things are objects in Ruby. Using IRB (Yellow with Red lettering denotes command I input to IRB and those on background of Green are output results. I will load some data and call the class method on that data to determine what type of Object we are dealing with... 


#A string in ruby can be declared by enclosing the data in quotes. Below is an example of a String Literal. 

>> "string".class
=> String

#A Number in Ruby can be one of many types depending on what type of number or how large the number is. For instance, in computing math, a Fixed Number is a number with no decimal place, and a Floating Point number is one which contains a decimal place (and a certain amount of precision). In Ruby as in many other languages smaller numbers are separated from larger numbers by class.

1 is a Fixed Number Class
>> 1.class
=> Fixnum

1.1 is a Floating Point Class
>> 1.1.class
=> Float

The below function produces a huge number which I will not even have in my blog for appearance sake. However the point is that the number is so large that it is in a separate class than a Fixnum. There is also HugeNum.

>> 100.downto(1).inject(:*).class
=> Bignum

# Classes like the File Class allow you to easily open a file in Ruby and perform read/write operations. A file is of class File (appropriately). 

>> File.open("/tmp/expect_ruby.rb").class
=> File

#Below is an example we will get more in depth into further down the line in this intro. However it is good to know that even an Object is an Object in Ruby. =)

>> obj = Object.new
=> #<Object:0x7f2ad73dd930>
>> obj.class
=> Object

At this point one would likely question, 

"What is all this class talk, I thought were talking Object Orientation?".

    Good question, the answer would be that an object is an instance of a class. So lets define a class. Very simply put a class is a way of organizing Variables, Constants and Methods pertaining to a specific logical grouping. For instance as previously mentioned, the File class deals with Files. Technically it deals with File Objects. 

    Using the File Class you will find methods for opening file objects, closing file objects, writing to file objects, reading from file objects, and so on. In order to utilize these methods, you must create an instance of a File Object. Below using IRB, I will create a file object, save it to a variable named "file" and call some methods on this file object. Here you should also get a good idea about the direct mapping of a file object to an actual file.

#Creating a File in Ruby is as simple as this:
>> file = File.new("/tmp/test_file_from_irb.txt", "w+")
=> #<File:/tmp/test_file_from_irb.txt>

#Now that we have our file object saved in a variable we can easily call methods on it.

>> file.ctime
=> Sat Sep 17 17:47:34 -0400 2011

#

>> file.class            
=> File


    Other than the File class, there are hundreds of useful classes in the standard library of Ruby. Another class which is very useful is the Time class. The Time class allows you to manipulate Time objects in comparison to the File class manipulation of File objects. 

So let's create a quick Time object to give a viewing of this in action.

#Creating a Time Object and saving it to a variable named time.
>> time = Time.new
=> Sat Sep 17 04:18:53 -0400 2011

#Accessing a method in the Time class via the Time Object stored in time variable. The month method returns the month index number. September is the 9th month.
>> time.month
=> 9

Comments