Ruby Intro

SENG2021

Classes

Ruby is a Object Oriented language so it’s no less than intuitive to have classes. The following code block shows the basic syntax of a Ruby class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Counter
  @@classCount = 0
  @instanceCount

  def initialize(startInstanceCount)
    @instanceCount = startInstanceCount
  end

  def icIncrement
    @instanceCount += 1
  end

  def self.ccIncrement
    @@classCount += 1
  end

  def to_s
    "classCount = #{@@classCount} and instanceCount = #{@instanceCount}"
  end
end

We have a Class variable, @@classCount. This is equivalent to the keyword static in Java. There’s an Instance variable @instanceCount.

Then there are the methods. initialize is the constructor used when you run Counter.new, icIncrement is an instance method, while self.ccIncrement is a class method – called with Counter.ccIncrement.

Finally to_s is the conversion of the class to a String, just like toString().

1
2
3
4
5
6
7
8
9
10
11
12
a = Counter.new 0
b = Counter.new 0

Counter.ccIncrement
a.icIncrement

puts a
# classCount = 1 and instanceCount = 0

b = Counter.new 5
puts b
# classCount = 1 and instanceCount = 5

Variable Scope

Scope-wise, there are 5 different types of variables in Ruby and they are simply differentiated by the first character of their name.

  1. $: Global
  2. @@: Class
  3. @: Instance
  4. [A-Z]: Constant
  5. [a-z_]: Local

Note that Constants can still be changed. The interpreter will simply issue a warning that that is the case, but the value assigning will proceed.

1
2
3
4
5
Aconstant = 1
Aconstant = 2
# warning: already initialized constant Aconstant
# warning: previous definition of Aconstant was here
# 2

Dynamic Typing

Ruby doesn’t care what class an object is, as long as it does what you want it to do. If it quacks like a duck, it is a duck.

I’ve prepared the 3 files below already. To see them, checkout the branch git checkout dynamic_typing. This code is based on the code snippets in the Ruby Cookbook which was based on Ruby 1.8

duck.rb
1
2
3
4
5
class Duck
  def quack
    'Quack!'
  end
end
humans.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Man
  def quack
    'Moo!'
  end

  def scream
    'AHHHHHH'
  end
end

class Woman
  def scream
     'AHHHH'
  end
end
make_it_quack.rb
1
2
3
def make_it_quack(duck)
  puts duck.quack
end

And back to irb. This time, run it with irb -I .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require 'duck'
require 'humans'
require 'make_it_quack'

d = Duck.new
m = Man.new
w = Woman.new

make_it_quack(d)
# Quack!
make_it_quack(m)
# Moo!
make_it_quack(w)
# NoMethodError: undefined method `quack' for #<Woman:0x007fb2d91ab3d0>

Unfortunately it seems like function parameters can no longer be given a type so the example isn’t the most clear. This is what it looks like in the book.

1
2
3
4
5
6
7
def make_it_quack(Duck duck)
  puts duck.quack
end

w = Woman.new
make_it_quack(w)
# TypeException: object not of type Duck

Duck Punching

So what if our ducks (Man) don’t quack? Then we punch them until it does.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
make_it_quack(m)
# Moo!

class Man
  def quack
    "Quack!"
  end
end

make_it_quack(m)
# Quack!

m.scream
# AHHHHHH

Just to be clear, we can also do the same to the Woman class.

1
2
3
4
5
6
7
8
9
10
11
make_it_quack(w)
# NoMethodError: undefined method `quack' for #<Woman:0x007fbe7b99e800>

class Woman
  def quack
    "Quack!"
  end
end

make_it_quack(w)
# Quack!