diff --git a/lib/rackstash.rb b/lib/rackstash.rb index 28987c2..6710488 100644 --- a/lib/rackstash.rb +++ b/lib/rackstash.rb @@ -37,6 +37,29 @@ module Rackstash PROGNAME = "rackstash/v#{Rackstash::VERSION}".freeze + # A class for the {UNDEFINED} object. Generally, there will only be exactly + # one object of this class. + # + # The {UNDEFINED} object can be used as the default value for method arguments + # to distinguish it from `nil`. See https://holgerjust.de/2016/detecting-default-arguments-in-ruby/#special-default-value + # for details. + class UndefinedClass + # @return [Boolean] `true` iff `other` is the exact same object as `self` + def ==(other) + self.equal?(other) + end + alias === == + alias eql? == + + # @return [String] the string `"undefined"` + def to_s + 'undefined'.freeze + end + alias inspect to_s + end + + UNDEFINED = UndefinedClass.new + EMPTY_STRING = ''.freeze EMPTY_SET = Set.new.freeze diff --git a/spec/rackstash_spec.rb b/spec/rackstash_spec.rb index 81cd85f..739f003 100644 --- a/spec/rackstash_spec.rb +++ b/spec/rackstash_spec.rb @@ -41,4 +41,16 @@ describe Rackstash do expect(Rackstash.const_get(name)).to be_frozen end end + + it 'defines UNDEFINED' do + expect(Rackstash::UNDEFINED).to be_instance_of Rackstash::UndefinedClass + expect(Rackstash::UNDEFINED.to_s).to eql 'undefined' + + expect(Rackstash::UNDEFINED).to equal Rackstash::UNDEFINED + + expect(Rackstash::UNDEFINED).not_to eql nil + expect(Rackstash::UNDEFINED).not_to eql false + expect(Rackstash::UNDEFINED).not_to eql true + expect(Rackstash::UNDEFINED).not_to eql 42 + end end