Just wanted to share a recent "discovery" of mine. (I'm sure many of you have already discovered this some time ago, but I've found value in list members sharing their discoveries, so I figured I'd try and give something back.)
I'm polishing Copland, getting it ready for RubyConf (and my "Dependency Injection in Ruby" presentation), and I needed some way to make certain operations available during an early stage of an object's lifecycle, but disallowed at a later stage. I was originally thinking of two options:
1) don't do anything about it. Expect undefined behavior if the user tries do to a disallowed operation.
2) use reflection to dynamically remove the methods when they are no longer acceptable.
After some thought, a better solution came to me. Create a submodule of the class called "Fixated". Then, when the object needs to change, call some "fixate" method of the object, which will extend the object with the "Fixated" module. The Fixated module then implements those disallowed methods by simply raising an exception:
class ServicePoint
def add_pending_interceptor( a )
( @pending_interceptors ||= [] ).push a
end
def fixate!
self.extend Fixated
end
def fixated?
false
end
module Fixated
def add_pending_interceptor( *args )
raise NotImplementedException,
"cannot add pending interceptors to fixated object"
end
def fixate!
# does nothing
end
def fixated?
true
end
end
end
svc = ServicePoint.new
svc.add_pending_interceptor( "mock object" )
svc.fixate!
# the next line raises an exception
svc.add_pending_interceptor( "mock object #2" )
Anyway, it works wonderfully for me. Here's where those of you more knowledgable point out a much more efficient way.
- Jamis
···
--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis
"I use octal until I get to 8, and then I switch to decimal."