Use bit flags for options.

A more idiomatic and efficient way of passing options.
This commit is contained in:
Thayne McCombs 2016-06-26 20:58:15 -06:00
parent ab5e5d1ba1
commit 6255292069
4 changed files with 83 additions and 62 deletions

View file

@ -32,7 +32,7 @@ void main() {
* By using the resolve option "registerBeforeResolving" you can register the resolved class
* immediately. Note that any autowired member will not automatically be registered as well.
*/
auto violinPlayer = dependencies.resolve!Violin([ResolveOption.registerBeforeResolving]);
auto violinPlayer = dependencies.resolve!Violin(ResolveOption.registerBeforeResolving);
/*
* You can make the resolve option persistent by setting it on the container with setPersistentResolveOptions().

View file

@ -140,7 +140,7 @@ private void autowireMember(string member, size_t memberIndex, Type)(shared(Depe
static if (isDynamicArray!MemberType) {
alias MemberElementType = ElementType!MemberType;
static if (isOptional) {
auto instances = container.resolveAll!MemberElementType([ResolveOption.noResolveException]);
auto instances = container.resolveAll!MemberElementType(ResolveOption.noResolveException);
} else {
auto instances = container.resolveAll!MemberElementType;
}
@ -183,7 +183,7 @@ private QualifierType createOrResolveInstance(MemberType, QualifierType, bool cr
return cast(MemberType) instanceFactory.getInstance();
} else {
static if (isOptional) {
return container.resolve!(MemberType, QualifierType)([ResolveOption.noResolveException]);
return container.resolve!(MemberType, QualifierType)(ResolveOption.noResolveException);
} else {
return container.resolve!(MemberType, QualifierType);
}

View file

@ -47,36 +47,38 @@ class RegistrationException : Exception {
* Options which influence the process of registering dependencies
*/
public enum RegistrationOption {
none = 0,
/**
* Prevent a concrete type being registered on itself. With this option you will always need
* to use the supertype as the type of the dependency.
*/
doNotAddConcreteTypeRegistration,
doNotAddConcreteTypeRegistration = 1,
/**
* Prevent a concrete type being registered on itself. With this option you will always need
* to use the supertype as the type of the dependency.
* @deprecated use doNotAddConcreteTypeRegistration instead
*/
DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION
DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION = doNotAddConcreteTypeRegistration
}
/**
* Options which influence the process of resolving dependencies
*/
public enum ResolveOption {
none = 0,
/**
* Registers the type you're trying to resolve before returning it.
* This essentially makes registration optional for resolving by concerete types.
* Resolinvg will still fail when trying to resolve a dependency by supertype.
*/
registerBeforeResolving,
registerBeforeResolving = 1 << 0,
/**
* Does not throw a resolve exception when a type is not registered but will
* return null instead. If the type is an array, an empty array is returned instead.
*/
noResolveException
noResolveException = 1 << 1
}
/**
@ -94,8 +96,8 @@ synchronized class DependencyContainer {
private Registration[] autowireStack;
private RegistrationOption[] persistentRegistrationOptions;
private ResolveOption[] persistentResolveOptions;
private RegistrationOption persistentRegistrationOptions;
private ResolveOption persistentResolveOptions;
/**
* Register a dependency by concrete class type.
@ -117,15 +119,27 @@ synchronized class DependencyContainer {
*
* See_Also: singleInstance, newInstance, existingInstance
*/
public Registration register(ConcreteType)(RegistrationOption[] options = []) {
public Registration register(ConcreteType)(RegistrationOption options = RegistrationOption.none) {
return register!(ConcreteType, ConcreteType)(options);
}
/**
* Deprecated: Use register(SuperType, ConcreteType)(RegistrationOption[]) instead
* Deprecated: Use register(ConcreteType)(RegistrationOptions) instead.
*/
public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption[] options...) {
return register!(SuperType, ConcreteType)(options);
deprecated public Registration register(ConcreteType)(RegistrationOption[] options) {
return register!(ConcreteType)(buildFlags(options));
}
/**
* Deprecated: Use register(SuperType, ConcreteType)(RegistrationOptions) instead
*/
deprecated public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption first, RegistrationOption[] options...) {
return register!(SuperType, ConcreteType)(first | buildFlags(options));
}
/// ditto
deprecated public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption[] options) {
return register!(SuperType, ConcreteType)(buildFlags(options));
}
/**
@ -145,7 +159,7 @@ synchronized class DependencyContainer {
*
* See_Also: singleInstance, newInstance, existingInstance, RegistrationOption
*/
public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption[] options = []) {
public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption options = RegistrationOption.none) {
TypeInfo registeredType = typeid(SuperType);
TypeInfo_Class concreteType = typeid(ConcreteType);
@ -172,34 +186,16 @@ synchronized class DependencyContainer {
return newRegistration;
}
private bool hasOption(OptionType)(OptionType[] options, shared(OptionType[]) persistentOptions, OptionType option) {
foreach (presentOption; persistentOptions) {
static if (is(OptionType == RegistrationOption)) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
}
}
private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) {
return ((options | persistentOptions) & option) != 0;
}
if (presentOption == option) {
return true;
}
private OptionType buildFlags(OptionType)(OptionType[] options) {
OptionType flags;
foreach (option; options) {
flags |= option;
}
foreach(presentOption ; options) {
static if (is(OptionType == RegistrationOption)) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
}
}
if (presentOption == option) {
return true;
}
}
return false;
return flags;
}
private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) {
@ -260,10 +256,24 @@ synchronized class DependencyContainer {
* ---
* You need to use the resolve method which allows you to specify a qualifier.
*/
public RegistrationType resolve(RegistrationType)(ResolveOption[] resolveOptions = []) {
public RegistrationType resolve(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) {
return resolve!(RegistrationType, RegistrationType)(resolveOptions);
}
/**
* Deprecated: Use register(RegistrationType)(ResolveOption) instead.
*/
deprecated public RegistrationType resolve(RegistrationType)(ResolveOption[] resolveOptions) {
return resolve!(RegistrationType)(buildFlags(resolveOptions));
}
/**
* Deprecated: Use register(RegistrationType, QualifierType)(ResolveOption) instead.
*/
deprecated public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption[] resolveOptions) {
return resolve!(RegistrationType, QualifierType)(buildFlags(resolveOptions));
}
/**
* Resolve dependencies using a qualifier.
*
@ -290,7 +300,7 @@ synchronized class DependencyContainer {
* container.resolve!(Animal, Dog);
* ---
*/
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption[] resolveOptions = []) {
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) {
TypeInfo resolveType = typeid(RegistrationType);
TypeInfo qualifierType = typeid(QualifierType);
@ -348,7 +358,7 @@ synchronized class DependencyContainer {
* Animal[] animals = container.resolveAll!Animal;
* ---
*/
public RegistrationType[] resolveAll(RegistrationType)(ResolveOption[] resolveOptions = []) {
public RegistrationType[] resolveAll(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) {
RegistrationType[] instances;
TypeInfo resolveType = typeid(RegistrationType);
@ -368,6 +378,13 @@ synchronized class DependencyContainer {
return instances;
}
/**
* Deprecated: Use resolveAll(RegistrationType)(ResolveOptions) instead.
*/
deprecated public RegistrationType[] resolveAll(RegistrationType)(ResolveOption[] resolveOptions) {
return resolveAll!RegistrationType(buildFlags(resolveOptions));
}
private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) {
if (resolveType == qualifierType) {
if (candidates.length > 1) {
@ -431,35 +448,39 @@ synchronized class DependencyContainer {
/**
* Apply persistent registration options which will be used everytime register() is called.
*/
public void setPersistentRegistrationOptions(OptionsTuple...)(OptionsTuple registrationOptions) {
unsetPersistentRegistrationOptions();
foreach (option; registrationOptions) {
persistentRegistrationOptions ~= option;
}
public void setPersistentRegistrationOptions(RegistrationOption[] registrationOptions...) {
persistentRegistrationOptions = buildFlags(registrationOptions);
}
/// ditto
public void setPersistentRegistrationOptions(RegistrationOption options) {
persistentRegistrationOptions = options;
}
/**
* Unsets all applied registration options
*/
public void unsetPersistentRegistrationOptions() {
persistentRegistrationOptions = [];
persistentRegistrationOptions = RegistrationOption.none;
}
/**
* Apply persistent resolve options which will be used everytime resolve() is called.
*/
public void setPersistentResolveOptions(OptionsTuple...)(OptionsTuple resolveOptions) {
unsetPersistentResolveOptions();
foreach (option; resolveOptions) {
persistentResolveOptions ~= option;
}
public void setPersistentResolveOptions(ResolveOption[] resolveOptions...) {
persistentResolveOptions = buildFlags(resolveOptions);
}
/// ditto
public void setPersistentResolveOptions(ResolveOption options) {
persistentResolveOptions = options;
}
/**
* Unsets all applied registration options
*/
public void unsetPersistentResolveOptions() {
persistentResolveOptions = [];
persistentResolveOptions = ResolveOption.none;
}
}

View file

@ -497,7 +497,7 @@ version(unittest) {
// Test registering type with option doNotAddConcreteTypeRegistration
unittest {
shared(DependencyContainer) container = new DependencyContainer();
container.register!(TestInterface, TestClass)([RegistrationOption.doNotAddConcreteTypeRegistration]);
container.register!(TestInterface, TestClass)(RegistrationOption.doNotAddConcreteTypeRegistration);
auto firstInstance = container.resolve!TestInterface;
assertThrown!ResolveException(container.resolve!TestClass);
@ -506,7 +506,7 @@ version(unittest) {
// Test registering type with option DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION (DEPRECATED)
unittest {
shared(DependencyContainer) container = new DependencyContainer();
container.register!(TestInterface, TestClass)([RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION]);
container.register!(TestInterface, TestClass)(RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION);
auto firstInstance = container.resolve!TestInterface;
assertThrown!ResolveException(container.resolve!TestClass);
@ -515,7 +515,7 @@ version(unittest) {
// Test registering conrete type with registration option doNotAddConcreteTypeRegistration does nothing
unittest {
shared(DependencyContainer) container = new DependencyContainer();
container.register!TestClass([RegistrationOption.doNotAddConcreteTypeRegistration]);
container.register!TestClass(RegistrationOption.doNotAddConcreteTypeRegistration);
container.resolve!TestClass;
}
@ -631,7 +631,7 @@ version(unittest) {
// Test registration when resolving
unittest {
shared(DependencyContainer) container = new DependencyContainer();
container.resolve!(TestInterface, TestClass)([ResolveOption.registerBeforeResolving]);
container.resolve!(TestInterface, TestClass)(ResolveOption.registerBeforeResolving);
container.resolve!TestClass;
}
@ -653,20 +653,20 @@ version(unittest) {
// Test ResolveOption registerBeforeResolving fails for interfaces
unittest {
shared(DependencyContainer) container = new DependencyContainer();
assertThrown!ResolveException(container.resolve!TestInterface([ResolveOption.registerBeforeResolving]));
assertThrown!ResolveException(container.resolve!TestInterface(ResolveOption.registerBeforeResolving));
}
// Test ResolveOption noResolveException does not throw
unittest {
shared(DependencyContainer) container = new DependencyContainer();
auto instance = container.resolve!TestInterface([ResolveOption.noResolveException]);
auto instance = container.resolve!TestInterface(ResolveOption.noResolveException);
assert(instance is null);
}
// ResolveOption noResolveException does not throw for resolveAll
unittest {
shared(DependencyContainer) container = new DependencyContainer();
auto instances = container.resolveAll!TestInterface([ResolveOption.noResolveException]);
auto instances = container.resolveAll!TestInterface(ResolveOption.noResolveException);
assert(instances.length == 0);
}
}