Website Logo. Upload to /source/logo.png ; disable in /source/_includes/logo.html

A Coder's Journey

From educator to programmer.

Back to School & Back to Basics: How Everything Really IS an Object in Ruby

When I first started at Flatiron, I believed Ruby was the language of choice because of its simplicity–I might have even gone so far as to call it straightforward. I didn’t yet understand its eloquence–but I could, as a beginninger, tell that very quickly I was stumbling head-first into some pretty serious logic. I liked that it made me immediately feel smart. Like I was a real programmer! And so, for the first part of the course, I missed the heart of the language itself.

The heart. The truth. Ruby is alive: a world of objects, instances of Fixnum and String and Integer, and a thousand other classes upon which to build.

But they are all just objects.

Sandi Metz believes we should get to know our objects. We should talk to them. Ask them what they want, what they yearn for…so today, I start at the very beginning and ask myself: How is everything an object?

For starters, every Ruby object is an instance of some class.

Classes earn their keep by providing two key functions:

  1. Being containers for methods.
  2. Being factories for making instances.

And every class except one has a superclass, someplace that class can turn to when someone calls a methods the class doesn’t understand.

Let’s check it out by creating our very own CoolBeans class.

1
2
3
4
5
6
7
8
9
10
11
12
class CoolBeans
  attr_accessor :beans

  def initialize
    @beans = []
  end

  def count_beans
    @beans.count
  end

end

Just from looking at it, there are four readily apparent methods our class CoolBeans has:

  1. It can initialize a default empty array of beans when a new instance is created
  2. It can count how many beans it has
  3. It can return the object assigned to @beans (through the instance method beans)
  4. It can assign a new object to @beans (through the instance method beans=)

(The third and fourth methods are created through my attr_accessor)

But don’t trust me! Let’s just ask the class what instance methods it has!

First–lets make an instance of the class:

1
2
my_beans = CoolBeans.new
 => #<CoolBeans:0x007fe8abf516d0 @beans=[]> 

This returns an object that is an instance of CoolBeans. Our object variable, @beans,(also known as an instance variable), is set to its default value of an empty array upon initialization.

Second-what class is this object exactly?

1
2
my_beans.class
 => CoolBeans

Okay–so we knew that…but now, we can ask the class of this object, what instance methods it has:

1
2
my_beans.class.instance_methods
 => [:beans, :beans=, :count_beans, :lm, :lim, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :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__]

But we don’t even need to go up to the class to know the instance methods because the object itself is an instance and knows its methods:

1
2
 my_beans = CoolBeans.new.methods
 => [:beans, :beans=, :count_beans, :lm, :lim, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :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__]

Wait a hot sec. I thought this class only had 4 instance methods? The ones listed earlier! So what exacty is happening here?

In Ruby if you can reference something with a variable–it’s an object, and virtually all Ruby objects can trace their ancestry back to a Basic Object.

1
2
3
4
5
6
 my_beans.class #find the class of the object my_beans
 => CoolBeans
my_beans.class.superclass #find the superclass of my_beans
 => Object
my_beans.class.superclass.superclass #finds the base class of almost everything in Ruby
 => BasicObject

Hence, almost everything in Ruby is an object–which works out quite conveniently for us, because everything being an object and such, Ruby has given us a shared set of methods all objects have in common, re: the extra 50 or so instance methods available to the class that are not written in the code itself, but rather inherited.

Here are some common methods all objects have–and you should know them if for no other reason than to stay out of their way 😎.

1
2
3
4
5
instance_of?
to_s
public_methods
instance_variables
send

But one last thing! Where did our initialize method go? Why wasn’t it listed in my instance methods?

That is because instance_methods returns an array of public and protected methods. However, initialize is always private. To see it, we would have to do the following:

1
2
my_beans.class.private_instance_methods
 => [:initialize, :default_src_encoding, :irb_binding, :initialize_copy, :initialize_dup, :initialize_clone, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :warn, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :eval, :local_variables, :iterator?, :block_given?, :catch, :throw, :loop, :respond_to_missing?, :trace_var, :untrace_var, :at_exit, :syscall, :open, :printf, :print, :putc, :puts, :gets, :readline, :select, :readlines, :`, :p, :test, :srand, :rand, :trap, :load, :require, :require_relative, :autoload, :autoload?, :proc, :lambda, :binding, :caller, :caller_locations, :exec, :fork, :exit!, :system, :spawn, :sleep, :exit, :abort, :Rational, :Complex, :set_trace_func, :gem, :gem_original_require, :singleton_method_added, :singleton_method_removed, :singleton_method_undefined, :method_missing]

And there you have it. Front and center.

Cool beans.