Skip to content

Instantly share code, notes, and snippets.

@eoinkelly
Forked from ootoovak/Problem.rb
Last active December 18, 2015 16:29
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 eoinkelly/5811944 to your computer and use it in GitHub Desktop.
Save eoinkelly/5811944 to your computer and use it in GitHub Desktop.
require 'rspec'
# This class can be initialised with one of
# * a hash
# * another instance of the object
# and it will have the same result
class Thing
attr_accessor :name
attr_accessor :description
def initialize(args = {})
@name = args.fetch(:name, '')
@description = args.fetch(:description, '')
end
def fetch(key, default_value)
send(key) || default_value
end
# This is required for == to determine that both objects are equal
def ==(o)
(name == o.name) && (description == o.description)
end
end
describe Thing do
let(:hash) { { name: 'Duck Type', description: 'Quacks like a duck?' } }
it "can be initialised with an instance of Hash representing the attributes" do
a = Thing.new(hash)
expect(a.name).to eq(hash[:name])
expect(a.description).to eq(hash[:description])
end
it "can be initialised with another instance of Thing" do
a = Thing.new(hash)
b = Thing.new(a)
expect(b.name).to eq(hash[:name])
expect(b.description).to eq(hash[:description])
end
it 'the created instance should be the same whether we initialise with Hash instance or Thing instance' do
a = Thing.new(hash)
b = Thing.new(a)
expect(a.name).to eq(b.name)
expect(a.description).to eq(b.description)
expect(a).to eq(b)
end
end
class MemoizedThing
@@instances = {}
attr_accessor :thing
def initialize(thing)
new = Thing.new(thing)
key = [new.name, new.description]
old = @@instances[key]
if old
@thing = old
else
@thing = new
@@instances[key] = new
end
end
end
describe MemoizedThing do
let(:hash) { { name: 'Duck Type', description: 'Quacks like a duck?' } }
it "re-uses old instances of thing if any are available" do
a = MemoizedThing.new(hash)
b = MemoizedThing.new(hash)
expect(a.thing).to equal(b.thing)
end
it "creates a new instance of thing if an old one cannot be found" do
a = MemoizedThing.new(hash)
expect(a.thing).to be_instance_of(Thing)
end
it "connects together instances of Thing in potentially bad/hilarious ways" do
peacenik = MemoizedThing.new(hash)
warmonger = MemoizedThing.new(hash)
peacenik.thing.name = "Make love not war"
warmonger.thing.name = "Kill 'em all"
expect(peacenik.thing.name).to eq("Kill 'em all") # Hmmm ...
end
end
# Want to pass in a hash or instance of object. Was hoping to avoid is_a? or creating a new object but
# think that can only be done with is_a? or overriding new. Also, I might be missing the point as
# avoiding is_a? should mean I am using Duck Typing but if I'm using Duck Typing then I shouldn't be
# checking object equality anyway. See RSpec test for details.
class MyClass
attr_accessor :name
attr_accessor :description
def initialize(args = {})
@name = args[:name]
@description = args[:description]
end
end
describe MyClass do
let(:hash) { { name: 'Duck Type', description: 'Quacks like a duck?' } }
before do
@my_instance_1 = MyClass.new(hash)
@my_instance_2 = MyClass.new(@my_instance_1)
end
it 'this is preferable' do
@my_instance_1.should equal(@my_instance_2)
end
it 'this is ok' do
@my_instance_1.should eq(@my_instance_2)
end
end
# Possilbe solutions involve overriding MyClass.new or buidling a constructor
# http://stackoverflow.com/questions/4888786/how-can-i-change-the-return-value-of-a-class-constructor-in-ruby
# Good old Rubber Duck Debugging
# Will only pass 1 of 2 tests
class MyClass
attr_accessor :name
attr_accessor :description
def initialize(args = {})
@name = args.fetch(:name, '')
@description = args.fetch(:description, '')
end
def fetch(key, default_value)
send(key) || default_value
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment