Ruby Objects BasicsRuby 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. =) => #<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 |
