10.Methods, Blocks and Modules In Ruby

Methods: 

Ruby methods are very similar to functions in any other programming language. Ruby methods are used to bundle one or more repeatable statements into a single unit.
Method names should begin with a lowercase letter. If you begin a method name with an uppercase letter, Ruby might think that it is a constant and hence can parse the call incorrectly.
Methods should be defined before calling them, otherwise Ruby will raise an exception for undefined method invoking.

Syntax:

def method_name [( [arg [= default]]...[, * arg [, &expr ]])]
   expr..
end
So you can define a simple method as follows:
def method_name 
   expr..
end
You can represent a method that accepts parameters like this:
def method_name (var1, var2)
   expr..
end
You can set default values for the parameters which will be used if method is called without passing required parameters:
def method_name (var1=value1, var2=value2)
   expr..
end
Whenever you call the simple method, you write only the method name as follows:
method_name
However, when you call a method with parameters, you write the method name along with the parameters, such as:
method_name 25, 30
The most important drawback to using methods with parameters is that you need to remember the number of parameters whenever you call such methods. For example, if a method accepts three parameters and you pass only two, then Ruby displays an error.

Example:

#!/usr/bin/ruby

def test(a1="Ruby", a2="Perl")
   puts "The programming language is #{a1}"
   puts "The programming language is #{a2}"
end
test "C", "C++"
test
This will produce the following result:
The programming language is C
The programming language is C++
The programming language is Ruby
The programming language is Perl

Return Values from Methods:

Every method in Ruby returns a value by default. This returned value will be the value of the last statement. For example:
def test
   i = 100
   j = 10
   k = 0
end
This method, when called, will return the last declared variable k.

Ruby return Statement:

The return statement in ruby is used to return one or more values from a Ruby Method.
Syntax:

