Showing posts with label OOP. Show all posts
Showing posts with label OOP. Show all posts

Thursday, October 13, 2011

Creating Classes

Ruby has numerous built-in classes, and additional classes may be defined in a Ruby program. To define a new class, the following construct is used:
class ClassName
# ...
end

The name of the class is itself a global constant and thus must begin with an uppercase letter. The class definition can contain class constants, class variables, class methods, instance variables, and instance methods. Class data are available to all objects of the class, whereas instance data are available only to the one object.
By the way: Classes in Ruby do not strictly speaking have names. The "name" of a class is only a constant that is a reference to an object of type Class (since in Ruby, Class is a class). There can certainly be more than one constant referring to a class, and these can be assigned to variables just as we can with any other object (since in Ruby, Class is an object). If all this confuses you, don't worry about it. For the sake of convenience, the novice can think of a Ruby class name as being like a C++ class name.

We have already learned how to define functions in ruby. Now lets make a complete greeter class to handle greetings:
class Greeter
#initialize
def initialize(name = "world")
@name=name
end

def sayHi
puts "Hello #{@name}"
end

def sayBye
puts "Bye #{@name}"
end
end
The new keyword here is class. This defines a new class called Greeter and a bunch of methods for that class. Also notice @name. This is an instance variable, and is available to all the methods of the class. As you can see it’s used by say_hi and say_bye.

Creating the object:
g=Greeter.new("k2")
g.sayHi
g.sayBye

Instance variables in Class
Instance variables are hidden away inside the object. They’re not terribly hidden, you see them whenever you inspect the object, and there are other ways of accessing them, but Ruby uses the good object-oriented approach of keeping data sort-of hidden away.

puts Greeter.instance_methods

Output:
"method", "send", "object_id", "singleton_methods",
"__send__", "equal?", "taint", "frozen?",
"instance_variable_get", "kind_of?", "to_a",
"instance_eval", "type", "protected_methods", "extend",
"eql?", "display", "instance_variable_set", "hash",
"is_a?", "to_s", "class", "tainted?", "private_methods",
"untaint", "say_hi", "id", "inspect", "==", "===",
"clone", "public_methods", "respond_to?", "freeze",
"say_bye", "__id__", "=~", "methods", "nil?", "dup",
"instance_variables", "instance_of?"

Whoa. That’s a lot of methods. We only defined two methods. What’s going on here? Well this is all of the methods for Greeter objects, a complete list, including ones defined by ancestor classes. If we want to just list methods defined for Greeter we can tell it to not include ancestors by passing it the parameter false, meaning we don’t want methods defined by ancestors.

Greeter.instance_methods(false)

Output this time is:
"say_bye", "say_hi"

Class level variables in ruby
Getters and setters in ruby
Self in ruby


self: Referencing to the current receiver

 Within the instance methods of a class, the pseudovariable self can be used as needed. This is only a reference to the current receiver, the object on which the instance method is invoked.

eg.
class Book
def self.title
true
end

def title
true
end
end

self refers to the object depends on its context. self.title in the above example will be invoked by the (current) object, Book. While title will be invoked by the object, Book.new. Therefore, to determine the value of self, you need to think around where the self resides.

There are only 2 things that change what self points to: There are only 2 things that change what self points to:
  1. Explicit receiver of method call
    puts self #self is "main", the top-level object instance
    Object.new #self is temporarily changed to the class Object,
    but then back to main

  2. class/module definition
    puts self #Again, self is "main"
    class Foo
    puts self #self is now Foo
    end
    #self is back to being main
Source:Paul Berry

So to define a method as a class method, prefix the method name with the self keyword. The scope of self varies depending on the context. Inside an instance method, self resolves to the receiver object. Outside an instance method, but inside a class definition, self resolves to the class.

Now consider this example:
class SelfStudy
attr_accessor :name

def self
@name
end

def self.name
@name
end

def self.name=(name)
@name = name
end

def self.default_name
self.name = "ClassName"
end

def default_name
self.name = "InstanceName"
end
end


Now playing with this class:
puts SelfStudy.name
#=> nil
puts SelfStudy.default_name
#=> ClassName

me = SelfStudy.new
puts me.name
#=> nil
puts me.default_name
#=> InstanceName

puts SelfStudy.name
#=> ClassName
puts SelfStudy.default_name
#=> ClassName

Please note the I just want to play up with self in the above example. So instead of defining @name in self method. As you should already know, you may simply replace it with
@name = nil

Getters and setters in Ruby class

Now consider this fragment, and pay attention to the getmyvar, setmyvar, and myvar= methods:

class MyClass

NAME = "Class Name" # class constant
@@count = 0 # Initialize a class variable
def initialize # called when object is allocated
@@count += 1
@myvar = 10
end

def MyClass.getcount # class method
@@count # class variable
end

def getcount # instance returns class variable!
@@count # class variable
end

def getmyvar # instance method
@myvar # instance variable
end

def setmyvar(val) # instance method sets @myvar
@myvar = val
end
def myvar=(val) # Another way to set @myvar
@myvar = val
end
end

Now lets create instance of this class:
foo = MyClass.new # @myvar is 10
foo.setmyvar 20 # @myvar is 20
foo.myvar = 30 # @myvar is 30

Here we see that getmyvar returns the value of @myvar, and setmyvar sets it. (In the terminology of many programmers, these would be referred to as a getter and a setter.) These work fine, but they do not exemplify the Ruby way of doing things. The method myvar= looks like assignment overloading (though strictly speaking, it isn't); it is a better replacement for setmyvar, but there is a better way yet.

The class called Module contains methods called attr, attr_accessor, attr_reader, and attr_writer. These can be used (with symbols as parameters) to automatically handle controlled access to the instance data. For example, the three methods getmyvar, setmyvar, and myvar= can be replaced by a single line in the class definition:

attr_accessor :myvar

This creates a method myvar that returns the value of @myvar and a method myvar= that enables the setting of the same variable. Methods attr_reader and attr_writer create read-only and write-only versions of an attribute, respectively.

Class level variables in ruby

We should use @@ to create such variables, they are similar to static variables we see in java or cpp.

class MyClass

@@count = 0 # Initialize a class variable

def initialize # called when object is allocated
@@count += 1
@myvar = 10
end
end

Wednesday, October 12, 2011

Built-in classes in Ruby

More than 30 built-in classes are predefined in the Ruby class hierarchy. Like many other OOP languages, Ruby does not allow multiple inheritance, but that does not necessarily make it any less powerful. Modern OO languages frequently follow the single inheritance model. Ruby does support modules and mixins, which are discussed in the next section. It also implements object IDs, as we just saw, which support the implementation of persistent, distributed, and relocatable objects.

Some points to cover are: