Skip to content

Instantly share code, notes, and snippets.

@pricees
Last active September 16, 2016 17:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pricees/f5ec1c14ca479528f1e695367d074097 to your computer and use it in GitHub Desktop.
Save pricees/f5ec1c14ca479528f1e695367d074097 to your computer and use it in GitHub Desktop.
Basic Null Object for use in the Rubies
# A simple null object
class NullObject < BasicObject
def to_ary; nil end # Handle the `puts call to_ary` don't ask
# Add the attributes, methods you care to define here
# ...
#
# def name
# 'Nully'
# end
# Let method missing handle the rest
def method_missing(name, *args, &block)
name_str = name.to_s
case
when name_str.end_with?('?')
false
when name_str.end_with?('s')
[]
else
self
end
end
end
nully = NullObject.new
nully.nullies? # false
nully.nullify! # self
nully.nullies.empty? # true
nully.some_association? # false
nully.some_association.optimistic.call # self
nully.nullies.each { |x| foo(x) } # nil
#
# Rails Example
#
class User < ActiveRecord::Base
has_many :campaigns
end
class Guest < NullObject
def campaigns # Expose ActiveRelation methods
Campaign.none
end
end
class CampaignTrafficker
def initialize(user: nil)
@user = user || Guest.new # protect against explicity passing falsy user argument
end
def send_campaigns!
user.campaigns.each { |campaign| campaign.traffic! }
end
private
attr_internal_reader :user
end
CampaignTrafficker.new(user: User.first).send_campaigns! # might do something
CampaignTrafficker.new(user: nil).send_campaigns! # won't do anything do something
#
# Null objects w/ duck typing
#
# No more!
foo && foo.bar
if foo
bar
end
foo.try(:bar).try(:name)
#
# Ditch the IFs Use NullObjects w/ Duck-Typing
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment