import zuice.inspect

class Injector(object):
    def __init__(self, bindings):
        self._bindings = bindings.copy()
        self._bindings.bind('injector').to_instance(self)
        self._bindings.bind(Injector).to_instance(self)
    
    def get(self, key):
        if isinstance(key, basestring):
            return self.get_from_name(key)
        if isinstance(key, type):
            return self.get_from_type(key)
        raise NoSuchBindingException(key)
    
    def get_from_type(self, type_to_get):
        if not isinstance(type_to_get, type):
            raise TypeError(str(type_to_get) + " is not a type")
        if type_to_get in self._bindings:
            return self._get_from_bindings(type_to_get)
        if hasattr(type_to_get.__init__, 'zuice'):
            return self._inject(type_to_get, type_to_get.__init__.zuice)
        try:
            return type_to_get()
        except TypeError:
            raise NoSuchBindingException(type_to_get)
        
    def get_from_name(self, name):
        if not isinstance(name, basestring):
            raise TypeError
        return self._get_from_bindings(name)
    
    def call(self, method):
        if hasattr(method, 'zuice'):
            zuice_constructor = method.zuice
        else:
            zuice_constructor = _ZuiceConstructorByName(method, zuice.inspect.get_args_spec)
        return self._inject(method, zuice_constructor)
        try:
            return method()
        except TypeError:
            raise NoSuchBindingException(method)
    
    def _get_from_bindings(self, key):
        if key not in self._bindings:
            raise NoSuchBindingException(key)
        return self.call(self._bindings[key])
        
    def _inject(self, to_call, argument_builder):
        args = argument_builder.build_args(self)
        return to_call(*args.args, **args.kwargs)

class NoSuchBindingException(Exception):
    def __init__(self, key):
        self.key = key
        
    def __str__(self):
        return str(self.key)

class _Arguments(object):
    def __init__(self, args, kwargs):
        self.args = args
        self.kwargs = kwargs

class _ZuiceConstructorByName(object):
    def __init__(self, method, argument_inspector):
        self._method = method
        self._argument_inspector = argument_inspector
    
    def build_args(self, injector):
        args_spec = self._argument_inspector(self._method)
        def build_arg(arg):
            if arg.name in injector._bindings:
                return injector.get_from_name(arg.name)
            if arg.has_default:
                return arg.default
            raise NoSuchBindingException(arg.name)
        return _Arguments(map(build_arg, args_spec), {})
        
def inject_by_name(constructor):
    constructor.zuice = _ZuiceConstructorByName(constructor, zuice.inspect.get_args_spec)
    return constructor

class _ZuiceConstructorByKey(object):
    def __init__(self, keys):
        self._keys = keys
    
    def build_args(self, injector):
        return _Arguments(map(lambda key: injector.get(key), self._keys), {})

class _ZuiceConstructorByNamedKey(object):
    def __init__(self, method, named_keys):
        self._method = method
        self._named_keys = named_keys
        
    def build_args(self, injector):
        def build_arg(arg):
            if arg.name in self._named_keys:
                return injector.get(self._named_keys[arg.name])
            try:
                return injector.get(arg.name)
            except NoSuchBindingException:
                if arg.has_default:
                    return arg.default
                raise NoSuchBindingException(arg.name)

        args_spec = zuice.inspect.get_args_spec(self._method)
        arg_names = [arg.name for arg in args_spec]
        args = map(build_arg, args_spec)
        
        kwargs = {}
        for key in self._named_keys:
            if key not in arg_names:
                kwargs[key] = injector.get(self._named_keys[key])
            
        return _Arguments(args, kwargs)

def inject_with(*keys, **named_keys):
    def a(constructor):
        if len(named_keys) > 0:
            zuice_constructor = _ZuiceConstructorByNamedKey(constructor, named_keys)
        else:
            zuice_constructor = _ZuiceConstructorByKey(keys)
        constructor.zuice = zuice_constructor
        return constructor
    return a

@@ -2868,222 +2868,8 @@
 or%0A%0A
-class _ZuiceConstructorByKey(object):%0A    def __init__(self, keys):%0A        self._keys = keys%0A    %0A    def build_args(self, injector):%0A        return _Arguments(map(lambda key: injector.get(key), self._keys), %7B%7D)%0A%0A
 clas
@@ -2937,16 +2937,22 @@
  method,
+ keys,
  named_k
@@ -2979,32 +2979,58 @@
 method = method%0A
+        self._keys = keys%0A
         self._na
@@ -3108,67 +3108,329 @@
     
-def build_arg(arg):%0A            if
+args_spec = zuice.inspect.get_args_spec(self._method)%0A        arg_names = %5Barg.name for arg in
  arg
-.name in self._named_
+s_spec%5D%0A        %0A        keys = self._named_keys.copy()%0A        for index in range(0, len(self._keys)):%0A            keys%5Barg_names%5Bindex%5D%5D = self._keys%5Bindex%5D%0A        %0A        def build_arg(arg):%0A            if arg.name in 
 keys
@@ -3463,36 +3463,24 @@
 njector.get(
-self._named_
 keys%5Barg.nam
@@ -3722,123 +3722,8 @@
 ame)
-%0A%0A        args_spec = zuice.inspect.get_args_spec(self._method)%0A        arg_names = %5Barg.name for arg in args_spec%5D
 %0A   
@@ -4049,44 +4049,8 @@
 r):%0A
-        if len(named_keys) %3E 0:%0A    
     
@@ -4118,89 +4118,20 @@
 or, 
+keys, 
 named_
-keys)%0A        else:%0A            zuice_constructor = _ZuiceConstructorByKey(
 keys

Remove _ZuiceConstructorByKey and use _ZuiceConstructorByNamedKey instead