Thought Schema

Programming the 20-something dream

Method_Missing: Gone Girl Your Code

Yes, Gone Girl is a verb. To avoid giving anything away, take it to mean to disappear, go absolutely mental, and return to an altered reality. Ruby has something similar: method_missing.

Gone Girl

Wonder how ActiveRecord creates those find methods on the fly? Method_messing. In fact, method_missing is a pillar of metaprogramming and is instrumental in the creation of DSLs.

When a method is called, Ruby looks for the method in the instance methods, class methods, superclass methods, mixins, etc. Method_missing is the last resort.

This means right before Ruby throws a NoMethod error, you can catch it with method_missing.

To see how it works, let’s see how Active Record’s find_by* methods are created:

1
2
3
4
5
6
7
8
class ActiveRecord::Base
  def method_missing(method_name, *args, &block) #1
    if method_name.to_s =~ /^find_by_(.+)$/ #2
      run_find_by_method($1, *args, &block) #3
    else
      super #4
    end
  end
  1. Method_missing takes three parameters: the method name, splatted arguments, and then a block to run.
  2. ActiveRecord is converting the method name into a string and then using Regex to match a find_by* pattern.
  3. This is the black box where the find_by* method is actually defined. When the method is defined, method_missing will no longer be called for that particular method name.
  4. Super allows Ruby to continue doing its thing if the match did not happen.

Try it yourself:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def method_missing(method_name, *arguments, &block)
  if method_name.to_s =~ /pattern_to_match/

    #This defines a class method for future usage.
    self.class.send (:define_method, method_name) do
      # Your magic
    end

    #This runs the newly minted method on your instance.
    self.send(method_name)
  else
    super
  end
end

#To ensure continuity in how Ruby treats methods, 
#you override the respond_to method Ruby has 
#with a match to your new method.
def respond_to?(method_name, include_private = false)
  method_name.to_s =~ /^what_is_[\w]+/ ? true : super
end

Go forth and catch those missing methods. Do not, however, Gone Girl.

Tap That Class

The Tap method reminds me of Nightcrawler, the furry indigo teleporter from the Marvel Universe. He appears out of nowhere, kicks ass, and then disappears in a puff of smoke.

Nightcrawler teleports

The Tap method, born in Ruby >= 1.9, is a helper method that yields a block on your object and returns the object. As a method, it looks like this:

class Object
  def tap
    yield self
    self
  end
end

This is especially useful when you are creating new classes because it allows you to assign properties from the get-go.

#Creating a new hero object
nightcrawler = Hero.new
nightcrawler.name = "Nightcrawler"
nightcrawler

#Refactored with tap
nightcrawler = Hero.new.tap{|h| name = "Nightcrawler"}

When you have many properties to set, this allows you to group all methods in an easy-to-read tap block.

nightcrawler = Hero.new.tap do |h|
  h.name = "Nightcrawler"
  h.power = "teleportation"
  h.train_under_xavier
  h.runaway
  h.redemption
  h.anything_else_you_want
end

Refactoring with tap can aid in readability. However, overdoing it with the tap blocks may result in the opposite. With great power, comes great responsibility.

Superpowers in mind, here’s the latest track from UK electro-duo Alunageorge. Goodbye for now.