From 3a6829970bf999d0015d613055034b678973036a Mon Sep 17 00:00:00 2001 From: Whiteknight Date: Sat, 19 Nov 2011 09:33:25 -0500 Subject: [PATCH] Initial rewrite of Container library --- VERSION | 2 +- setup.winxed | 14 +- src/container/Argument.winxed | 37 +++ src/container/Container.winxed | 272 ++++++------------ src/container/ItemFactory.winxed | 68 ----- src/container/Option.winxed | 3 + src/container/Resolver.winxed | 166 +++++++++++ .../action_argument/ContainerResolver.winxed | 26 -- .../itemfactory/FactoryMethod.winxed | 28 -- src/container/itemfactory/Instance.winxed | 18 -- .../itemfactory/P6protoobject.winxed | 20 -- src/container/itemfactory/ParrotClass.winxed | 32 --- src/container/itemfactory/Prototype.winxed | 24 -- src/container/option/Build.winxed | 89 ++++++ src/container/option/Misc.winxed | 3 + src/unstable/container2/Container.winxed | 118 -------- src/unstable/container2/Option.winxed | 37 --- src/unstable/container2/Resolver.winxed | 47 --- 18 files changed, 391 insertions(+), 613 deletions(-) create mode 100644 src/container/Argument.winxed delete mode 100644 src/container/ItemFactory.winxed create mode 100644 src/container/Option.winxed create mode 100644 src/container/Resolver.winxed delete mode 100644 src/container/action_argument/ContainerResolver.winxed delete mode 100644 src/container/itemfactory/FactoryMethod.winxed delete mode 100644 src/container/itemfactory/Instance.winxed delete mode 100644 src/container/itemfactory/P6protoobject.winxed delete mode 100644 src/container/itemfactory/ParrotClass.winxed delete mode 100644 src/container/itemfactory/Prototype.winxed create mode 100644 src/container/option/Build.winxed create mode 100644 src/container/option/Misc.winxed delete mode 100644 src/unstable/container2/Container.winxed delete mode 100644 src/unstable/container2/Option.winxed delete mode 100644 src/unstable/container2/Resolver.winxed diff --git a/VERSION b/VERSION index ceb66d42..b7716770 100644 --- a/VERSION +++ b/VERSION @@ -2,7 +2,7 @@ action: 2 Stable assert: 0 Alpha benchmark: 0 Alpha commandline: 0 Alpha -container: 2 Stable +container: 3 Alpha core: 2 Stable decorate: 0 Beta dumper: 0 Beta diff --git a/setup.winxed b/setup.winxed index 11573a1c..938e4d0c 100644 --- a/setup.winxed +++ b/setup.winxed @@ -87,15 +87,13 @@ function setup_stable_libraries(var rosella) ); // Dependency Injection / Inversion of Control container library - setup_winxed_lib(rosella, "container", ["Core", "Action"], + setup_winxed_lib(rosella, "container", ["Core"], "container/Container", - "container/ItemFactory", - "container/itemfactory/ParrotClass", - "container/itemfactory/P6protoobject", - "container/itemfactory/Prototype", - "container/itemfactory/FactoryMethod", - "container/itemfactory/Instance", - "container/action_argument/ContainerResolver" + "container/Argument", + "container/Option", + "container/option/Build", + "container/option/Misc", + "container/Resolver" ); // A proxying library for building and managing proxies diff --git a/src/container/Argument.winxed b/src/container/Argument.winxed new file mode 100644 index 00000000..b75e9fb6 --- /dev/null +++ b/src/container/Argument.winxed @@ -0,0 +1,37 @@ +class Rosella.Container.Argument +{ + function get_value(var container) + { + Rosella.Error.must_subclass(__CLASS__); + } +} + +class Rosella.Container.Argument.Resolve : Rosella.Container.Argument +{ + var type; + + function Resolve(var type) + { + self.type = type; + } + + function get_value(var container) + { + return container.resolve(self.type); + } +} + +class Rosella.Container.Argument.Instance : Rosella.Container.Argument +{ + var instance; + + function Instance(var instance) + { + self.instance = instance; + } + + function get_value(var container) + { + return self.instance; + } +} diff --git a/src/container/Container.winxed b/src/container/Container.winxed index c0cfc580..11e332c0 100644 --- a/src/container/Container.winxed +++ b/src/container/Container.winxed @@ -30,221 +30,121 @@ namespace Rosella.Container resolution system. Types are registered with the container, and later instances of those types can be resolved according to a set of resolution rules. - - If the container does not have a pre-registered set of rules for a - type, it falls back to using an ObjectFactory to build one. The - object factory to use can be specified when the container is - constructed. - - Use the "register" set of functions to set up resolution rules for a - type. Use the "resolve" set of functions to get an instance of that - type according to the resolution rules. - - "Resolution Rules" are lists of Action objects, which are executed - on the new instance as soon as it is fetched/allocated. */ class Rosella.Container { - var library; - var default_factory; - var options; - - // Constructor. Set up the container. If we pass in an object factory - // the container will use that for fallback resolution behavior. If - // we set auto_register to 1 (true) we will automatically register - // automatically generated instances with the container. - function Container(var factory [named,optional], int have_fact [opt_flag], - var auto_register [named,optional], int have_auto_reg [opt_flag]) - { - self.library = {}; - self.options = {}; - if (have_auto_reg) - self.options["auto_register"] = auto_register; - else - self.options["auto_register"] = 0; - if (have_fact) - self.default_factory = factory; - else - self.default_factory = new Rosella.ObjectFactory(); - } + var type_registry; + var aliases; - /* Registration Functions - Registrations happen with a type "key". The type can be any object - understood by Rosella.construct. The container can currently only - support a single registration per type key. Subsequent - registrations with the same key, or with a different type object - which stringifies to the same thing as an existing key, will - overwrite the old value. - - Registration functions all take a "meth_inits" argument, which is - an array of Action objects to execute on the object after it is - fetched/allocated, but before it is returned to the user. This - parameter must be provided, but may be an empty array, Null, or - Undef. - */ - - // Register a type object. The type object is used as a meta-object - // to instantiate instances. init_pmc, if given, might be used if - // the type is (or refers to) a Parrot Class PMC. In that case, it - // will be passed as the second input argument to new_p_p_p. - function register_type(var type, - var init_pmc [named,optional], int have_init [opt_flag], - var meth_inits [named,optional], int have_inits [opt_flag]) - { - string name = Rosella.get_type_name(type); - if (!have_init) - init_pmc = new 'Undef'; - if (!have_inits) - meth_inits = []; - var item = self.private_get_generator_item(type, init_pmc, meth_inits); - self.library[name] = item; - } - - // Register a type prototype. The prototype is cloned to produce - // new instances. - function register_prototype(var type, var prototype, - var meth_inits [named,optional], int have_inits [opt_flag]) + function Container() { - string name = Rosella.get_type_name(type); - if (!have_inits) - meth_inits = []; - var item = self.private_get_prototype_item(prototype, meth_inits); - self.library[name] = item; + var reg = {}; + reg.set_key_type(3); + self.type_registry = reg; + self.aliases = {}; } - // Register a type instance. The type always resolves to this single - // instance, and new objects are not created. The type to use is - // inferred from the instance object. - function register_instance(var instance, - var meth_inits [named,optional], int have_inits [opt_flag]) + function __sort_options(var type, var options) { - var type = self.get_instance_type(instance); - if (!have_inits) - meth_inits = []; - self.register_instance(type, instance, meth_inits:[named]); - } - - // Register a type instance. The type key is provided explicitly - function register_instance_type(var type, var instance, - var meth_inits [named,optional], int have_inits [opt_flag]) - { - string name = Rosella.get_type_name(type); - if (!have_inits) - meth_inits = []; - var item = self.private_get_instance_item(instance, meth_inits); - self.library[name] = item; + var resolver = null; + var build_options = []; + var misc_options = []; + for (var option in options) { + if (option instanceof Rosella.Container.Resolver) { + if (resolver != null) + self.multiple_resolvers_error(type); + resolver = option; + continue; + } + if (!(option instanceof Rosella.Container.Option)) { + if (resolver != null) + self.multiple_resolvers_error(type); + // it's an instance + resolver = new Rosella.Container.Resolver.Instance(option); + continue; + } + if (option instanceof Rosella.Container.Option.Build) { + push(build_options, option); + continue; + } + if (option instanceof Rosella.Container.Option) { + push(misc_options, option); + continue; + } + Rosella.Error.invalid(__FUNCTION__, "Invalid option: %s", typeof(option)); + } + return resolver, build_options, misc_options; } - // Register a type with a factory method. The method is an invokable - // object (Sub, method, etc) which is expected to return an instance. - // In addition to the meth_inits argument, it also takes a list of - // arg_inits, Argument objects which are passed to the factory - // method as parameters. - function register_factory_method(var type, var factory, - var meth_inits [named,optional], int have_inits [opt_flag], - var arg_inits [named,optional], int have_args [opt_flag]) + function register(var type, var options [slurpy]) { - string name = Rosella.get_type_name(type); - if (!have_inits) - meth_inits = []; - if (!have_args) - arg_inits = []; - var item = self.private_get_factory_method_item(factory, - meth_inits, arg_inits - ); - self.library[name] = item; + var type_class = Rosella.get_type_class(type); + if (type_class == null) + Rosella.Error.invalid(__FUNCTION__, "Attempt to register invalid or null type"); + :(var resolver, var build_options, var misc_options) = self.__sort_options(type_class, options); + if (resolver == null) + resolver = new Rosella.Container.Resolver.Type(type); + resolver.set_options(build_options, misc_options); + if (exists self.type_registry[type_class]) + resolver.previous(self.type_registry[type_class]); + self.type_registry[type_class] = resolver; + return self; } - /* Resolution Functions - These functions resolve a type key into a usable instance. - Each of these functions takes a type key to use for looking up - the resolution rules and ultimately providing an instance. - */ - - // Resolve the type using full resolution. If the type is not - // registered, fall back to the default factory to allocate one. - // If auto_register is set, automatically register the output of - // the default factory as the instance for that type. - // Notice that when falling back to the default factory, no arguments - // can be provided. - function resolve(var type, var pos [slurpy], var named [slurpy,named]) + function unregister(var type) { - string name = Rosella.get_type_name(type); - if (exists self.library[name]) - return self.library[name].create(pos:[flat], named:[flat,named]); - var obj = self.resolve_create(type, pos:[flat], named:[flat,named]); - if (self.options["auto_register"]) - self.register_instance_type(type, obj); - return obj; + var type_class = Rosella.get_type_class(type); + if (exists self.type_registry[type_class]) { + var old = self.type_registry[type_class].previous(); + if (old == null) + delete self.type_registry[type_class]; + else + self.type_registry[type_class] = old; + } + return self; } - // Create-only resolution. Do not attempt to resolve using normal - // rules, always use the default factory. - function resolve_create(var type, var pos [slurpy], var named [slurpy,named]) + function multiple_resolvers_error(var type) { - return self.default_factory.create_typed(type, - pos:[flat], named:[flat,named] - ); + Rosella.Error.invalid(__FUNCTION__, "Multiple resolvers specified for type registration %", Rosella.get_type_name(type)); } - // Partial resolution. Resolve the instance only if the type has been - // previously registered. If there is no registration, die. - function resolve_nocreate(var type, var overrides [slurpy], - var named_opts[slurpy,named]) + function alias(var type, string name) { - string name = Rosella.get_type_name(type); - if (exists self.library[name]) - return self.library[name].create(); - - Rosella.Error.invalid(__FUNCTION__, "Type " + type + " not registered"); + var type_class = Rosella.get_type_class(type); + if (type_class == null) + Rosella.Error.invalid(__FUNCTION__, "Cannot setup alias '%s' for unknown class", name); + self.aliases[name] = type_class; } - /* Instance Entry Functions - These functions are not part of the public interface for - Container. - - These functions are used to create ItemFactory objects for each - registration. ItemFactory is the class that performs rule-based - resolutions - */ - - // Get an ItemFactory for handling instance registrations - function private_get_instance_item(var instance, var meth_inits) + function resolve[multi("pmc")](var type, var options [slurpy]) { - return new Rosella.Container.ItemFactory.Instance(instance, meth_inits); + var type_class = Rosella.get_type_class(type); + if (type_class == null) + Rosella.Error.invalid(__FUNCTION__, "Cannot resolve unknown class"); + return self.__resolve_internal(type_class, options); } - // Get an ItemFactory for handling prototype registrations - function private_get_prototype_item(var proto, var meth_inits) + function resolve[multi(string)](string name, var options [slurpy]) { - return new Rosella.Container.ItemFactory.Prototype(proto, meth_inits); + if (exists self.aliases[name]) { + var type = self.aliases[name]; + return self.__resolve_internal(type, options); + } else + Rosella.Error.invalid(__FUNCTION__, "Cannot resolve alias '%s'", name); } - // Get an ItemFactory for handling a Class or P6protoobject - // registration. - function private_get_generator_item(var type, var init_pmc, var meth_inits) + function __resolve_internal(var type, var options) { - var item; - if (type instanceof "P6protoobject") { - item = new Rosella.Container.ItemFactory.P6protoobject( - type, meth_inits); - } else if (type instanceof "Class") { - item = new Rosella.Container.ItemFactory.ParrotClass( - type, init_pmc, meth_inits); - } else { - var type_obj = Rosella.get_type_class(type); - item = new Rosella.Container.ItemFactory.ParrotClass( - type_obj, init_pmc, meth_inits); + var type_class = Rosella.get_type_class(type); + :(var resolver, var build_options, var misc_options) = self.__sort_options(type_class, options); + if (resolver == null) { + if (exists self.type_registry[type_class]) + resolver = self.type_registry[type_class]; + else + Rosella.Error.invalid(__FUNCTION__, "No Resolver specified for type %s", type_class); } - return item; - } - - // Get an ItemFactory for a factory method registration - function private_get_factory_method_item(var sub, var meth_inits, - var arg_inits) - { - return new Rosella.Container.ItemFactory.FactoryMethod( - sub, meth_inits, arg_inits - ); + var instance = resolver.resolve(self, build_options, misc_options); + return instance; } } diff --git a/src/container/ItemFactory.winxed b/src/container/ItemFactory.winxed deleted file mode 100644 index 0a1288dc..00000000 --- a/src/container/ItemFactory.winxed +++ /dev/null @@ -1,68 +0,0 @@ -/* ItemFactory is the class that handles resolving a single type. - ItemFactory is an abstract parent class and should not be used - directly. You should use one of the existing subclasses or a custom - subclass instead. - - Container.ItemFactory is an ObjectFactory with the additional feature - of executing an array of Actions on the generated object. -*/ -class Rosella.Container.ItemFactory : Rosella.ObjectFactory -{ - var method_initializers; // A list of Action objects - - /* ObjectFactory Public Interface - */ - - // Create and initialize the object, according to the rules of this - // particular subclass. - function create(var p [slurpy], var n [named,slurpy]) - { - var item = self.protected_resolve_instance(); - self.__initialize(item); - return item; - } - - // Create a new object using standard Rosella.construct(). Execute all - // initializers on it. This ignores most behavior of the particular - // subclass and is probably not what you want. - function create_typed(var type, var p [slurpy], var n [named,slurpy]) - { - using Rosella.construct; - var object = construct(type, p:[flat], n:[flat,named]); - self.__initialize(object); - return object; - } - - /* Private Internal Routines - */ - - // Initialize the new object by executing all initializer actions on - // it. - function __initialize(var object) - { - if (self.method_initializers == null) - return; - for (var init in self.method_initializers) - init.execute(object); - } - - // Set up the list of method initializers - function protected_method_initializers(var inits) - { - int have_inits = 0; - ${ defined have_inits, inits }; - if (have_inits) - self.method_initializers = inits; - else - self.method_initializers = []; - } - - /* Routines to be Subclassed - */ - - // Get a fresh, uninitialized instance object. This must be subclassed - function protected_resolve_instance() - { - Rosella.Error.must_subclass(__CLASS__); - } -} diff --git a/src/container/Option.winxed b/src/container/Option.winxed new file mode 100644 index 00000000..aab807a7 --- /dev/null +++ b/src/container/Option.winxed @@ -0,0 +1,3 @@ +class Rosella.Container.Option +{ +} diff --git a/src/container/Resolver.winxed b/src/container/Resolver.winxed new file mode 100644 index 00000000..3bfacd05 --- /dev/null +++ b/src/container/Resolver.winxed @@ -0,0 +1,166 @@ +class Rosella.Container.Resolver +{ + var previous; + var build_options; + var misc_options; + var data; + var positionals; + var named; + + function previous(var prev [optional], int has_p [opt_flag]) + { + if (has_p) + self.previous = prev; + return self.previous; + } + + function set_options(var build, var misc) + { + self.build_options = build; + self.misc_options = misc; + } + + function resolve(var container, var build, var misc) + { + if (elements(build) == 0) + build = self.build_options; + if (elements(misc) == 0) + misc = self.misc_options; + var obj = self.resolve_internal(container); + self.execute_options(container, obj, build, misc); + return obj; + } + + function execute_options(var container, var obj, var build, var misc) + { + for (var build_opt in build) + build_opt.execute(container, obj); + for (var misc_opt in misc) + misc_opt.execute(container, obj); + } + + function get_arguments(var container, var p, var n) + { + var po = []; + var no = {}; + if (p != null) { + for (int i = 0; i < elements(p); i++) { + var positional = p[i]; + if (positional instanceof Rosella.Container.Argument) + po[i] = positional.get_value(container); + else + po[i] = positional; + } + } + if (n != null) { + for (string s in n) { + var named = n[s]; + if (named instanceof Rosella.Container.Argument) + no[s] = named.get_value(container); + else + no[s] = self.named[s].get_value(container); + } + } + return po, no; + } + + function resolve_internal(var build, var misc) + { + Rosella.Error.must_subclass(__CLASS__); + } +} + +class Rosella.Container.Resolver.Instance : Rosella.Container.Resolver +{ + function Instance(var obj) + { + self.data = obj; + } + + function resolve_internal(var container) + { + return self.data; + } +} + +class Rosella.Container.Resolver.Type : Rosella.Container.Resolver +{ + function Type(var type, var p [slurpy], var n [slurpy,named]) + { + self.data = type; + self.positionals = p; + self.named = n; + } + + function resolve_internal(var container) + { + :(var p, var n) = self.get_arguments(container, self.positionals, self.named); + return Rosella.construct(self.data, p:[flat], n:[flat,named]); + } +} + +class Rosella.Container.Resolver.TypeConstructor : Rosella.Container.Resolver +{ + var constructor; + + function TypeConstructor(var type, string constructor, var p [slurpy], var n [slurpy,named]) + { + self.data = type; + self.positionals = p; + self.named = n; + self.constructor = constructor; + } + + function resolve_internal(var container) + { + var obj = Rosella.alloc(self.data); + var constructor = Rosella.find_named_method(obj, string(self.constructor)); + if (constructor == null) + Rosella.Error.invalid(__FUNCTION__, "Cannot find method '%s' in type %s", self.constructor, self.data); + :(var p, var n) = self.get_arguments(container, self.positionals, self.named); + obj.*constructor(p:[flat], n:[flat,named]); + return obj; + } +} + +class Rosella.Container.Resolver.Factory : Rosella.Container.Resolver +{ + var method; + + function Factory(var factory, string method, var p [slurpy], var n [slurpy,named]) + { + self.data = factory; + self.method = method; + self.positionals = p; + self.named = n; + } + + function resolve_internal(var container) + { + var factory = self.data; + var method = Rosella.find_named_method(factory, string(self.method)); + if (method == null) + Rosella.Error.invalid(__FUNCTION__, "Cannot find method '%s' on factory type %s", self.method, typeof(self.data)); + :(var p, var n) = self.get_arguments(container, self.positionals, self.named); + var obj = factory.*method(p:[flat], n:[flat,named]); + return obj; + } +} + +class Rosella.Container.Resolver.FactoryMethod : Rosella.Container.Resolver +{ + function FactoryMethod(var factory_method, var p [slurpy], var n [slurpy,named]) + { + self.data = factory_method; + self.positionals = p; + self.named = n; + } + + function resolve_internal(var container) + { + var f = self.data; + :(var p, var n) = self.get_arguments(container, self.positionals, self.named); + var obj = f(p:[flat], n:[flat,named]); + return obj; + } +} diff --git a/src/container/action_argument/ContainerResolver.winxed b/src/container/action_argument/ContainerResolver.winxed deleted file mode 100644 index fbf27700..00000000 --- a/src/container/action_argument/ContainerResolver.winxed +++ /dev/null @@ -1,26 +0,0 @@ -/* An action type which uses the Container to resolve the value. -*/ -class Rosella.Action.Argument.ContainerResolver : Rosella.Action.Argument -{ - var container; - var type; - - function ContainerResolver(var container, var type, var args [slurpy,named]) - { - if (type == null || container == null) - Rosella.Error.invalid(__FUNCTION__, "container and type may not be null"); - int is_container = 0; - ${ can is_container, container, "resolve" }; - if (!is_container) - Rosella.Error.invalid(__FUNCTION__, "container argument is not a valid Container"); - self.container = container; - self.type = type; - self.setup_positioning(args:[flat,named]); - } - - // Resolve the value from the container - function resolve_value() - { - return self.container.resolve(self.type); - } -} diff --git a/src/container/itemfactory/FactoryMethod.winxed b/src/container/itemfactory/FactoryMethod.winxed deleted file mode 100644 index caf5f003..00000000 --- a/src/container/itemfactory/FactoryMethod.winxed +++ /dev/null @@ -1,28 +0,0 @@ -/* An ItemFactory to resolve from a factory method object. -*/ -class Rosella.Container.ItemFactory.FactoryMethod : Rosella.Container.ItemFactory -{ - var sub; - var arg_initializers; - - function FactoryMethod(var sub, var inits, var arg_inits) - { - if (sub == null) - Rosella.Error.invalid(__FUNCTION__, "sub may not be null. It must be an invokable object"); - self.sub = sub; - Rosella.Action.Argument.verify_all_arguments(__FUNCTION__, arg_inits); - self.arg_initializers = arg_inits; - self.protected_method_initializers(inits); - } - - // Execute the factory method to return an instance of the object. - function protected_resolve_instance() - { - var pos = []; - var named = {}; - for (var arg_init in self.arg_initializers) - arg_init.prepare_args(pos, named); - var sub = self.sub; - return sub(pos:[flat], named:[flat,named]); - } -} diff --git a/src/container/itemfactory/Instance.winxed b/src/container/itemfactory/Instance.winxed deleted file mode 100644 index 4ec5f9d0..00000000 --- a/src/container/itemfactory/Instance.winxed +++ /dev/null @@ -1,18 +0,0 @@ -/* An ItemFactory subclass for resolving an instance. -*/ -class Rosella.Container.ItemFactory.Instance : Rosella.Container.ItemFactory -{ - var instance; - - function Instance(var obj, var inits) - { - self.instance = obj; - self.protected_method_initializers(inits); - } - - // Return the instance - function protected_resolve_instance() - { - return self.instance; - } -} diff --git a/src/container/itemfactory/P6protoobject.winxed b/src/container/itemfactory/P6protoobject.winxed deleted file mode 100644 index 84cd72de..00000000 --- a/src/container/itemfactory/P6protoobject.winxed +++ /dev/null @@ -1,20 +0,0 @@ -/* An ItemFactory for resolving from a P6protoobject -*/ -class Rosella.Container.ItemFactory.P6protoobject : Rosella.Container.ItemFactory -{ - var proto; - - function P6protoobject(var proto, var inits) - { - if (proto == null) - Rosella.Error.invalid(__FUNCTION__, "proto object may not be null"); - self.proto = proto; - self.protected_method_initializers(inits); - } - - // Get a new instance from the P6protoobject - function protected_resolve_instance() - { - return self.proto.new(); - } -} diff --git a/src/container/itemfactory/ParrotClass.winxed b/src/container/itemfactory/ParrotClass.winxed deleted file mode 100644 index 6e7eb855..00000000 --- a/src/container/itemfactory/ParrotClass.winxed +++ /dev/null @@ -1,32 +0,0 @@ -// An ItemFactory for resolving from a Parrot Class PMC (or anything -// that can be resolved to a class using Rosella.construct) -class Rosella.Container.ItemFactory.ParrotClass : Rosella.Container.ItemFactory -{ - var class_obj; - var init_pmc; - - function ParrotClass(var class_obj, var init, var inits) - { - if (class_obj == null) - Rosella.Error.invalid(__FUNCTION__, "class_obj may not be null"); - self.class_obj = class_obj; - self.init_pmc = init; - self.protected_method_initializers(inits); - } - - // Instantiate the class, using the various data - function protected_resolve_instance() - { - int have_init_pmc = 0; - var init_pmc = self.init_pmc; - ${ defined have_init_pmc, init_pmc }; - var object = null; - var class_obj = self.class_obj; - if (have_init_pmc) { - var init_pmc = self.init_pmc; - ${ new object, class_obj, init_pmc }; - } else - ${ new object, class_obj }; - return object; - } -} diff --git a/src/container/itemfactory/Prototype.winxed b/src/container/itemfactory/Prototype.winxed deleted file mode 100644 index 7ef59179..00000000 --- a/src/container/itemfactory/Prototype.winxed +++ /dev/null @@ -1,24 +0,0 @@ -/* An ItemFactory to resolve from a prototype by cloning. This uses the - basic Parrot clone op. -*/ -class Rosella.Container.ItemFactory.Prototype : Rosella.Container.ItemFactory -{ - var prototype; - - function Prototype(var proto, var inits) - { - if (proto == null) - Rosella.Error.invalid(__FUNCTION__, "Prototype object may not be null"); - self.prototype = proto; - self.protected_method_initializers(inits); - } - - // Clone the prototype and return the clone - function protected_resolve_instance() - { - var object = null; - var prototype = self.prototype; - ${ clone object, prototype }; - return object; - } -} diff --git a/src/container/option/Build.winxed b/src/container/option/Build.winxed new file mode 100644 index 00000000..626d144d --- /dev/null +++ b/src/container/option/Build.winxed @@ -0,0 +1,89 @@ +class Rosella.Container.Option.Build : Rosella.Container.Option +{ + function execute(var container, var instance) + { + Rosella.Error.must_subclass(__CLASS__); + } +} + +// Call a method during build +class Rosella.Container.Option.Method : Rosella.Container.Option.Build +{ + var method; + var positional; + var named; + + function Method(string method, var p [slurpy], var n [slurpy,named]) + { + self.method = method; + self.positional = p; + self.named = n; + } + + function execute(var container, var instance) + { + var p = []; + var n = {}; + var method = Rosella.find_named_method(instance, string(self.method)); + if (method == null) + Rosella.Error.invalid(__FUNCTION__, "Cannot find method %s", self.method); + for (int i = 0; i < elements(self.positional); i++) { + var positional = self.positional[i]; + if (positional instanceof Rosella.Container.Argument) + p[i] = positional.get_value(container); + else + p[i] = positional; + } + for (string s in self.named) { + var named = self.named[s]; + if (named instanceof Rosella.Container.Argument) + n[s] = named.get_value(container); + else + n[s] = self.named[s].get_value(container); + } + } +} + +// Set an attribute value during build +class Rosella.Container.Option.Attribute : Rosella.Container.Option.Build +{ + var attribute; + var value; + + function Attribute(string attribute, var value) + { + self.attribute = attribute; + self.value = value; + } + + function execute(var container, var instance) + { + string attr = string(self.attribute); + var value = self.value; + if (value instanceof Rosella.Container.Argument) + value = value.get_value(container); + instance.*attr = value; + } +} + +// Set a property value during build +class Rosella.Container.Option.Property : Rosella.Container.Option.Build +{ + var property; + var value; + + function Property(string property, var value) + { + self.property = property; + self.value = value; + } + + function execute(var container, var instance) + { + string prop = string(self.property); + var value = self.value; + if (value instanceof Rosella.Container.Argument) + value = value.get_value(container); + ${ setprop instance, prop, value }; + } +} diff --git a/src/container/option/Misc.winxed b/src/container/option/Misc.winxed new file mode 100644 index 00000000..7882b4d1 --- /dev/null +++ b/src/container/option/Misc.winxed @@ -0,0 +1,3 @@ +class Rosella.Container.Option.ManageLifetime : Rosella.Container.Option +{ +} diff --git a/src/unstable/container2/Container.winxed b/src/unstable/container2/Container.winxed deleted file mode 100644 index 8ce6844b..00000000 --- a/src/unstable/container2/Container.winxed +++ /dev/null @@ -1,118 +0,0 @@ -namespace Rosella.Container -{ -} - -class Rosella.Container -{ - var type_registry; - var aliases; - - function Container() - { - var reg = {}; - reg.set_key_type(3); - self.type_registry = reg; - self.aliases = {}; - } - - function sort_options(var options) - { - var resolver = null; - var build_options = []; - var misc_options = []; - for (var option in options) { - if (!(option instanceof Rosella.Container.Option)) { - if (resolver != null) - self.multiple_resolvers_error(type); - // it's an instance - resolver = new Rosella.Container.Resolver.Instance(option); - continue; - } - if (option instanceof Rosella.Container.Option.Create) { - if (resolver != null) - self.multiple_resolvers_error(type); - resolver = option.get_resolver(); - continue; - } - if (option instanceof Rosella.Container.Option.Build) { - push(build_options, option); - continue; - } - if (option instanceof Rosella.Container.Option) { - push(misc_options, option); - continue; - } - Rosella.Error.invalid(__FUNCTION__, "Invalid option: %s", typeof(option)); - } - return resolver, build_options, misc_options; - } - - function register(var type, var options [slurpy]) - { - var type_class = Rosella.get_type_class(type); - if (type_class == null) - Rosella.Error.invalid(__FUNCTION__, "Attempt to register invalid or null type"); - :(var resolver, var build_options, var misc_options) = self.sort_options(options); - if (resolver == null) - resolver = new Rosella.Container.Resolver.Type(type); - resolver.set_options(build_options, misc_options); - if (exists self.type_registry[type_class]) - resolver.previous(self.type_registry[type_class]); - self.type_registry[type_class] = resolver; - return self; - } - - function unregister(var type) - { - var type_class = Rosella.get_type_class(type); - if (exists self.type_registry[type_class]) { - var old = self.type_registry[type_class].previous(); - if (old == null) - delete self.type_registry[type_class]; - self.type_registry[type_class] = old; - } - return self; - } - - function multiple_resolvers_error(var type) - { - Rosella.Error.invalid(__FUNCTION__, - "Multiple resolvers specified for type registration %", - Rosella.get_type_name(type)); - } - - function alias(var type, string name) - { - self.aliases[name] = type; - } - - function resolve(var type, var options [slurpy]) - { - return self.resolve_internal(type, options); - } - - function resolve_alias(string name, var options [slurpy]) - { - if (exists self.aliases[name]) { - var type = self.aliases[name]; - return self.resolve_internal(type, options); - } else { - Rosella.Error.invalid(__FUNCTION__, "Cannot resolve alias '%s'", name); - } - } - - function resolve_internal(var type, var options) - { - var type_class = Rosella.get_type_class(type); - :(var resolver, var build_options, var misc_options) = self.sort_options(options); - if (resolver == null) { - if (exists self.type_registry[type_class]) - resolver = self.type_registry[type_class]; - else - Rosella.Error.invalid(__FUNCTION__, "No Resolver specified for type %s", - type_class); - } - var instance = resolver.resolve(build_options, misc_options); - return instance; - } -} diff --git a/src/unstable/container2/Option.winxed b/src/unstable/container2/Option.winxed deleted file mode 100644 index 167c54f9..00000000 --- a/src/unstable/container2/Option.winxed +++ /dev/null @@ -1,37 +0,0 @@ -class Rosella.Container.Option -{ -} - -class Rosella.Container.Option.Create : Rosella.Container.Option -{ - function get_resolver() - { - } -} - -class Rosella.Container.Option.Build : Rosella.Container.Option -{ - function execute(var instance) - { - } -} - -class Rosella.Container.Option.ManageLifetime : Rosella.Container.Option -{ -} - -class Rosella.Container.Option.Method : Rosella.Container.Option.Build -{ -} - -class Rosella.Container.Option.Constructor : Rosella.Container.Option.Create -{ -} - -class Rosella.Container.Option.Factory : Rosella.Container.Option.Create -{ -} - -class Rosella.Container.Option.FactoryMethod : Rosella.Container.Option.Create -{ -} diff --git a/src/unstable/container2/Resolver.winxed b/src/unstable/container2/Resolver.winxed deleted file mode 100644 index fac778d8..00000000 --- a/src/unstable/container2/Resolver.winxed +++ /dev/null @@ -1,47 +0,0 @@ -class Rosella.Container.Resolver -{ - var previous; - var build_options; - var misc_options; - - function previous(var prev [optional], int has_p [opt_flag]) - { - if (has_p) - self.previous = prev; - return self.previous; - } - - function set_options(var build, var misc) - { - self.build_options = build; - self.misc_options = misc; - } - - function resolve(var build, var misc) - { - if (elements(build) == 0) - build = self.build_options; - if (elements(misc) == 0) - misc = self.misc_options; - } -} - -class Rosella.Container.Resolver.Instance : Rosella.Container.Resolver -{ -} - -class Rosella.Container.Resolver.Type : Rosella.Container.Resolver -{ -} - -class Rosella.Container.Resolver.TypeConstructor : Rosella.Container.Resolver -{ -} - -class Rosella.Container.Resolver.Factory : Rosella.Container.Resolver -{ -} - -class Rosella.Container.Resolver.FactoryMethod : Rosella.Container.Resolver -{ -}