Skip to content

Commit

Permalink
Merge 6c95561 into 536e47e
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilya Bylich committed May 29, 2013
2 parents 536e47e + 6c95561 commit 81ac13b
Show file tree
Hide file tree
Showing 15 changed files with 460 additions and 405 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
env:
- TRAVIS=true
35 changes: 35 additions & 0 deletions spec/basic_null_object_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'spec_helper'

describe 'basic null object' do
let(:null_class) { Naught.build }
subject(:null) { null_class.new }

it 'responds to arbitrary messages and returns nil' do
expect(null.info).to be_nil
expect(null.foobaz).to be_nil
expect(null.to_s).to be_nil
end

it 'accepts any arguments for any messages' do
null.foobaz(1,2,3)
end

it 'reports that it responds to any message' do
expect(null).to respond_to(:info)
expect(null).to respond_to(:foobaz)
expect(null).to respond_to(:to_s)
end

it 'can be inspected' do
expect(null.inspect).to eq("<null>")
end

it 'knows its own class' do
expect(null.class).to eq(null_class)
end

it 'aliases .new to .get' do
expect(null_class.get.class).to be(null_class)
end

end
16 changes: 16 additions & 0 deletions spec/blackhole_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'spec_helper'

describe 'black hole null object' do
subject(:null) { null_class.new }
let(:null_class) {
Naught.build do |b|
b.black_hole
end
}

it 'returns self from arbitray method calls' do
expect(null.info).to be(null)
expect(null.foobaz).to be(null)
expect(null << "bar").to be(null)
end
end
20 changes: 20 additions & 0 deletions spec/conversions_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'spec_helper.rb'

describe 'explicitly convertable null object' do
let(:null_class) {
Naught.build do |b|
b.define_explicit_conversions
end
}
subject(:null) { null_class.new }

it "defines common explicit conversions to return zero values" do
expect(null.to_s).to eq("")
expect(null.to_a).to eq([])
expect(null.to_i).to eq(0)
expect(null.to_f).to eq(0.0)
expect(null.to_c).to eq(Complex(0))
expect(null.to_r).to eq(Rational(0))
expect(null.to_h).to eq({})
end
end
22 changes: 22 additions & 0 deletions spec/functions/actual_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'spec_helper'

describe 'Actual()' do
include ConvertableNull::Conversions

specify 'given a null object, returns nil' do
null = ConvertableNull.get
expect(Actual(null)).to be_nil
end

specify 'given anything else, returns the input unchanged' do
expect(Actual(false)).to be(false)
str = "hello"
expect(Actual(str)).to be(str)
expect(Actual(nil)).to be_nil
end

it 'also works with blocks' do
expect(Actual{ConvertableNull.new}).to be_nil
expect(Actual{"foo"}).to eq("foo")
end
end
22 changes: 22 additions & 0 deletions spec/functions/just_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'spec_helper'

describe 'Just()' do
include ConvertableNull::Conversions

specify 'passes non-nullish values through' do
expect(Just(false)).to be(false)
str = "hello"
expect(Just(str)).to be(str)
end

specify 'rejects nullish values' do
expect{Just(nil)}.to raise_error(ArgumentError)
expect{Just("")}.to raise_error(ArgumentError)
expect{Just(ConvertableNull.get)}.to raise_error(ArgumentError)
end

it 'also works with blocks' do
expect{Just{nil}.class}.to raise_error(ArgumentError)
expect(Just{"foo"}).to eq("foo")
end
end
35 changes: 35 additions & 0 deletions spec/functions/maybe_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'spec_helper'

describe 'Maybe()' do
include ConvertableNull::Conversions

specify 'given nil, returns a null object' do
expect(Maybe(nil).class).to be(ConvertableNull)
end

specify 'given a null object, returns the same null object' do
null = ConvertableNull.get
expect(Maybe(null)).to be(null)
end

specify 'given anything in null_equivalents, return a null object' do
expect(Maybe("").class).to be(ConvertableNull)
end

specify 'given anything else, returns the input unchanged' do
expect(Maybe(false)).to be(false)
str = "hello"
expect(Maybe(str)).to be(str)
end

it 'generates null objects with useful trace info' do
null = Maybe(); line = __LINE__
expect(null.__line__).to eq(line)
expect(null.__file__).to eq(__FILE__)
end

it 'also works with blocks' do
expect(Maybe{nil}.class).to eq(ConvertableNull)
expect(Maybe{"foo"}).to eq("foo")
end
end
34 changes: 34 additions & 0 deletions spec/functions/null_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require 'spec_helper'

describe 'Null()' do
include ConvertableNull::Conversions

