Ruby Programming/Syntax/Classes

From Wikibooks, the open-content textbooks collection

Jump to: navigation, search

Classes are the basic template from which object instances are created. A class is made up of a collection of variables representing internal state and methods providing behaviours that operate on that state.

Contents

[edit] Class Definition

Classes are defined in Ruby using the class keyword followed by a name. The name must begin with a capital letter and by convention names that contain more than one word are run together with each word capitalized and no separating characters (CamelCase). The class definition may contain method, class variable, and instance variable declarations as well as calls to methods that execute in the class context, such as attr_accessor. The class declaration is terminated by the end keyword.

Example:

  class MyClass
    def some_method
    end
  end

[edit] Instance Variables

Instance variables are created for each class instance and are accessible only within that instance or through the methods provided by that instance. They are accessed using the @ operator.

Example:

  class MyClass
    @one = 1
    def do_something
      @one = 2
    end
    def output
      puts @one
    end
  end
  instance = MyClass.new
  instance.output
  instance.do_something
  instance.output

Surprisingly, this outputs:

 nil
 2


This happens (nil in the first output line) because @one defined below class MyClass is an instance variable belonging to the class object (note this is not the same as a class variable and could not be referred to as @@one), whereas @one defined inside the do_something method is an instance variable belonging to instances of MyClass. They are two distinct variables and the first is accessible only in a class method.

[edit] Class Variables

Class variables are accessed using the @@ operator. These variables are associated with the class rather than any object instance of the class and are the same across all object instances. (These are the same as class "static" variables in Java or C++).

Example:

  class MyClass
    @@value = 1
    def add_one
      @@value= @@value + 1
    end
 
    def value
      @@value
    end
  end
  instanceOne = MyClass.new
  instanceTwo = MyClass.new
  puts instanceOne.value
  instanceOne.add_one
  puts instanceOne.value
  puts instanceTwo.value

Outputs:

 1
 2
 2

[edit] Class Instance Variables

Classes can have instance variables. This gives each class a variable that is not shared by other classes in the inheritance chain.

  class Employee
    class << self; attr_accessor :instances; end
    def store
      self.class.instances ||= []
      self.class.instances << self
    end
    def initialize name
      @name = name
    end
  end
  class Overhead < Employee; end
  class Programmer < Employee; end
  Overhead.new('Martin').store
  Overhead.new('Roy').store
  Programmer.new('Erik').store
  puts Overhead.instances.size    # => 2
  puts Programmer.instances.size  # => 1

For more details, see MF Bliki: ClassInstanceVariables

[edit] Class Methods

Class methods are declared the same way as normal methods, except that they are prefixed by self, or the class name, followed by a period. These methods are executed at the Class level and may be called without an object instance. They cannot access instance variables but do have access to class variables.

Example:

  class MyClass
    def self.some_method
      puts 'something'
    end
  end
  MyClass.some_method

Outputs:

 something

[edit] Instantiation

An object instance is created from a class through the a process called instantiation. In Ruby this takes place through the Class method new.

Example:

  anObject = MyClass.new(parameters)

This function sets up the object in memory and then delegates control to the initialize function of the class if it is present. Parameters passed to the new function are passed into the initialize function.

  class MyClass
    def initialize(parameters)
    end
  end

[edit] Declaring Visibility

By default, all methods in Ruby classes are public - accessible by anyone. If desired, this access can be restricted by public, private, protected object methods. It is interesting that these are not actually keywords, but actual methods that operate on the class, dynamically altering the visibility of the methods.

As a result of that fact these 'keywords' influence the visibility of all following declarations until a new visibility is set or the end of the declaration-body is reached.

[edit] Private

Simple example:

  class Example
    def methodA
    end
 
    private # all methods that follow will be made private: not accessible for outside objects
 
    def methodP
    end
  end

If private is invoked without arguments, it sets access to private for all subseqent methods. It can also be invoked with named arguments.

Named private method example:

  class Example
    def methodA
    end
 
    def methodP
    end
 
    private :methodP
  end

Here private was invoked with an argument, altering the visibility of methodP to private.

Note for class methods (those that are declared using def ClassName.method_name), you need to use another function: private_class_method

Common usage of private_class_method is to make the "new" method (constructor) inaccessible, to force access to an object through some getter function. A typical Singleton implementation is an obvious example.

  class SingletonLike
    private_class_method :new
 
    def SingletonLike.create(*args, &block)
      @@inst = new(*args, &block) unless @@inst
      return @@inst
    end
  end

More info about the difference between C++ and Ruby private/protected: http://lylejohnson.name/blog/?p=5

One person summed up the distinctions by saying that in C++, “private” means “private to this class”, while in Ruby it means “private to this instance”. What this means, in C++ from code in class A, you can access any private method for any other object of type A. In Ruby, you can not: you can only access private methods for your instance of object, and not for any other object instance (of class A).

Ruby folks keep saying "private means you cannot specify the receiver". What they are saying, if method is private, in your code you can say:

  class AccessPrivate
    def a
    end
    private :a # a is private method
 
    def accessing_private
      a              # sure! 
      self.a         # nope! private methods cannot be called with an explicit receiver at all, even if that receiver is "self"
      other_object.a # nope, a is private, you can't get it (but if it was protected, you could!)
    end
  end

