Many people think of Ruby as an Object Oriented Language. It is - and a lovely one at that. But Ruby makes so much more sense if you think of it as a Message Oriented Language. Most of programming in Ruby involves sending messages to objects, and defining how objects should respond to messages. Master this and you’ve almost mastered Ruby.

We can send a message to an object by using the dot operator, the message name, and an optional payload (typically known as arguments in other languages).

object.send(:message)

object.send(:message, payload)

So how do we add 2 & 3 in Ruby? We send the object 2 the message + and the payload 3:

2.send(:+, 3)
# => 5

How do we reverse the string RailsGirls? By sending a String object the message reverse:

"RailsGirls".send(:reverse)
# => "slriGslisR"

And to randomly generate 5 numbers between 0 and 100, we send a Range object the message to_a which responds with an Array Object. We then send this object the message sample and the payload 5:

(0..100).send(:to_a).send(:sample, 5)
# => [75, 89, 76, 62, 55]

Syntactic Sugar

Every language is optimised for some quality. C is optimised for speed. Java is optimised for bureaucracy. Ruby is optimised for developer happiness.

One way to make developers happy is by giving them a rich and expressive language. Ruby does this by sprinkling some semantic sugar on top of its message oriented architecture. The first dollop of sugar let’s us stop the tedious .send(:message) syntax and replace it with simply .message.

2.send(:+, 3)
# => 5

2.+(3)
# => 5  

"Hello, Ruby!".send(:include?, "Z")
# => false

"Hello, Ruby!".include?("Z")
# => false

Next, we can get rid of parenthesis so long as there is no ambiguity.

2.+ 3
# => 5  

66.even?
# => true

Finally, some core objects have additional semantic sugar baked in.

2.send(:+, 3)
2 + 3
# => 5

"I love Ruby".send(:[], (2..5))
"I love Ruby"[2..5]
# => "love"

Mmmm, syntax. Yummy.

Everything in Ruby is an Object. Almost

Spend any time around Rubyists and you’ll here that everything in Ruby is an object. That’s almost true but why it’s almost true becomes clearer when you understand just how Ruby conceives of objects.

The traditional coneption of an object in computer science is anything that holds state and exhibits behaviour. In Ruby however, an object is anything that responds to a message.

Numbers are objects because they respond to messages.

42.class
# => Fixnum

Strings are objects because they respond to messages.

"Ruby is beautiful".class
# => String

Booleans are objects because they respond to messages.

true.class
# => TrueClass

Nils are objects because they respond to messages.

nil.class
# => NilClass

Objects are obviously objects because they respond to messages.

Object.class
# => Class

Even Classes are objects because they respond to messages.

Class.class
# => Class

Yes, the Class class is an object of class Class. Ruby is meta.

Responding to Messages

While much of programming in Ruby involves sending messages to objects, a lot also involves the other side of this relationship - defining how objects should respond to messages. The Ruby Core and Standard libraries already provide a bunch of useful functionality. Often however, we need to compose our own. Ruby of course, make this all very simple with the class keyword.

class MyFirstClass
end

That it - we’ve just created a class of object called MyFirstClass. Out of the box, we get a lot of functionality thanks to Ruby’s automatic inheritance from the Object class.

MyFirstClass.ancestors
# => [MyFirstClass, Object, Kernel, BasicObject]


MyFirstClass.methods
# => [:allocate, :new, :superclass, :freeze, :===, :==, :<=>, :<, :<=, :>, :>=, :to_s, :inspect, :included_modules, :include?, :name, :ancestors, :instance_methods, :public_instance_methods, :protected_instance_methods, :private_instance_methods, :constants, :const_get, :const_set, :const_defined?, :const_missing, :class_variables, :remove_class_variable, :class_variable_get, :class_variable_set, :class_variable_defined?, :public_constant, :private_constant, :singleton_class?, :include, :prepend, :module_exec, :class_exec, :module_eval, :class_eval, :method_defined?, :public_method_defined?, :private_method_defined?, :protected_method_defined?, :public_class_method, :private_class_method, :autoload, :autoload?, :instance_method, :public_instance_method, :nil?, :=~, :!~, :eql?, :hash, :class, :singleton_class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Typically though, that isn’t enough. Often, we need to define our own responses to messages which we do with the def keyword.

class Hipster
  def ironic?
    true
  end

  def opinion_on(it)
     "#{it} is so last year.""
  end
end

Now we can create instance objects of our Hipster class, send them messages, and watch them respond.

byron = Hipster.new
# => #<Hipster:0x007f83539f6130>

byron.ironic?
# => true

byron.opinion_on "Craft beer"
# => "Craft beer is so last year."

That’s largely all there is to Ruby. Just remember that it’s a Message Oriented Language.