Lets get right to it. Here’s how one can write a NullObject
in a modern, Rubocop-friendly manner:
class NullObject
def method_missing method, *args, &block
if respond_to? method
nil
else
super
end
end
def respond_to_missing? _name, _include_private = false
true
end
end
One of the things you should support is the fallback to super
. I achieve that by the if/else
block. In practice super
is never reached, so this feels a little bit like a waste.
The other thing is to declare whether your object (NullObject
) should respond to methods it doesn’t have. A true null object should respond to all methods, so I set respond_to_missing?
to true
.
Just for posterity, here’s how you could write specs for it:
describe NullObject do
it 'returns nil for any method call' do
null = NullObject.new
expect(null.missing_method).to be_nil
expect(null.some_other_missing_method(1, 2, 3)).to be_nil
end
it 'responds to missing methods' do
null = NullObject.new
expect(null.respond_to?(:missing_method)).to be true
end
end
Additional reading about the NullObject
pattern:
- http://wiki.c2.com/?NullObject
- http://www.virtuouscode.com/2011/05/30/null-objects-and-falsiness/