Here’s another library that comes from Lafcadio: ContextualService.
The ContextualService library makes it easy to manage and set services to a single, global resource such as a database or file system. By defining a service to be a child of ContextualService::Service, you
- lock off access to instantiation, so all access have to go through the service’s get method,
- and provide a simple way to set the instance, most likely for testing.
For example, Lafcadio uses ContextualService to manage access to the ObjectStore, which controls access to a database.
class Lafcadio::ObjectStore < ContextualService::Service def initialize ... end end
ObjectStore.new will raise an error. To get an instance of ObjectStore, you call ObjectStore.get_object_store. If no instance has been previously set, this will instantiate the ObjectStore and save the instance for future accesses. If a mock instance has been previously set with set_object_store, it will simply return that mock instance.
Since access to the global service is attached to the class, there’s no need to pass in a mock service as an argument to any method that needs it. This can simplify testing considerably if you’ve got highly decomposed code that needs to access a global service from many places. Also, since the Context object is hidden, clients of the service don’t have to be conscious of it.
def some_method os = Lafcadio::ObjectStore.get_object_store # do something with the object store here some_other_method end def some_other_method os = Lafcadio::ObjectStore.get_object_store # do something with the object store here, too end class TestSomeMethod < Test::Unit::TestCase def test1 mock_object_store = Lafcadio::MockObjectStore.new Lafcadio::ObjectStore.set_object_store mock_object_store some_method # assert something happened end end