Here, "other_object" is the "receiver" that method "a" is invoked on. For private methods, it does not work. However, that is what "protected" visibility will allow.

[edit] Public

Public is default accessibility level for class methods. I am not sure why this is specified - maybe for completeness, maybe so that you could dynamically make some method private at some point, and later - public.

In Ruby, visibility is completely dynamic. You can change method visibility at runtime!

[edit] Protected

Now, protected deserves more discussion. Those of you coming from Java (or C++) background, you know that "private" means that method visibility is restricted to the declaring class, and if method is "protected", it will be accessible for children of the class (classes that inherit from parent).

In Ruby, private visibility is what protected was in Java. Private methods in Ruby are accessible from children. This is a sensible design, since in Java, when method was private, it rendered it useless for children classes: making it a rule, that all methods should be "protected" by default, and never private. However, you can't have truly private methods in Ruby; you can't completely hide a method.

The difference between protected and private is subtle. If a method is protected, it may be called by any instance of the defining class or its subclasses. If a method is private, it may be called only within the context of the calling object---it is never possible to access another object instance's private methods directly, even if the object is of the same class as the caller. For protected methods, they are accessible from objects of the same class (or children).

So, from within an object "a1" (an instance of Class A), you can call private methods only for instance of "a1" (self). And you can not call private methods of object "a2" (that also is of class A) - they are private to a2. But you can call protected methods of object "a2" since objects a1 and a2 are both of class A.

Ruby FAQ gives following example - implementing an operator that compares one internal variable with variable from another class (for purposes of comparing the objects):

  def <=>(other)
    self.age <=> other.age
  end

If age is private, this method will not work, because other.age is not accessible. If "age" is protected, this will work fine, because self and other are of same class, and can access each other's protected methods.

To think of this, protected actually reminds me of the "internal" accessibility modifier in C# or "default" accessibility in Java (when no accessibility keword is set on method or variable): method is accessible just as "public", but only for classes inside the same package.

[edit] Instance Variables

Note that object instance variables are not really private, you just can't see them. To access an instance variable, you need to create a getter and setter.

Like this (no, don't do this by hand! See below):

  class GotAccessor
    def initialize(size)
      @size = size
    end
 
    def size
      @size
    end
    def size=(val)
      @size = val
    end
  end
 
  # you could the access @size variable as
  # a = GotAccessor.new(5)
  # x = a.size 
  # a.size = y

Luckily, we have special functions to do just that: attr_accessor, attr_reader, attr_writer. attr_accessor will give you get/set functionality, reader will give only getter and writer will give only setter.

Now reduced to:

  class GotAccessor
    def initialize(size)
      @size = size
    end
 
    attr_accessor :size
  end
 
  # attr_accessor generates variable @size accessor methods automatically:
  # a = GotAccessor.new(5)
  # x = a.size 
  # a.size = y

[edit] Inheritance

A class can inherit functionality and variables from a superclass, sometimes referred to as a parent class or base class. Ruby does not support multiple inheritance and so a class in Ruby can have only one superclass. The syntax is as follows:

 
  class ParentClass
    def a_method
      puts 'b'
    end
  end
 
  class SomeClass < ParentClass  # < means inherit (or "extends" if you are from Java background)
     def another_method
       puts 'a'
     end
  end
 
  instance = SomeClass.new
  instance.another_method
  instance.a_method

Outputs:

  a
  b

All non-private variables and functions are inherited by the child class from the superclass.

If your class overrides a method from parent class (superclass), you still can access the parent's method by using 'super' keyword.

  class ParentClass
    def a_method
      puts 'b'
    end
  end
 
  class SomeClass < ParentClass  
     def a_method
       super
       puts 'a'
     end
  end
 
  instance = SomeClass.new
  instance.a_method

Outputs:

  b
  a

(because a_method also did invoke the method from parent class).

If you have a deep inheritance line, and still want to access some parent class (superclass) methods directly, you can't. super only gets you a direct parent's method. But there is a workaround! When inheriting from a class, you can alias parent class method to a different name. Then you can access methods by alias.

  class X
    def foo
      "hello"
    end
  end
 
  class Y < X
    alias xFoo foo
      def foo
        xFoo + "y"
      end
  end
 
  puts X.new.foo
  puts Y.new.foo

Outputs

 hello
 helloy

[edit] Mixing in Modules

First, you need to read up on modules. Modules are way of grouping together some functions and variables and classes, somewhat like classes, but more like namespaces. So a module is not really a class. You can't instantiate a Module, and thus it does not have self.

This trait, however, allows us to include the module into a class. Mix it in, so to speak.

module MixALot
  def say_what?
    "hello"
  end
end
 
class MC
  include MixALot
 
  # ... method say_what? is available here!
end

Note if your module is in another file, you must first require that module, to bring it in, before you can use it in include.

[edit] Ruby Class Meta-Model

In keeping with the Ruby principle that everything is an object, classes are themselves instances of the class Class. They are stored in constants under the scope of the module in which they are declared. A call to a method on an object instance is delegated to a variable inside the object that contains a reference to the class of that object. The method implementation exists on the Class instance object itself. Class methods are implemented on meta-classes that are linked to the existing class instance objects in the same way that those classes instances are linked to them. These meta-classes are hidden from most Ruby functions.