specify 'given no input, returns a null object' do
expect(Null().class).to be(ConvertableNull)
end

specify 'given nil, returns a null object' do
expect(Null(nil).class).to be(ConvertableNull)
end

specify 'given a null object, returns the same null object' do
null = ConvertableNull.get
expect(Null(null)).to be(null)
end

specify 'given anything in null_equivalents, return a null object' do
expect(Null("").class).to be(ConvertableNull)
end

specify 'given anything else, raises an ArgumentError' do
expect{Null(false)}.to raise_error(ArgumentError)
expect{Null("hello")}.to raise_error(ArgumentError)
end

it 'generates null objects with useful trace info' do
null = Null(); line = __LINE__
expect(null.__line__).to eq(line)
expect(null.__file__).to eq(__FILE__)
end

end
22 changes: 22 additions & 0 deletions spec/functions_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'spec_helper'

describe 'Actual()' do
include ConvertableNull::Conversions

specify 'given a null object, returns nil' do
null = ConvertableNull.get
expect(Actual(null)).to be_nil
end

specify 'given anything else, returns the input unchanged' do
expect(Actual(false)).to be(false)
str = "hello"
expect(Actual(str)).to be(str)
expect(Actual(nil)).to be_nil
end

it 'also works with blocks' do
expect(Actual{ConvertableNull.new}).to be_nil
expect(Actual{"foo"}).to eq("foo")
end
end
25 changes: 25 additions & 0 deletions spec/implicit_conversions_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'spec_helper'

describe 'implicitly convertable null object' do
subject(:null) { null_class.new }
let(:null_class) {
Naught.build do |b|
b.define_implicit_conversions
end
}
it 'implicitly splats the same way an empty array does' do
a, b = null
expect(a).to be_nil
expect(b).to be_nil
end
it 'is implicitly convertable to String' do
expect(eval(null)).to be_nil
end
it 'implicitly converts to an empty array' do
expect(null.to_ary).to eq([])
end
it 'implicitly converts to an empty string' do
expect(null.to_str).to eq("")
end

end
110 changes: 110 additions & 0 deletions spec/mimic_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
require 'spec_helper'
require 'logger'

describe 'null object mimicking a class' do
class User
def login
"bob"
end
end

module Authorizable
def authorized_for?(object)
true
end
end

class LibraryPatron < User
include Authorizable

def member?; true; end
def name; "Bob"; end
def notify_of_overdue_books(titles)
puts "Notifying Bob his books are overdue..."
end
end

subject(:null) { mimic_class.new }
let(:mimic_class) {
Naught.build do |b|
b.mimic LibraryPatron
end
}
it 'responds to all methods defined on the target class' do
expect(null.member?).to be_nil
expect(null.name).to be_nil
expect(null.notify_of_overdue_books(['The Grapes of Wrath'])).to be_nil
end

it 'does not respond to methods not defined on the target class' do
expect{null.foobar}.to raise_error(NoMethodError)
end

it 'reports which messages it does and does not respond to' do
expect(null).to respond_to(:member?)
expect(null).to respond_to(:name)
expect(null).to respond_to(:notify_of_overdue_books)
expect(null).not_to respond_to(:foobar)
end
it 'has an informative inspect string' do
expect(null.inspect).to eq("<null:LibraryPatron>")
end

it 'excludes Object methods from being mimicked' do
expect(null.object_id).not_to be_nil
expect(null.hash).not_to be_nil
end

it 'includes inherited methods' do
expect(null.authorized_for?('something')).to be_nil
expect(null.login).to be_nil
end

describe 'with include_super: false' do
let(:mimic_class) {
Naught.build do |b|
b.mimic LibraryPatron, include_super: false
end
}

it 'excludes inherited methods' do
expect(null).to_not respond_to(:authorized_for?)
expect(null).to_not respond_to(:login)
end
end
end

describe 'using mimic with black_hole' do
subject(:null) { mimic_class.new }
let(:mimic_class) {
Naught.build do |b|
b.mimic Logger
b.black_hole
end
}

def self.it_behaves_like_a_black_hole_mimic
it 'returns self from mimicked methods' do
expect(null.info).to equal(null)
expect(null.error).to equal(null)
expect(null << "test").to equal(null)
end

it 'does not respond to methods not defined on the target class' do
expect{null.foobar}.to raise_error(NoMethodError)
end
end

it_behaves_like_a_black_hole_mimic

describe '(reverse order)' do
let(:mimic_class) {
Naught.build do |b|
b.black_hole
b.mimic Logger
end
}

it_behaves_like_a_black_hole_mimic
end
end
Loading

0 comments on commit 81ac13b

Please sign in to comment.