Skip to content

Instantly share code, notes, and snippets.

@jwilger
Last active June 20, 2016 18:04
Show Gist options
  • Save jwilger/23f7e37135ba4162fd1a813bcb98ca96 to your computer and use it in GitHub Desktop.
Save jwilger/23f7e37135ba4162fd1a813bcb98ca96 to your computer and use it in GitHub Desktop.
PseudoSingleton
require 'delegate'
require 'forwardable'
module PseudoSingleton
def instance
@instance ||= new
end
private
attr_accessor :instance_delegator
def self.extended(other)
other.extend(SingleForwardable)
other.send(:instance_delegator=, SimpleDelegator.new(other.instance))
other.def_delegator :instance_delegator, :method_missing
end
end
require 'pseudo_singleton'
RSpec.describe PseudoSingleton do
let(:described_class) do
Class.new do
extend PseudoSingleton
def foo
:bar
end
end
end
subject { described_class }
describe '.instance' do
it 'returns an instance of the class' do
expect(subject.instance).to be_kind_of described_class
end
it 'always returns the *same* instance of the class' do
expect(subject.instance).to be subject.instance
end
end
describe 'forwarding of class methods to the instance' do
it 'delegates any methods called on the class but not defined on the class to the instance' do
expect(subject.foo).to eq :bar
end
end
end
@jwilger
Copy link
Author

jwilger commented Jun 20, 2016

I suppose the other option would be to forget about using a shared module and just change it so that classes that would extend PseudoSingleton instead become self-extending modules and then, for testing purposes (where you don't want to test the singleton version) you just define your subject as subject { Object.new.extend(described_class) }.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment