Dan Rubio Dan Rubio - 10 months ago 25
Ruby Question

Can someone help explain the post_initialize callback for class creation (Sandi Metz)

I am reading Sandi Metz's POODR and have come across a coding principle that I don't quite understand. Here is the code:

class Bicycle
attr_reader :size, :chain, :tire_size

def initialize(args = {})
@size = args[:size] || 1
@chain = args[:chain] || 2
@tire_size = args[:tire_size] || 3

class MountainBike < Bicycle
attr_reader :front_shock, :rear_shock

def post_initialize(args)
@front_shock = args[:front_shock]
@rear_shock = args[:rear_shock]

mb = MountainBike.new(front_shock: 4, rear_shock: 5)
puts mb.size
puts mb.chain
puts mb.tire_size
puts mb.front_shock
puts mb.rear_shock

This code will output
for its respective attributes. What I don't understand is the method look up.

When a mountain bike is instantiated, because it does not have its own
method, it will travel up the method lookup chain onto its super class (
). But now from there, it seems that Bicycle then moves back down into MountainBike's post_initialize method. Instead of continuing up the method chain, how can it go back down? Is
a ruby keyword like
in that it serves some sort of special function? Is there some other ruby introspection methods I can use to see what is going on?


The important thing to understand here is that in this code:

def initialize(args = {})
  # ...

...post_initialize has an implicit receiver, self. In other words, post_initialize(args) here is equivalent to self.post_initialize(args), and self is an instance of MountainBike. Method lookup always starts with the receiver's class, so it has no trouble finding MountainBike#post_initialize.

 That's a lie; it's not equivalent when it comes to privacy; private methods cannot be called with an explicit receiver.
 That's also a lie; it actually starts with the receiver's singleton class, but then it tries its class.