From: <fli...@us...> - 2010-01-30 19:14:06
|
Revision: 326 http://structuremap.svn.sourceforge.net/structuremap/?rev=326&view=rev Author: flimflan Date: 2010-01-30 19:13:59 +0000 (Sat, 30 Jan 2010) Log Message: ----------- When wiring up the built-in registration conventions, can now call OnAddedPluginTypes() to configure options (scope, enrichment, etc) for discovered plugin types - pulled registration of built-in conventions off IAssemblyScanner and moved to AssemblyScannerExtensions Modified Paths: -------------- trunk/Source/StructureMap/Graph/AssemblyScanner.cs trunk/Source/StructureMap/Graph/FirstInterfaceConvention.cs trunk/Source/StructureMap/Graph/IAssemblyScanner.cs trunk/Source/StructureMap/Graph/ITypeScanner.cs trunk/Source/StructureMap/Graph/ImplementationMap.cs trunk/Source/StructureMap/StructureMap.csproj trunk/Source/StructureMap.Testing/Graph/DefaultConventionScanningTester.cs trunk/Source/StructureMap.Testing/Graph/SingleImplementationScannerTester.cs trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj Added Paths: ----------- trunk/Source/StructureMap/AssemblyScannerExtensions.cs trunk/Source/StructureMap/Configuration/DSL/Expressions/ConfigureConventionExpression.cs trunk/Source/StructureMap/Graph/IRegistrationConvention.cs trunk/Source/StructureMap.Testing/Graph/GenericConnectionScannerTester.cs Added: trunk/Source/StructureMap/AssemblyScannerExtensions.cs =================================================================== --- trunk/Source/StructureMap/AssemblyScannerExtensions.cs (rev 0) +++ trunk/Source/StructureMap/AssemblyScannerExtensions.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -0,0 +1,63 @@ +using System; +using StructureMap.Configuration.DSL.Expressions; +using StructureMap.Graph; + +namespace StructureMap +{ + /// <summary> + /// Extend the assembly scanning DSL to support the built-in registration conventions + /// </summary> + public static class AssemblyScannerExtensions + { + /// <summary> + /// Adds the DefaultConventionScanner to the scanning operations. I.e., a concrete + /// class named "Something" that implements "ISomething" will be automatically + /// added to PluginType "ISomething" + /// </summary> + public static ConfigureConventionExpression WithDefaultConventions(this IAssemblyScanner assemblyScanner) + { + var convention = new DefaultConventionScanner(); + assemblyScanner.With(convention); + return new ConfigureConventionExpression(convention); + } + + /// <summary> + /// Scans for PluginType's and Concrete Types that close the given open generic type + /// </summary> + /// <example> + /// + /// </example> + /// <param name="openGenericType"></param> + public static ConfigureConventionExpression ConnectImplementationsToTypesClosing(this IAssemblyScanner assemblyScanner, Type openGenericType) + { + var convention = new GenericConnectionScanner(openGenericType); + assemblyScanner.With(convention); + return new ConfigureConventionExpression(convention); + } + + /// <summary> + /// Automatically registers all concrete types without primitive arguments + /// against its first interface, if any + /// </summary> + public static ConfigureConventionExpression RegisterConcreteTypesAgainstTheFirstInterface(this IAssemblyScanner assemblyScanner) + { + var convention = new FirstInterfaceConvention(); + assemblyScanner.With(convention); + return new ConfigureConventionExpression(convention); + } + + /// <summary> + /// Directs the scanning to automatically register any type that is the single + /// implementation of an interface against that interface. + /// The filters apply + /// </summary> + public static ConfigureConventionExpression SingleImplementationsOfInterface(this IAssemblyScanner assemblyScanner) + { + var convention = new ImplementationMap(); + assemblyScanner.With(convention); + assemblyScanner.ModifyGraphAfterScan(convention.RegisterSingleImplementations); + return new ConfigureConventionExpression(convention); + } + + } +} \ No newline at end of file Added: trunk/Source/StructureMap/Configuration/DSL/Expressions/ConfigureConventionExpression.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Expressions/ConfigureConventionExpression.cs (rev 0) +++ trunk/Source/StructureMap/Configuration/DSL/Expressions/ConfigureConventionExpression.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -0,0 +1,21 @@ +using System; +using StructureMap.Graph; + +namespace StructureMap.Configuration.DSL.Expressions +{ + public class ConfigureConventionExpression + { + private readonly ConfigurableRegistrationConvention _convention; + + internal ConfigureConventionExpression(ConfigurableRegistrationConvention convention) + { + _convention = convention; + } + + public ConfigureConventionExpression OnAddedPluginTypes(Action<GenericFamilyExpression> configurePluginType) + { + _convention.SetFamilyConfigurationAction(configurePluginType); + return this; + } + } +} \ No newline at end of file Modified: trunk/Source/StructureMap/Graph/AssemblyScanner.cs =================================================================== --- trunk/Source/StructureMap/Graph/AssemblyScanner.cs 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap/Graph/AssemblyScanner.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -42,7 +42,6 @@ private readonly List<Assembly> _assemblies = new List<Assembly>(); private readonly List<IRegistrationConvention> _conventions = new List<IRegistrationConvention>(); private readonly CompositeFilter<Type> _filter = new CompositeFilter<Type>(); - private readonly ImplementationMap _implementationMap = new ImplementationMap(); private readonly List<Action<PluginGraph>> _postScanningActions = new List<Action<PluginGraph>>(); private readonly List<ITypeScanner> _scanners = new List<ITypeScanner>(); @@ -75,16 +74,6 @@ _scanners.Fill(scanner); } - public void WithDefaultConventions() - { - Convention<DefaultConventionScanner>(); - } - - public void RegisterConcreteTypesAgainstTheFirstInterface() - { - Convention<FirstInterfaceConvention>(); - } - [Obsolete("Replace ITypeScanner with IRegistrationConvention")] public void With<T>() where T : ITypeScanner, new() { @@ -186,18 +175,11 @@ Exclude(type => type == typeof (T)); } - public void ConnectImplementationsToTypesClosing(Type openGenericType) + public void ModifyGraphAfterScan(Action<PluginGraph> modifyGraph) { - With(new GenericConnectionScanner(openGenericType)); + _postScanningActions.Add(modifyGraph); } - - public void SingleImplementationsOfInterface() - { - _conventions.Fill(_implementationMap); - _postScanningActions.Add(graph => _implementationMap.RegisterSingleImplementations(graph)); - } - public void AssembliesFromApplicationBaseDirectory() { AssembliesFromApplicationBaseDirectory(a => true); Modified: trunk/Source/StructureMap/Graph/FirstInterfaceConvention.cs =================================================================== --- trunk/Source/StructureMap/Graph/FirstInterfaceConvention.cs 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap/Graph/FirstInterfaceConvention.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -6,9 +6,9 @@ namespace StructureMap.Graph { - public class FirstInterfaceConvention : IRegistrationConvention + public class FirstInterfaceConvention : ConfigurableRegistrationConvention { - public void Process(Type type, Registry registry) + public override void Process(Type type, Registry registry) { if (!type.IsConcrete() || !type.CanBeCreated()) return; @@ -18,6 +18,7 @@ { Debug.WriteLine("Plugging {0} into {1}".ToFormat(type.Name, interfaceType.Name)); registry.AddType(interfaceType, type); + ConfigureFamily(registry.For(interfaceType)); } } } Modified: trunk/Source/StructureMap/Graph/IAssemblyScanner.cs =================================================================== --- trunk/Source/StructureMap/Graph/IAssemblyScanner.cs 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap/Graph/IAssemblyScanner.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -1,5 +1,6 @@ using System; using System.Reflection; +using StructureMap.Configuration.DSL.Expressions; namespace StructureMap.Graph { @@ -76,20 +77,6 @@ void With(ITypeScanner scanner); /// <summary> - /// Adds the DefaultConventionScanner to the scanning operations. I.e., a concrete - /// class named "Something" that implements "ISomething" will be automatically - /// added to PluginType "ISomething" - /// </summary> - void WithDefaultConventions(); - - /// <summary> - /// Automatically registers all concrete types without primitive arguments - /// against its first interface, if any - /// </summary> - void RegisterConcreteTypesAgainstTheFirstInterface(); - - - /// <summary> /// Creates and adds a new ITypeScanner of type T to this scanning operation /// </summary> /// <typeparam name="T"></typeparam> @@ -178,22 +165,6 @@ // ... Other methods /// <summary> - /// Scans for PluginType's and Concrete Types that close the given open generic type - /// </summary> - /// <example> - /// - /// </example> - /// <param name="openGenericType"></param> - void ConnectImplementationsToTypesClosing(Type openGenericType); - - /// <summary> - /// Directs the scanning to automatically register any type that is the single - /// implementation of an interface against that interface. - /// The filters apply - /// </summary> - void SingleImplementationsOfInterface(); - - /// <summary> /// Adds a registration convention to be applied to all the types in this /// logical "scan" operation /// </summary> @@ -205,5 +176,7 @@ /// logical "scan" operation /// </summary> void With(IRegistrationConvention convention); + + void ModifyGraphAfterScan(Action<PluginGraph> modifyGraph); } } \ No newline at end of file Added: trunk/Source/StructureMap/Graph/IRegistrationConvention.cs =================================================================== --- trunk/Source/StructureMap/Graph/IRegistrationConvention.cs (rev 0) +++ trunk/Source/StructureMap/Graph/IRegistrationConvention.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -0,0 +1,31 @@ +using System; +using StructureMap.Configuration.DSL; +using StructureMap.Configuration.DSL.Expressions; + +namespace StructureMap.Graph +{ + public interface IRegistrationConvention + { + void Process(Type type, Registry registry); + } + + /// <summary> + /// Allows built-in registration conventions to be configurable through the assembly scanning DSL + /// </summary> + /// <remarks> + /// Intended for StructureMap internal use only. + /// Custom registration convention instances can be directly configured + /// before being passed to IAssemblyScanner.With(IRegistrationConvention). + /// </remarks> + public abstract class ConfigurableRegistrationConvention : IRegistrationConvention + { + protected Action<GenericFamilyExpression> ConfigureFamily = x => { }; + + public void SetFamilyConfigurationAction(Action<GenericFamilyExpression> configureFamily) + { + ConfigureFamily = configureFamily; + } + + public abstract void Process(Type type, Registry registry); + } +} \ No newline at end of file Modified: trunk/Source/StructureMap/Graph/ITypeScanner.cs =================================================================== --- trunk/Source/StructureMap/Graph/ITypeScanner.cs 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap/Graph/ITypeScanner.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -10,14 +10,9 @@ void Process(Type type, PluginGraph graph); } - public interface IRegistrationConvention + public class DefaultConventionScanner : ConfigurableRegistrationConvention { - void Process(Type type, Registry registry); - } - - public class DefaultConventionScanner : IRegistrationConvention - { - public void Process(Type type, Registry registry) + public override void Process(Type type, Registry registry) { if (!type.IsConcrete()) return; @@ -25,6 +20,7 @@ if (pluginType != null && Constructor.HasConstructors(type)) { registry.AddType(pluginType, type); + ConfigureFamily(registry.For(pluginType)); } } @@ -36,7 +32,7 @@ } } - public class GenericConnectionScanner : IRegistrationConvention + public class GenericConnectionScanner : ConfigurableRegistrationConvention { private readonly Type _openType; @@ -50,12 +46,14 @@ } } - public void Process(Type type, Registry registry) + public override void Process(Type type, Registry registry) { Type interfaceType = type.FindInterfaceThatCloses(_openType); if (interfaceType != null) { - registry.For(interfaceType).Add(type); + var family = registry.For(interfaceType); + ConfigureFamily(family); + family.Add(type); } } } Modified: trunk/Source/StructureMap/Graph/ImplementationMap.cs =================================================================== --- trunk/Source/StructureMap/Graph/ImplementationMap.cs 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap/Graph/ImplementationMap.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -7,11 +7,11 @@ namespace StructureMap.Graph { - public class ImplementationMap : IRegistrationConvention + public class ImplementationMap : ConfigurableRegistrationConvention { private readonly Cache<Type, List<Type>> _types = new Cache<Type, List<Type>>(t => new List<Type>()); - public void Process(Type type, Registry registry) + public override void Process(Type type, Registry registry) { RegisterType(type); } @@ -30,13 +30,22 @@ public void RegisterSingleImplementations(PluginGraph graph) { + var singleImplementationRegistry = new SingleImplementationRegistry(); _types.Each((pluginType, types) => { if (types.Count == 1) { - graph.AddType(pluginType, types[0]); + singleImplementationRegistry.AddType(pluginType, types[0]); + ConfigureFamily(singleImplementationRegistry.For(pluginType)); } }); + singleImplementationRegistry.ConfigurePluginGraph(graph); } } + + internal class SingleImplementationRegistry : Registry + { + // This type created just to make the output clearer in WhatDoIHave() + // might consider adding a Description property to Registry instead + } } \ No newline at end of file Modified: trunk/Source/StructureMap/StructureMap.csproj =================================================================== --- trunk/Source/StructureMap/StructureMap.csproj 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap/StructureMap.csproj 2010-01-30 19:13:59 UTC (rev 326) @@ -336,6 +336,7 @@ <Compile Include="CloseGenericTypeExpression.cs" /> <Compile Include="ConfigurationExpression.cs" /> <Compile Include="Configuration\DictionaryReader.cs" /> + <Compile Include="AssemblyScannerExtensions.cs" /> <Compile Include="Configuration\DSL\Expressions\InstanceExpression.cs" /> <Compile Include="Configuration\DSL\IRegistry.cs" /> <Compile Include="Configuration\DSL\SetterConvention.cs" /> @@ -358,12 +359,14 @@ <Compile Include="Extensions.cs" /> <Compile Include="Graph\CompositeFilter.cs" /> <Compile Include="Graph\CompositePredicate.cs" /> + <Compile Include="Configuration\DSL\Expressions\ConfigureConventionExpression.cs" /> <Compile Include="Graph\FamilyAttributeScanner.cs" /> <Compile Include="Graph\FindAllTypesFilter.cs" /> <Compile Include="Graph\FindRegistriesScanner.cs" /> <Compile Include="Graph\FirstInterfaceConvention.cs" /> <Compile Include="Graph\IAssemblyScanner.cs" /> <Compile Include="Graph\ImplementationMap.cs" /> + <Compile Include="Graph\IRegistrationConvention.cs" /> <Compile Include="Graph\ITypeScanner.cs" /> <Compile Include="Graph\PluggableAttributeScanner.cs" /> <Compile Include="Graph\PluginCache.cs" /> Modified: trunk/Source/StructureMap.Testing/Graph/DefaultConventionScanningTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Graph/DefaultConventionScanningTester.cs 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap.Testing/Graph/DefaultConventionScanningTester.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -6,71 +6,14 @@ namespace StructureMap.Testing.Graph { [TestFixture] - public class GenericConnectionScannerTester - { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - container = new Container(x => - { - x.Scan(o => - { - o.TheCallingAssembly(); - o.ConnectImplementationsToTypesClosing(typeof (IFinder<>)); - }); - }); - } - - #endregion - - private Container container; - - [Test] - public void can_find_the_closed_finders() - { - container.GetInstance<IFinder<string>>().ShouldBeOfType<StringFinder>(); - container.GetInstance<IFinder<int>>().ShouldBeOfType<IntFinder>(); - container.GetInstance<IFinder<double>>().ShouldBeOfType<DoubleFinder>(); - } - - [Test, ExpectedException(typeof (ApplicationException))] - public void fails_on_closed_type() - { - new GenericConnectionScanner(typeof (double)); - } - } - - public interface IFinder<T> - { - } - - public class StringFinder : IFinder<string> - { - } - - public class IntFinder : IFinder<int> - { - } - - public class DoubleFinder : IFinder<double> - { - } - - [TestFixture] public class DefaultConventionScanningTester { - #region Setup/Teardown - [SetUp] public void SetUp() { PluginCache.ResetAll(); } - #endregion - [Test] public void FindPluginType() { @@ -129,6 +72,21 @@ family.Seal(); Assert.AreEqual(1, family.InstanceCount); } + + [Test] + public void can_configure_plugin_families_via_dsl() + { + var container = new Container(registry => registry.Scan(x => + { + x.TheCallingAssembly(); + x.WithDefaultConventions().OnAddedPluginTypes(t => t.Singleton()); + })); + + var firstInstance = container.GetInstance<IConvention>(); + var secondInstance = container.GetInstance<IConvention>(); + secondInstance.ShouldBeTheSameAs(firstInstance); + } + } public interface IConvention Added: trunk/Source/StructureMap.Testing/Graph/GenericConnectionScannerTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Graph/GenericConnectionScannerTester.cs (rev 0) +++ trunk/Source/StructureMap.Testing/Graph/GenericConnectionScannerTester.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -0,0 +1,63 @@ +using System; +using NUnit.Framework; +using StructureMap.Graph; + +namespace StructureMap.Testing.Graph +{ + [TestFixture] + public class GenericConnectionScannerTester + { + [Test] + public void can_find_the_closed_finders() + { + var container = new Container(x => x.Scan(o => + { + o.TheCallingAssembly(); + o.ConnectImplementationsToTypesClosing(typeof(IFinder<>)); + })); + container.GetInstance<IFinder<string>>().ShouldBeOfType<StringFinder>(); + container.GetInstance<IFinder<int>>().ShouldBeOfType<IntFinder>(); + container.GetInstance<IFinder<double>>().ShouldBeOfType<DoubleFinder>(); + } + + [Test, ExpectedException(typeof (ApplicationException))] + public void fails_on_closed_type() + { + new GenericConnectionScanner(typeof (double)); + } + + [Test] + public void can_configure_plugin_families_via_dsl() + { + var container = new Container(registry => registry.Scan(x => + { + x.TheCallingAssembly(); + x.ConnectImplementationsToTypesClosing(typeof(IFinder<>)).OnAddedPluginTypes(t => t.Singleton()); + })); + + var firstStringFinder = container.GetInstance<IFinder<string>>().ShouldBeOfType<StringFinder>(); + var secondStringFinder = container.GetInstance<IFinder<string>>().ShouldBeOfType<StringFinder>(); + secondStringFinder.ShouldBeTheSameAs(firstStringFinder); + + var firstIntFinder = container.GetInstance<IFinder<int>>().ShouldBeOfType<IntFinder>(); + var secondIntFinder = container.GetInstance<IFinder<int>>().ShouldBeOfType<IntFinder>(); + secondIntFinder.ShouldBeTheSameAs(firstIntFinder); + } + } + + public interface IFinder<T> + { + } + + public class StringFinder : IFinder<string> + { + } + + public class IntFinder : IFinder<int> + { + } + + public class DoubleFinder : IFinder<double> + { + } +} \ No newline at end of file Modified: trunk/Source/StructureMap.Testing/Graph/SingleImplementationScannerTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Graph/SingleImplementationScannerTester.cs 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap.Testing/Graph/SingleImplementationScannerTester.cs 2010-01-30 19:13:59 UTC (rev 326) @@ -6,28 +6,48 @@ [TestFixture] public class SingleImplementationScannerTester { - [Test] - public void other() + private Container _container; + + [SetUp] + public void Setup() { - typeof (Type).IsValueType.ShouldBeFalse(); + _container = new Container(registry => registry.Scan(x => + { + x.TheCallingAssembly(); + x.IncludeNamespaceContainingType<SingleImplementationScannerTester>(); + x.SingleImplementationsOfInterface(); + })); } [Test] public void registers_plugins_that_only_have_a_single_implementation() { - var container = new Container(registry => - { - registry.Scan(x => - { - x.TheCallingAssembly(); - x.IncludeNamespaceContainingType<SingleImplementationScannerTester>(); - x.SingleImplementationsOfInterface(); - }); - }); - container.GetInstance<IOnlyHaveASingleConcreteImplementation>() + _container.GetInstance<IOnlyHaveASingleConcreteImplementation>() .ShouldBeOfType<MyNameIsNotConventionallyRelatedToMyInterface>(); } + + [Test] + public void should_not_automatically_register_plugins_that_have_multiple_implementations() + { + _container.TryGetInstance<IHaveMultipleConcreteImplementations>().ShouldBeNull(); + } + + [Test] + public void can_configure_plugin_families_via_dsl() + { + var differentContainer = new Container(registry => registry.Scan(x => + { + x.TheCallingAssembly(); + x.IncludeNamespaceContainingType<SingleImplementationScannerTester>(); + x.SingleImplementationsOfInterface().OnAddedPluginTypes(t => t.Singleton()); + })); + + var firstInstance = differentContainer.GetInstance<IOnlyHaveASingleConcreteImplementation>(); + var secondInstance = differentContainer.GetInstance<IOnlyHaveASingleConcreteImplementation>(); + secondInstance.ShouldBeTheSameAs(firstInstance); + } + } @@ -38,4 +58,8 @@ public class MyNameIsNotConventionallyRelatedToMyInterface : IOnlyHaveASingleConcreteImplementation { } -} \ No newline at end of file + + public interface IHaveMultipleConcreteImplementations { } + public class FirstConcreteImplementation : IHaveMultipleConcreteImplementations { } + public class SecondConcreteImplementation : IHaveMultipleConcreteImplementations { } +} Modified: trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj =================================================================== --- trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj 2010-01-28 01:27:28 UTC (rev 325) +++ trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj 2010-01-30 19:13:59 UTC (rev 326) @@ -258,6 +258,7 @@ <SubType>Code</SubType> </Compile> <Compile Include="Graph\FirstInterfaceConventionTester.cs" /> + <Compile Include="Graph\GenericConnectionScannerTester.cs" /> <Compile Include="Graph\SingleImplementationScannerTester.cs" /> <Compile Include="Graph\TestExplicitArguments.cs" /> <Compile Include="Graph\FillDependenciesTester.cs"> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |