Nothing and Ducks
Let's talk about nothing
Types of Nothing in Code
Numbers
0.0 / 0.0 # => NaN
Strings
""
Collections
[]
{}
Objects
nil
Let's talk about ducks
NaN is a Duck
def math_it_up!(number)
number * 100 / 10 + 5 - 3
end
math_it_up!(2) # => 22
math_it_up!(0.0/0.0) # => NaN
"" is a Duck
def string_it_up!(string)
string.upcase.capitalize
end
string_it_up!("ducks") # => "Ducks"
string_it_up!("") # => ""
[] and {} are Ducks
def array_it_up!(array)
array.map(&:to_s)
end
array_it_up!([1, 2]) # => ["1", "2"]
array_it_up!([]) # => []
def hash_it_up!(hash)
hash.group_by(&:last).map{|num, pairs| [num, pairs.map(&:first)]}
end
hash_it_up!(:one => 1, :uno => 1, :dos => 2, :two => 2)
# => [[1, [:uno, :one]], [2, [:dos, :two]]]
hash_it_up!({}) # => []
nil is a Goose
class Report def initialize(data) @data = data end
def generate @data.each do |row| puts row end
@generated = true end end report = Report.new([1, 3, 6]) report.generate nil.generate # => NoMethodError: undefined method `generate' for nil:NilClass
Overcoming Object Nothingness
The Null Object Pattern
Real World Example
Before
module Emails
class EmailDirector
class << self
def get_email_for(email_type)
"Emails::EmailTypes::#{email_type.classify}".constantize.new
rescue NameError
nil
end
end
end
end
Real World Example
Before
class MessageDispatcher
class << self
def method_missing(method, *args)
email = EmailDirector.get_email_for(method, *args)
if email && email.use_exact_target?
email.push_email_message_to_bus
else
CustomerNotifier.send(method, *args)
end
end
end
end
Real World Example
class Emails::EmailTypes::Base
def initialize(*args); raise "Me wants initialization"; end
def use_exact_target?; raise "Me wants definition"; end
def push_email_message_to_bus
xml = build_message
push_message_to_bus(xml)
end
private
def build_message; raise "Me wants definition"; end
def push_message_to_bus(xml)
ESB::MessageBridge.transaction do
ESB::MessageBridge.push(xml, :mail_message)
end
end
end
Real World Example
After
module Emails
module EmailTypes
class NilType < Emails::EmailTypes::Base
def initialize(*args)
end
def use_exact_target?
false
end
private
def build_message
end
end
end
end
Real World Example
After
module Emails
class EmailDirector
class << self
def get_email_for(email_type, *args)
"Emails::EmailTypes::#{email_type.camelize}".constantize.new(*args)
rescue NameError
Emails::EmailTypes::NilType.new
end
end
end
end
Real World Example
After
class MessageDispatcher
class << self
def method_missing(method, *args)
email = EmailDirector.get_email_for(method, *args)
if email.use_exact_target?
email.push_email_message_to_bus
else
CustomerNotifier.send(method, *args)
end
end
end
end
Generalizing the Null Object Pattern
Query methods are hard
Generalizing the Null Object Pattern
"Tell, don't ask" makes it easy
Generalizing the Null Object Pattern
class NullObject
def initialize(*args)
end
def method_missing(*args)
end
end
object = NullObject.new
object.do_important_stuff!
Questions?
nothing and ducks
By blatyo
nothing and ducks
- 803