Why would that be a chore I hear you ask?
Because the singleton in question had several configuration options.
Most of which were file based.
So out of the ~60 specs, 50 of them were for error conditions.
(File missing, folder not readable, not JSON, JSON but with invalid stanzas etc)
The problem was that each test had to start with a clean slate.
The singleton class must be pristine and new each run.
How the hell do you do that?
Unload the class, then reload it.
I fiddled about quite a bit with this, so I've put together a simple project that illustrates how this is done.
The bottom line is that you have to send :remove_const and the class name to the module or whatever your class is defined in.
For example, say a class is defined in a file skavee_bloopsie.rb thus:
module Skavee class Bloopsie end end
Then this is what you run to unload and reload it:
Skavee.send(:remove_const, :Bloopsie)
This works at any depth of modules:
module A
module B
module C
class Z
def ohai
'ohai!'
end
end
end
end
end
A::B::C.send(:remove_const, :Z)
You can test this yourself by copying and pasting this into irb:
module A
module B
module C
class Z
def ohai
'ohai!'
end
end
end
end
end
a = A::B::C::Z.new
=> #<A::B::C::Z:0x007fc78c9b1dc8>
puts a.ohai
=> "ohai!"
A::B::C.send(:remove_const, :Z)
=> A::B::C::Z
b = A::B::C::Z.new
=> NameError: uninitialized constant A::B::C::Z
And here's the Gotcha!
a.ohai
=> "ohai!"
Wha? Well it's obvious. The instance is still being referenced.
So be careful out there people.
An example gem is available via my repo at https://github.com/ZenGirl/ruby-class-unloading
No comments:
Post a Comment