Very often in Ruby code, we would like to execute some action only if an object is present:

def slug(title) if title title.strip.downcase.tr_s('^[a-z0-9]', '-') end end

slug(" Confident Code")

confident-code

h = {} slug(h[:missing_key])

nil

Strictly speaking, we aren’t checking for object presence here. In Ruby there is almost always an object present, but the default marker for missing data is the special nil object—the one and only instance of NilClass .

h = {} def noop; end

Expression Result h[:missing] nil noop nil if (1==2) then 'wrong' end nil

What we are really checking for is the presence of either a “falsy” object ( nil or false , most likely nil ), or a “truthy” object (anything other than nil or false ). So in effect this is an instance of typecasing.

Switching on object type is a smell in object-oriented languages. In general, we don’t want to ask an object what it is; we want to tell it what to do and let it figure out the best way to do it based on its type. This is the essence of polymorphism.

What we need is an object to represent the special case of “do nothing on missing value”. As it happens, there is a pattern for that: Null Object. Quoting Wikipedia: “a Null Object is an object with defined neutral (‘null’) behavior”.

Ruby does not have a built-in Null Object class ( NilClass doesn’t qualify). Implementation of one is trivial, however:

class NullObject def method_missing(*args, &block) nil end end

Instances of NullObject will respond to any message (method call) with a no-op.

no = NullObject.new no.foobar

nil

A more useful (and common) form of Null Object returns self from every call.

class NullObject def method_missing(*args, &block) self end end

This version makes it possible to nullify arbitrary chains of method calls:

NullObject.new.foobar.baz.buz

#<NullObject:0x7f97b56214f8>

A useful accompaniment to a Null Object class is a constructor method that converts nil values into null objects, and leaves other values as-is:

def Maybe(value) case value when nil then NullObject.new else value end end

We can also define some common conversions a la NilClass :

class NullObject def to_a; []; end def to_s; ""; end def to_f; 0.0; end def to_i; 0; end end

With these tools in hand we can rewrite our #slug method more cleanly, and, dare I say, more confidently:

def slug(title) Maybe(title).strip.downcase.tr('^[0-9a-z]', '-') end

puts slug(" Exceptional Ruby ").to_s # => "exceptional-ruby" puts slug(nil).to_s # => ""

In some cases we may want to call methods on other objects if the maybe-null object is not null. For this case, we can define the Ruby 1.9 / ActiveSupport #tap method as a no-op for NullObject :

class NullObject def tap; self; end end

Maybe(obj).tap do puts "Object is present!" end