Created
July 8, 2014 06:10
-
-
Save zipcode/ca6f5286658d3c81756c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import wraps | |
class instancemethod(object): | |
def __init__(self, f): | |
self.f = f | |
def __get__(self, obj, cls=None): | |
if obj is None: | |
obj = cls.instance() | |
@wraps(self.f) | |
def newfunc(*args, **kwargs): | |
return self.f(obj, *args, **kwargs) | |
return newfunc | |
class InjectorException(Exception): | |
pass | |
class Injector(object): | |
__instance = None | |
def __init__(self): | |
self.__bindings = {} | |
self.bindvalue("Injector", self) | |
@classmethod | |
def instance(cls): | |
if cls.__instance is None: | |
cls.__instance = cls() | |
return cls.__instance | |
def setinstance(cls): | |
cls.__class__.__instance = cls | |
@instancemethod | |
def bind(self, name, obj, force=False): | |
if not force and self.__bindings.get(name) is not None: | |
raise InjectorException("Duplicate binding of %s" % name) | |
self.__bindings[name] = obj | |
return self | |
@instancemethod | |
def bindvalue(self, name, value, **kwargs): | |
self.bind(name, lambda: value, **kwargs) | |
@instancemethod | |
def inject(self, name): | |
obj = self.__bindings[name] | |
if obj is None: | |
raise InjectorException("No binding for %s" % name) | |
return obj() | |
def inject(*bindings, **kwbindings): | |
def decorate(cls): | |
@wraps(cls) | |
def newcls(*args, **kwargs): | |
args = list(args) | |
for position in xrange(len(args), len(bindings)): | |
if bindings[position] is None: | |
raise InjectorException("Attempted to bind in a position marked \"None\". Did you get the argument list right?") | |
injected = Injector.inject(bindings[position]) | |
args.append(injected) | |
for key in kwbindings.keys(): | |
if kwargs.get(key) is None: | |
kwargs[key] = Injector.inject(kwbindings[key]) | |
return cls(*args, **kwargs) | |
return newcls | |
return decorate | |
def bind(name=None): | |
if not (isinstance(name, str) or name is None): | |
raise AssertionError("Cannot bind object as a name. Did you write @bind instead of @bind()?") | |
def decorate(cls): | |
Injector.bind(name or cls.__name__, cls) | |
return cls | |
return decorate | |
def bindinstance(name=None): | |
if not (isinstance(name, str) or name is None): | |
raise AssertionError("Cannot bindinstance object. Did you write @bindinstance instead of @bindinstance()?") | |
def decorate(cls): | |
Injector.bindvalue(name or cls.__name__, cls()) | |
return cls | |
return decorate | |
def example(): | |
# Save the old injector | |
i = Injector.instance() | |
Injector().setinstance() | |
Injector.bindvalue("message", "Hello World") | |
@bindinstance() | |
class Printer(object): | |
def __init__(self): | |
self.count = 0 | |
def say(self, message): | |
print "%03d : %s" % (self.count, message) | |
self.count += 1 | |
@inject("message", printer="Printer") | |
def do(message, printer=None): | |
printer.say(message) | |
printer.say(message + "!!") | |
do() | |
do("yep!") | |
print "--- manually setting printer" | |
do(printer = Printer()) | |
# Return to old injector | |
i.setinstance() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment