Methods & Blocks

Methods

Methods in Ruby are set of expressions that 1) always return a value, 2) are always associated with some Ruby object.

Ruby methods are not straightforward objects but can be obtained as objects using an Object.method method. Such a method object might be 1) called, 2) used as a block or 3) unbound from its associated object and bound to another.

class Mathematician
  def sum(a, b)
    a + b
  end
end

engineer = Mathematician.new
engineer.sum(2, 2) # => 4
engineer.sum.class # => ArgumentError: wrong number of arguments (given 0, expected 2)
object_method = engineer.method(:sum)
object_method.class # => Method
object_method.call(3, 3) # => 6

Method Arguments

Arguments can be provided to Ruby methods through: 1) standard arguments, 2) keyword arguments, and 3) variable length arguments.

# Standard arguments:
def sum(first_number, second_number)
  first_number + second_number
end

sum(2, 2) #=> 4
sum(2) #=> ArgumentError: wrong number of arguments (given 1, expected 2)

# Keyword arguments:
def sum(first_number:, second_number:)
  first_number + second_number
end

sum(first_number: 2, second_number: 2) # => 4
sum(second_number: 2, first_number: 2) # => 4
sum(first_number: 2) # => missing keyword: second_number

# Variable length arguments:
def sum_all(*args)
  args.inject(0, :+)
end

sum_all(1, 2, 3) # => 6
sum_all(1, 2, 3, 4, 5) # => 15

With both - standard arguments and keyword arguments - it is possible to use default values making the arguments with default values optional.

def sum(first_number, second_number = 2)
  first_number + second_number
end

sum(2, 3) #=> 5
sum(2) #=> 4

def sum(first_number:, second_number: 2)
  first_number + second_number
end

sum(first_number: 2, second_number: 3) # => 5
sum(first_number: 2) # => 4

Blocks

It might be said that an inspiration for blocks were higher-order functions.

Blocks in Ruby are set of expressions accepting arguments that 1) do not return a value by itself, 2) are not associated with any Ruby object. Blocks are not objects but can be turned to objects with & notation signalled in a given method's arguments.

Blocks are signalled by the do ... end notation or the { ... } notation and their arguments are enclosed in |...| notation.

Blocks can be 1) called from within a method or 2) yielded to.

Calling Blocks

Blocks can be turned into objects (namely procs) and called when its underlying method uses & in its arguments.

def sum(&my_block)
  my_block.call(2, 2)
end

sum { |a, b| a + b } # => 4
sum { |a, b| a - b } # => 0
sum { |a, b| a + a + b + b } # => 8

Yielding to Blocks

The same results as with calling blocks can be achieved with yielding to blocks with a yield keyword.

def sum
  yield(3, 4)
end

sum { |a, b| a + b } # => 7
sum { |a, b| a - b } # => -1
sum { |a, b| a + a + b + b } # => 14