return [expr[`,' expr...]]
If more than two expressions are given, the array containing these values will be the return value. If no expression given, nil will be the return value.

Example:

return

OR

return 12

OR

return 1,2,3
Have a look at this example:
#!/usr/bin/ruby

def test
   i = 100
   j = 200
   k = 300
return i, j, k
end
var = test
puts var
This will produce the following result:
100
200
300

Variable Number of Parameters:

Suppose you declare a method that takes two parameters, whenever you call this method, you need to pass two parameters along with it.
However, Ruby allows you to declare methods that work with a variable number of parameters. Let us examine a sample of this:
#!/usr/bin/ruby

def sample (*test)
   puts "The number of parameters is #{test.length}"
   for i in 0...test.length
      puts "The parameters are #{test[i]}"
   end
end
sample "Zara", "6", "F"
sample "Mac", "36", "M", "MCA"
In this code, you have declared a method sample that accepts one parameter test. However, this parameter is a variable parameter. This means that this parameter can take in any number of variables. So above code will produce following result:
The number of parameters is 3
The parameters are Zara
The parameters are 6
The parameters are F
The number of parameters is 4
The parameters are Mac
The parameters are 36
The parameters are M
The parameters are MCA

Class Methods:

When a method is defined outside of the class definition, the method is marked as private by default. On the other hand, the methods defined in the class definition are marked as public by default. The default visibility and the private mark of the methods can be changed by public or private of the Module.
Whenever you want to access a method of a class, you first need to instantiate the class. Then, using the object, you can access any member of the class.
Ruby gives you a way to access a method without instantiating a class. Let us see how a class method is declared and accessed:
class Accounts
   def reading_charge
   end
   def Accounts.return_date
   end
end
See how the method return_date is declared. It is declared with the class name followed by a period, which is followed by the name of the method. You can access this class method directly as follows:
Accounts.return_date
To access this method, you need not create objects of the class Accounts.

Ruby alias Statement:

This gives alias to methods or global variables. Aliases can not be defined within the method body. The alias of the method keep the current definition of the method, even when methods are overridden.
Making aliases for the numbered global variables ($1, $2,...) is prohibited. Overriding the built-in global variables may cause serious problems.

Syntax:

alias method-name method-name
alias global-variable-name global-variable-name

Example:

alias foo bar
alias $MATCH $&
Here we have defined foo alias for bar and $MATCH is an alias for $&

Ruby undef Statement:

This cancels the method definition. An undef can not appear in the method body.
By using undef and alias, the interface of the class can be modified independently from the superclass, but notice it may be broke programs by the internal method call to self.

Syntax:

undef method-name

Example:

To undefine a method called bar do the following:

undef bar


Blocks:

You have seen how Ruby defines methods where you can put number of statements and then you call that method. Similarly, Ruby has a concept of Block.
  • A block consists of chunks of code.
  • You assign a name to a block.
  • The code in the block is always enclosed within braces ({}).
  • A block is always invoked from a function with the same name as that of the block. This means that if you have a block with the name test, then you use the function test to invoke this block.
  • You invoke a block by using the yield statement.

Syntax:

block_name{
   statement1
   statement2
   ..........
}
Here, you will learn to invoke a block by using a simple yield statement. You will also learn to use a yield statement with parameters for invoking a block. You will check the sample code with both types of yield statements.

The yield Statement:

Let's look at an example of the yield statement:
#!/usr/bin/ruby

def test
   puts "You are in the method"
   yield
   puts "You are again back to the method"
   yield
end
test {puts "You are in the block"}
This will produce the following result:
You are in the method
You are in the block
You are again back to the method
You are in the block
You also can pass parameters with the yield statement. Here is an example:
#!/usr/bin/ruby

def test
   yield 5
   puts "You are in the method test"
   yield 100
end
test {|i| puts "You are in the block #{i}"}
This will produce the following result:
You are in the block 5
You are in the method test
You are in the block 100
Here, the yield statement is written followed by parameters. You can even pass more than one parameter. In the block, you place a variable between two vertical lines (||) to accept the parameters. Therefore, in the preceding code, the yield 5 statement passes the value 5 as a parameter to the test block.
Now, look at the following statement:
test {|i| puts "You are in the block #{i}"}
Here, the value 5 is received in the variable i. Now, observe the following puts statement:
puts "You are in the block #{i}"
The output of this puts statement is:
You are in the block 5
If you want to pass more than one parameters, then the yield statement becomes:
yield a, b
and the block is:
test {|a, b| statement}
The parameters will be separated by commas.

Blocks and Methods:

You have seen how a block and a method can be associated with each other. You normally invoke a block by using the yield statement from a method that has the same name as that of the block. Therefore, you write:
#!/usr/bin/ruby

def test
  yield
end
test{ puts "Hello world"}
This example is the simplest way to implement a block. You call the test block by using the yield statement.
But if the last argument of a method is preceded by &, then you can pass a block to this method and this block will be assigned to the last parameter. In case both * and & are present in the argument list, & should come later.
#!/usr/bin/ruby

def test(&block)
   block.call
end
test { puts "Hello World!"}
This will produce the following result:
Hello World!

BEGIN and END Blocks

Every Ruby source file can declare blocks of code to be run as the file is being loaded (the BEGIN blocks) and after the program has finished executing (the END blocks).
#!/usr/bin/ruby

BEGIN { 
  # BEGIN block code 
  puts "BEGIN code block"
} 

END { 
  # END block code 
  puts "END code block"
}
  # MAIN block code 
puts "MAIN code block"
A program may include multiple BEGIN and END blocks. BEGIN blocks are executed in the order they are encountered. END blocks are executed in reverse order. When executed, above program produces the following result:
BEGIN code block
MAIN code block
END code block


Modules:

Modules are a way of grouping together methods, classes, and constants. Modules give you two major benefits.
  • Modules provide a namespace and prevent name clashes.
  • Modules implement the mixin facility.
Modules define a namespace, a sandbox in which your methods and constants can play without having to worry about being stepped on by other methods and constants.

Syntax:

module Identifier
   statement1
   statement2
   ...........
end
Module constants are named just like class constants, with an initial uppercase letter. The method definitions look similar, too: Module methods are defined just like class methods.
As with class methods, you call a module method by preceding its name with the module's name and a period, and you reference a constant using the module name and two colons.

Example:

#!/usr/bin/ruby

# Module defined in trig.rb file

module Trig
   PI = 3.141592654
   def Trig.sin(x)
   # ..
   end
   def Trig.cos(x)
   # ..
   end
end
We can define one more module with same function name but different functionality:
#!/usr/bin/ruby

# Module defined in moral.rb file

module Moral
   VERY_BAD = 0
   BAD = 1
   def Moral.sin(badness)
   # ...
   end
end
Like class methods, whenever you define a method in a module, you specify the module name followed by a dot and then the method name.

Ruby require Statement:

The require statement is similar to the include statement of C and C++ and the import statement of Java. If a third program wants to use any defined module, it can simply load the module files using the Ruby require statement:

Syntax:

require filename
Here, it is not required to give .rb extension along with a file name.

Example:

$LOAD_PATH << '.'

require 'trig.rb'
require 'moral'

y = Trig.sin(Trig::PI/4)
wrongdoing = Moral.sin(Moral::VERY_BAD)
Here we are using $LOAD_PATH << '.' to make Ruby aware that included files must be searched in the current directory. If you do not want to use $LOAD_PATH then you can use require_relative to include files from a relative directory.
IMPORTANT: Here, both the files contain same function name. So, this will result in code ambiguity while including in calling program but modules avoid this code ambiguity and we are able to call appropriate function using module name.

Ruby include Statement:

You can embed a module in a class. To embed a module in a class, you use the include statement in the class:

Syntax:

include modulename
If a module is defined in a separate file, then it is required to include that file using require statement before embedding module in a class.

Example:

Consider following module written in support.rb file.
module Week
   FIRST_DAY = "Sunday"
   def Week.weeks_in_month
      puts "You have four weeks in a month"
   end
   def Week.weeks_in_year
      puts "You have 52 weeks in a year"
   end
end
Now, you can include this module in a class as follows:
#!/usr/bin/ruby
$LOAD_PATH << '.'
require "support"

class Decade
include Week
   no_of_yrs=10
   def no_of_months
      puts Week::FIRST_DAY
      number=10*12
      puts number
   end
end
d1=Decade.new
puts Week::FIRST_DAY
Week.weeks_in_month
Week.weeks_in_year
d1.no_of_months
This will produce the following result:
Sunday
You have four weeks in a month
You have 52 weeks in a year
Sunday
120

Mixins in Ruby:

Before going through this section, I assume you have knowledge of Object Oriented Concepts.
When a class can inherit features from more than one parent class, the class is supposed to show multiple inheritance.
Ruby does not support multiple inheritance directly but Ruby Modules have another wonderful use. At a stroke, they pretty much eliminate the need for multiple inheritance, providing a facility called a mixin.
Mixins give you a wonderfully controlled way of adding functionality to classes. However, their true power comes out when the code in the mixin starts to interact with code in the class that uses it.
Let us examine the following sample code to gain an understand of mixin:
module A
   def a1
   end
   def a2
   end
end
module B
   def b1
   end
   def b2
   end
end

class Sample
include A
include B
   def s1
   end
end

samp=Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1
Module A consists of the methods a1 and a2. Module B consists of the methods b1 and b2. The class Sample includes both modules A and B. The class Sample can access all four methods, namely, a1, a2, b1, and b2. Therefore, you can see that the class Sample inherits from both the modules. Thus, you can say the class Sample shows multiple inheritance or a mixin.

No comments:

Post a Comment