Community

What I would’ve loved I had known when I first met Ruby


Motivation

Everytime I’m learning a new language, the first thing I try to learn is how this new language
implements OOP, and now it’s Ruby’s turn. Before joining the company, I had been playing with Java for some
years; then I first heard about Ruby being a fully OOP language I got really excited, and
when I got hands-on some existing Ruby code, things got confusing.

I would’ve liked to know all of this before looking at any Ruby code:

First things first: Ruby Objects

Things that we must know:

  • And object is formed by: State + Behavior = Object
  • Everything in Ruby is an object, even nil which is NilClass, false FalseClass, true TrueClass and modules

    ruby-1.8.7-p299 > “some”.class
    => String
    ruby-1.8.7-p299 > “some”.class.superclass
    => Object
    ruby-1.8.7-p299 > “some”.class.superclass.superclass
    => nil
    ruby-1.8.7-p299 > “some”.class.superclass.superclass.class
    => NilClass
    ruby-1.8.7-p299 > false.class
    => FalseClass
    ruby-1.8.7-p299 > true.class
    => TrueClass
    ruby-1.8.7-p299 > module B end
    => nil
    ruby-1.8.7-p299 > B.class
    => Module
    ruby-1.8.7-p299 > B.class.superclass
    => Object

  • Do you remember those so-called ‘static classes’ in languages other than Ruby? They’re objects too,
    and when I say objects, I really mean it. Consider the following code stored in test.rb file:

    class A
    def self.outside
    self
    end

    def inside
    self
    end
    end

Let’s play with it using irb:
ruby-1.8.7-p299 > require ‘./test’
ruby-1.8.7-p299 > A.outside
=> A
ruby-1.8.7-p299 > A.outside.class
=> Class
ruby-1.8.7-p299 > A.new.inside
=> #
ruby-1.8.7-p299 > A.new.inside.class
=> A

As you can see both are A objects whose type is Class

  • Those class names are constants containing references to objects:

    ruby-1.8.7-p299 > clazz = Class.new
    => #Class:0x7f8fdec83230
    ruby-1.8.7-p299 > clazz.class
    => Class
    ruby-1.8.7-p299 > Blabla = clazz
    => Blabla
    ruby-1.8.7-p299 > Blabla.class
    => Class
    ruby-1.8.7-p299 > Blabla.new
    => #Blabla:0x7f8fdec77a70

Self

When I first met Ruby I thought “self” was the same as this (like in many other languages), and I was wrong, so lets
see what it is:

Default receiver of method calls

Since everything in Ruby are objects, then all the function definitions we find defined all around
and all those functions we call like p,
puts, def, etc are method calls. Some may
not be exactly defined inside a class but, in the end they will get either inherited or mixed in.

Look at following example:
p “1. Current receiver is #{self}”
class A
p “2. Current receiver is #{self}”
def initialize
p “3. Current receiver is #{self}”
end
p “4. Current receiver is #{self}”
end
p “5. Current receiver is #{self}”

Running this script we see:
user@user-desktop:~$ ruby test.rb
“1. Current receiver is main”
“2. Current receiver is A”
“4. Current receiver is A”
“5. Current receiver is main”

Where instance variables are found

class A
  def initialize
    @a, @b = 2, 1
  end
end

p A.new.instance_variables

Running this script we see:
user@user-desktop:~$ ruby test.rb
[“@b”, “@a”]

Metaprogramming

This is why I fell in love with ruby, it is a huge topic which I won’t cover, but it allows you
to write code that writes code lets see some examples:

Create a A Class, re-open it and see how it is the same object

class A
  def method1
    p "I'm method one"
  end
end

p A.instance_methods false
p A.object_id

class A
  def method2
    p "I'm method two"
  end
end

p A.instance_methods false
p A.object_id

Which throws:
user@user-desktop:~$ ruby test.rb
[“method1”]
70312385439840
[“method2”, “method1”]
70312385439840

As you saw the object id remains the same after re-open a class in order to add a second method, also,
we got all instance methods that one class
of A would have.

Call all instance methods of a certain class whenever you call a method whose name matches

class A
  def hello
    p "Hello"
  end 
  def bye 
    p "Bye"
  end 
  def welcome
    p 'Welcome'
  end 
  def method_missing(method_name, *args, &block)
    method_to_call = methods.find {|name| name =~ /#{method_name.to_s}/}
    send(method_to_call) if method_to_call
    p 'Unknown method' unless method_to_call
  end 
end

instance = A.new
instance.els
instance.hel
instance.by
instance.wel

Which throws:
user@user-desktop:~$ ruby test.rb
“Unknown method”
“Hello”
“Bye”
“Welcome”

That’s it. I hope this gives you some good overview and if you are ready for the whole package I
suggest you start with:

Happy programming!

Community
The Rubber Duck Effect
Best Practices
De Código, Café y Cervezas – Clean Code
Best Practices
De Código, Café y Cervezas – Clean Code 2da Parte