A library of utility services and concerns.
SleepingKingStudios::Tools defines the Initializer utility class for initializing a library or project and its dependencies.
An initializer is used to set up the project, including loading configuration, setting initial data or states, and initializing dependencies.
Using an initializer provides several advantages:
The class reference for SleepingKingStudios::Tools::Toolbox::Initializer can be found in Reference.
In order to ensure the initializer runs only once, it must be defined statically when the library or project is defined.
module Space
@initializer = SleepingKingStudios::Tools::Toolbox::Initializer.new do
# Initialize the project's dependencies.
Planets.initializer.call
# Set up the project environment.
Space.load_configuration
Space.launch_sites = %w[KSC]
# Load human-readable message definitions for the project namespace.
SleepingKingStudios::Tools.initializer.call
SleepingKingStudios::Tools::Messages::Registry
.global
.register(file: 'config/messages.yml' scope: 'space')
end
def self.initializer = @initializer
end
First, we define the initializer itself as an instance variable in the Module definition (which sets @initializer an instance variable on the singleton class). This ensures that the initializer is defined when the code is first loaded.
The Initializer.new method takes a block, which is run when the initializer is called for the first time. In our initializer, we’re doing a different things:
Planets.initializer.call. This ensures that whatever setup the Planets module needs is completed before setting up Space.Space.load_configuration and do some manual data setup on Space.launch_sites.SleepingKingStudios::Tools itself is initialized, and register a message strategy for messages with the space namespace, matching our library name. See Messages for more details.Next, we define a class method that returns the initializer. This allows our initializer to be called from outside of our module.
Important Note: Do not define the @initializer inside the method - this will allow the initializer to be called multiple times in a multi-threaded application. Always define the initializer in the Module body, then define the method to access it.
Once the initializer is defined, update the entry point for your project to call the initializer.
Projects that rely on a library with an initializer should call that initializer, ideally in an initializer of their own. For example, imagine that the Space::Game project relies on the Space::Orbits and Space::Rockets libraries, each of which relies on Space::Physics. In that example:
Space::Game should call the initializer for Space::Orbits and Space::Rockets.Space::Orbits should call the initializer for Space::Physics.Space::Rockets should also call the initializer for Space::Physics.Even if multiple libraries call the same initializer, the code will run only once - in the above example, the initializer for Space::Physics will only run once, even though multiple libraries rely on it. This allows each library to safely manage its own dependencies.
You can also call the initializer directly. In a script:
# bin/launch
require 'space'
Space.initializer.call
Space.launch_rocket(ARGV[0])
In your test suite:
# spec/spec_helper.rb
require 'space'
Space.initializer.call
RSpec.configure do
# Test configuration here.
end
Back to Documentation