diff --git a/docs/catalogs.rst b/docs/catalogs.rst index df304ddc..05641883 100644 --- a/docs/catalogs.rst +++ b/docs/catalogs.rst @@ -1,11 +1,58 @@ Catalogs ======== +Catalogs are collections of providers. Main purpose of catalogs is to group +providers. + +There are, actually, several popular use cases of catalogs: + +- Grouping of providers from same architectural layer (for example, + ``Services``, ``Models`` and ``Forms`` catalogs). +- Grouping of providers from a same functional components (for example, + catalog ``Users``, that contains all functional parts of ``Users`` + component). + Writing catalogs ---------------- -Creating catalogs from modules ------------------------------- +Catalogs have to be created by extending base catalog class +``objects.catalog.AbstractCatalog``. -@override decorator -------------------- +Providers have to be defined like catalog's attributes. Every provider in +catalog has name. This name should follow ``some_provider`` manner, that is +standard naming convention for names of attributes in Python. + +.. note:: + + It might be useful to add such + ``""":type: (objects.Provider) -> Object1"""`` documentation blocks one + line after provider definition for every provider. It will help code + analysis tools and IDE's to understand that variable above contains some + callable object, that returns particular instance as a result of call. + +Example: + +.. literalinclude:: ../examples/catalogs/simple.py + :language: python + +Overriding of catalogs +---------------------- + +Catalogs can be overridden by other catalogs. This, actually, means that +all of the providers from overriding catalog will override providers with the +same names in overridden catalog. + +There are two ways to override catalog by another catalog: + +- Use ``Catalog.override(Catalog)`` method. +- Use ``@override(Catalog)`` class decorator. + +Example of overriding catalog using ``Catalog.override()`` method: + +.. literalinclude:: ../examples/catalogs/override.py + :language: python + +Example of overriding catalog using ``@override()`` decorator: + +.. literalinclude:: ../examples/catalogs/override_decorator.py + :language: python diff --git a/examples/catalogs/override.py b/examples/catalogs/override.py new file mode 100644 index 00000000..bb691c1b --- /dev/null +++ b/examples/catalogs/override.py @@ -0,0 +1,49 @@ +"""`Catalog.override()` example.""" + +from collections import namedtuple + +from objects.catalog import AbstractCatalog +from objects.providers import Factory +from objects.injections import KwArg + + +# Creating some example classes: +Object1 = namedtuple('Object1', ['arg1', 'arg2']) +Object2 = namedtuple('Object2', ['object1']) +ExtendedObject2 = namedtuple('ExtendedObject2', []) + + +class Catalog(AbstractCatalog): + + """Providers catalog.""" + + object1_factory = Factory(Object1, + KwArg('arg1', 1), + KwArg('arg2', 2)) + """:type: (objects.Provider) -> Object1""" + + object2_factory = Factory(Object2, + KwArg('object1', object1_factory)) + """:type: (objects.Provider) -> Object2""" + + +class AnotherCatalog(AbstractCatalog): + + """Another providers catalog.""" + + object2_factory = Factory(ExtendedObject2) + """:type: (objects.Provider) -> ExtendedObject2""" + + +# Overriding `Catalog` with `AnotherCatalog`: +Catalog.override(AnotherCatalog) + +# Creating some objects using overridden catalog: +object2_1 = Catalog.object2_factory() +object2_2 = Catalog.object2_factory() + +# Making some asserts: +assert object2_1 is not object2_2 + +assert isinstance(object2_1, ExtendedObject2) +assert isinstance(object2_2, ExtendedObject2) diff --git a/examples/catalogs/override_decorator.py b/examples/catalogs/override_decorator.py new file mode 100644 index 00000000..d9a33f4e --- /dev/null +++ b/examples/catalogs/override_decorator.py @@ -0,0 +1,49 @@ +"""Catalog `@override()` decorator example.""" + +from collections import namedtuple + +from objects.catalog import AbstractCatalog +from objects.catalog import override +from objects.providers import Factory +from objects.injections import KwArg + + +# Creating some example classes: +Object1 = namedtuple('Object1', ['arg1', 'arg2']) +Object2 = namedtuple('Object2', ['object1']) +ExtendedObject2 = namedtuple('ExtendedObject2', []) + + +class Catalog(AbstractCatalog): + + """Providers catalog.""" + + object1_factory = Factory(Object1, + KwArg('arg1', 1), + KwArg('arg2', 2)) + """:type: (objects.Provider) -> Object1""" + + object2_factory = Factory(Object2, + KwArg('object1', object1_factory)) + """:type: (objects.Provider) -> Object2""" + + +# Overriding `Catalog` with `AnotherCatalog`: +@override(Catalog) +class AnotherCatalog(AbstractCatalog): + + """Another providers catalog.""" + + object2_factory = Factory(ExtendedObject2) + """:type: (objects.Provider) -> ExtendedObject2""" + + +# Creating some objects using overridden catalog: +object2_1 = Catalog.object2_factory() +object2_2 = Catalog.object2_factory() + +# Making some asserts: +assert object2_1 is not object2_2 + +assert isinstance(object2_1, ExtendedObject2) +assert isinstance(object2_2, ExtendedObject2) diff --git a/examples/catalogs/simple.py b/examples/catalogs/simple.py new file mode 100644 index 00000000..7a00976b --- /dev/null +++ b/examples/catalogs/simple.py @@ -0,0 +1,41 @@ +"""Catalog example.""" + +from collections import namedtuple + +from objects.catalog import AbstractCatalog +from objects.providers import Factory +from objects.injections import KwArg + + +# Creating some example classes: +Object1 = namedtuple('Object1', ['arg1', 'arg2']) +Object2 = namedtuple('Object2', ['object1']) + + +class Catalog(AbstractCatalog): + + """Providers catalog.""" + + object1_factory = Factory(Object1, + KwArg('arg1', 1), + KwArg('arg2', 2)) + """:type: (objects.Provider) -> Object1""" + + object2_factory = Factory(Object2, + KwArg('object1', object1_factory)) + """:type: (objects.Provider) -> Object2""" + +# Creating some objects: +object2_1 = Catalog.object2_factory() +object2_2 = Catalog.object2_factory() + +# Making some asserts: +assert object2_1 is not object2_2 + +assert isinstance(object2_1, Object2) +assert object2_1.object1.arg1 == 1 +assert object2_1.object1.arg2 == 2 + +assert isinstance(object2_2, Object2) +assert object2_2.object1.arg1 == 1 +assert object2_2.object1.arg2 == 2