diff options
| author | Dmitry Vasiliev <dima@hlabs.spb.ru> | 2007-06-24 17:10:08 +0000 |
|---|---|---|
| committer | Dmitry Vasiliev <dima@hlabs.spb.ru> | 2007-06-24 17:10:08 +0000 |
| commit | 7cbc5a076f2e5a69298143ff4a59bd4eaffd8aca (patch) | |
| tree | 4ec00651fadb803a0e070322236a2235facfc1b5 /src | |
| parent | 420db6adf6314a437e3f235bffd57194775a8d13 (diff) | |
| download | zope-interface-7cbc5a076f2e5a69298143ff4a59bd4eaffd8aca.tar.gz | |
Added russian translation for adapter.txt
Diffstat (limited to 'src')
| -rw-r--r-- | src/zope/interface/adapter.ru.txt | 544 | ||||
| -rw-r--r-- | src/zope/interface/adapter.txt | 6 | ||||
| -rw-r--r-- | src/zope/interface/tests/test_adapter.py | 5 |
3 files changed, 550 insertions, 5 deletions
diff --git a/src/zope/interface/adapter.ru.txt b/src/zope/interface/adapter.ru.txt new file mode 100644 index 0000000..1456118 --- /dev/null +++ b/src/zope/interface/adapter.ru.txt @@ -0,0 +1,544 @@ +================ +Реестр адаптеров +================ + +.. contents:: + +Реестры адаптеров предоставляют возможность для регистрации объектов которые +зависят от одной, или нескольких спецификаций интерфейсов и предоставляют +(возможно не напрямую) какой-либо интерфейс. В дополнение, регистрации имеют +имена. (Можно думать об именах как о спецификаторах предоставляемого +интерфейса.) + +Термин "спецификация интерфейса" ссылается и на интерфейсы и на определения +интерфейсов, такие как определения интерфейсов реализованных каким-либо +классом. + +Одиночные адаптеры +================== + +Давайте рассмотрим простой пример использующий единственную требуемую +спецификацию:: + + >>> from zope.interface.adapter import AdapterRegistry + >>> import zope.interface + + >>> class IR1(zope.interface.Interface): + ... pass + >>> class IP1(zope.interface.Interface): + ... pass + >>> class IP2(IP1): + ... pass + + >>> registry = AdapterRegistry() + +Мы зарегистрируем объект который зависит от IR1 и "предоставляет" IP2:: + + >>> registry.register([IR1], IP2, '', 12) + +После регистрации мы можем запросить объект снова:: + + >>> registry.lookup([IR1], IP2, '') + 12 + +Заметьте, что мы используем целое в этом примере. В реальных приложениях вы +можете использовать объекты которые на самом деле зависят или предоставляют +интерфейсы. Реестр не заботиться о том, что регистрируется и таким образом мы +можем использовать целые, или строки что бы упростить наши примеры. Здесь есть +одно исключение. Регистрация значения None удаляет регистрацию для любого +зарегистрированного прежде значения. + +Если объект зависит от спецификации он может быть запрошен с помощью +спецификации которая расширяет спецификацию от которой он зависит:: + + >>> class IR2(IR1): + ... pass + >>> registry.lookup([IR2], IP2, '') + 12 + +Мы можем использовать класс реализующий спецификацию для запроса объекта:: + + >>> class C2: + ... zope.interface.implements(IR2) + + >>> registry.lookup([zope.interface.implementedBy(C2)], IP2, '') + 12 + +и объект может быть запрошен для интерфейсов которые предоставляемый объектом +интерфейс расширяет:: + + >>> registry.lookup([IR1], IP1, '') + 12 + >>> registry.lookup([IR2], IP1, '') + 12 + +Но если вы требуете спецификацию которая не расширяет спецификацию от которой +зависит объект, вы не получите ничего:: + + >>> registry.lookup([zope.interface.Interface], IP1, '') + +Между прочим, вы можете передать значение по умолчанию при запросе:: + + >>> registry.lookup([zope.interface.Interface], IP1, '', 42) + 42 + +Если вы пробуете получить интерфейс который объект не предоставляет вы также +не получите ничего:: + + >>> class IP3(IP2): + ... pass + >>> registry.lookup([IR1], IP3, '') + +Вы также не получите ничего если вы используете неверное имя:: + + >>> registry.lookup([IR1], IP1, 'bob') + >>> registry.register([IR1], IP2, 'bob', "Bob's 12") + >>> registry.lookup([IR1], IP1, 'bob') + "Bob's 12" + +Вы можете не использовать имя при запросе:: + + >>> registry.lookup([IR1], IP1) + 12 + +Если мы регистрируем объект который предоставляет IP1:: + + >>> registry.register([IR1], IP1, '', 11) + +тогда этот объект будет иметь преимущество перед O(12):: + + >>> registry.lookup([IR1], IP1, '') + 11 + +Также, если мы регистрируем объект для IR2 тогда он будет иметь преимущество +когда используется IR2:: + + >>> registry.register([IR2], IP1, '', 21) + >>> registry.lookup([IR2], IP1, '') + 21 + +Поиск того, что (если вообще что-то) зарегистрировано +----------------------------------------------------- + +Мы можем спросить есть-ли адаптер зарегистрированный для набора интерфейсов. +Это отличается от обычного запроса так как здесь мы ищем точное совпадение:: + + >>> print registry.registered([IR1], IP1) + 11 + + >>> print registry.registered([IR1], IP2) + 12 + + >>> print registry.registered([IR1], IP2, 'bob') + Bob's 12 + + + >>> print registry.registered([IR2], IP1) + 21 + + >>> print registry.registered([IR2], IP2) + None + +В последнем примере, None был возвращен потому, что для данного интерфейса +ничего не было зарегистрировано. + +lookup1 +------- + +Запрос одиночного адаптера - это наиболее частая операция и для нее есть +специализированная версия запроса которая получает на вход единственный +требуемый интерфейс:: + + >>> registry.lookup1(IR2, IP1, '') + 21 + >>> registry.lookup1(IR2, IP1) + 21 + +Адаптация на практике +--------------------- + +Реестр адаптеров предназначен для поддержки адаптации когда один объект +реализующий интерфейс адаптируется к другому объекту который поддерживает +другой интерфейс. Реестр адаптеров также поддерживает вычисление адаптеров. В +этом случае мы должны регистрировать фабрики для адаптеров:: + + >>> class IR(zope.interface.Interface): + ... pass + + >>> class X: + ... zope.interface.implements(IR) + + >>> class Y: + ... zope.interface.implements(IP1) + ... def __init__(self, context): + ... self.context = context + + >>> registry.register([IR], IP1, '', Y) + +В этом случае мы регистрируем класс как фабрику. Теперь мы можем вызвать +`queryAdapter` для получения адаптированного объекта:: + + >>> x = X() + >>> y = registry.queryAdapter(x, IP1) + >>> y.__class__.__name__ + 'Y' + >>> y.context is x + True + +Мы также можем регистрировать и запрашивать по имени:: + + >>> class Y2(Y): + ... pass + + >>> registry.register([IR], IP1, 'bob', Y2) + >>> y = registry.queryAdapter(x, IP1, 'bob') + >>> y.__class__.__name__ + 'Y2' + >>> y.context is x + True + +Когда фабрика для адаптера возвращает `None` - это рассматривается как если бы +адаптер не был найден. Это позволяет нам избежать адаптации (по желанию) и дает +возможность фабрике адаптера определить возможна ли адаптация основываясь на +состоянии объекта который адаптируется:: + + >>> def factory(context): + ... if context.name == 'object': + ... return 'adapter' + ... return None + + >>> class Object(object): + ... zope.interface.implements(IR) + ... name = 'object' + + >>> registry.register([IR], IP1, 'conditional', factory) + >>> obj = Object() + >>> registry.queryAdapter(obj, IP1, 'conditional') + 'adapter' + >>> obj.name = 'no object' + >>> registry.queryAdapter(obj, IP1, 'conditional') is None + True + >>> registry.queryAdapter(obj, IP1, 'conditional', 'default') + 'default' + +Альтернативный метод для предоставления такой же функциональности как и +`queryAdapter()` - это `adapter_hook()`:: + + >>> y = registry.adapter_hook(IP1, x) + >>> y.__class__.__name__ + 'Y' + >>> y.context is x + True + >>> y = registry.adapter_hook(IP1, x, 'bob') + >>> y.__class__.__name__ + 'Y2' + >>> y.context is x + True + +`adapter_hook()` просто меняет порядок аргументов для объекта и интерфейса. Это +используется для встраивания в механизм вызовов интерфейсов. + +Адаптеры по умолчанию +--------------------- + +Иногда вы можете захотеть предоставить адаптер который не будет ничего +адаптировать. Для этого нужно передать None как требуемый интерфейс:: + + >>> registry.register([None], IP1, '', 1) + +после этого вы можете использовать этот адаптер для интерфейсов для которых у +вас нет конкретного адаптера:: + + >>> class IQ(zope.interface.Interface): + ... pass + >>> registry.lookup([IQ], IP1, '') + 1 + +Конечно, конкретные адаптеры все еще используются когда необходимо:: + + >>> registry.lookup([IR2], IP1, '') + 21 + +Адаптеры классов +---------------- + +Вы можете регистрировать адаптеры для определений классов, что будет похоже на +регистрацию их для классов:: + + >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', 'C21') + >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') + 'C21' + +Адаптеры для словарей +--------------------- + +В какой-то момент было невозможно регистрировать адаптеры основанные на +словарях из-за ошибки. Давайте удостоверимся что это теперь работает:: + + >>> adapter = {} + >>> registry.register((), IQ, '', adapter) + >>> registry.lookup((), IQ, '') is adapter + True + +Удаление регистрации +-------------------- + +Вы можете удалить регистрацию регистрируя None вместо объекта:: + + >>> registry.register([zope.interface.implementedBy(C2)], IP1, '', None) + >>> registry.lookup([zope.interface.implementedBy(C2)], IP1, '') + 21 + +Конечно это значит, что None не может быть зарегистрирован. Это исключение к +утверждению выше о том, что реестр не заботиться о том, что регистрируется. + +Мульти-адаптеры +=============== + +Вы можете адаптировать несколько спецификаций:: + + >>> registry.register([IR1, IQ], IP2, '', '1q2') + >>> registry.lookup([IR1, IQ], IP2, '') + '1q2' + >>> registry.lookup([IR2, IQ], IP1, '') + '1q2' + + >>> class IS(zope.interface.Interface): + ... pass + >>> registry.lookup([IR2, IS], IP1, '') + + >>> class IQ2(IQ): + ... pass + + >>> registry.lookup([IR2, IQ2], IP1, '') + '1q2' + + >>> registry.register([IR1, IQ2], IP2, '', '1q22') + >>> registry.lookup([IR2, IQ2], IP1, '') + '1q22' + +Мульти-адаптация +---------------- + +Вы можете адаптировать несколько объектов:: + + >>> class Q: + ... zope.interface.implements(IQ) + +Как и с одиночными адаптерами, мы регистрируем фабрику которая возвращает +класс:: + + >>> class IM(zope.interface.Interface): + ... pass + >>> class M: + ... zope.interface.implements(IM) + ... def __init__(self, x, q): + ... self.x, self.q = x, q + >>> registry.register([IR, IQ], IM, '', M) + +И затем мы можем вызвать `queryMultiAdapter` для вычисления адаптера:: + + >>> q = Q() + >>> m = registry.queryMultiAdapter((x, q), IM) + >>> m.__class__.__name__ + 'M' + >>> m.x is x and m.q is q + True + +и, конечно, мы можем использовать имена:: + + >>> class M2(M): + ... pass + >>> registry.register([IR, IQ], IM, 'bob', M2) + >>> m = registry.queryMultiAdapter((x, q), IM, 'bob') + >>> m.__class__.__name__ + 'M2' + >>> m.x is x and m.q is q + True + +Адаптеры по умолчанию +--------------------- + +Как и для одиночных адаптеров вы можете определить адаптер по умолчанию передав +None вместо *первой* спецификации:: + + >>> registry.register([None, IQ], IP2, '', 'q2') + >>> registry.lookup([IS, IQ], IP2, '') + 'q2' + +Нулевые адаптеры +================ + +Вы можете также адаптировать без спецификации:: + + >>> registry.register([], IP2, '', 2) + >>> registry.lookup([], IP2, '') + 2 + >>> registry.lookup([], IP1, '') + 2 + +Перечисление именованных адаптеров +---------------------------------- + +Адаптеры имеют имена. Иногда это полезно для получения всех именованных +адаптеров для заданного интерфейса:: + + >>> adapters = list(registry.lookupAll([IR1], IP1)) + >>> adapters.sort() + >>> adapters + [(u'', 11), (u'bob', "Bob's 12")] + +Это работает также и для мульти-адаптеров:: + + >>> registry.register([IR1, IQ2], IP2, 'bob', '1q2 for bob') + >>> adapters = list(registry.lookupAll([IR2, IQ2], IP1)) + >>> adapters.sort() + >>> adapters + [(u'', '1q22'), (u'bob', '1q2 for bob')] + +И даже для нулевых адаптеров:: + + >>> registry.register([], IP2, 'bob', 3) + >>> adapters = list(registry.lookupAll([], IP1)) + >>> adapters.sort() + >>> adapters + [(u'', 2), (u'bob', 3)] + +Подписки +======== + +Обычно мы хотим запросить объект который наиболее близко соответствует +спецификации. Иногда мы хотим получить все объекты которые соответствуют +какой-либо спецификации. Мы используем подписки для этого. Мы подписываем +объекты для спецификаций и затем позже находим все подписанные объекты:: + + >>> registry.subscribe([IR1], IP2, 'sub12 1') + >>> registry.subscriptions([IR1], IP2) + ['sub12 1'] + +Заметьте, что в отличие от обычных адаптеров подписки не имеют имен. + +Вы можете иметь несколько подписчиков для одной спецификации:: + + >>> registry.subscribe([IR1], IP2, 'sub12 2') + >>> registry.subscriptions([IR1], IP2) + ['sub12 1', 'sub12 2'] + +Если подписчики зарегистрированы для одних и тех же требуемых интерфейсов, они +возвращаются в порядке определения. + +Вы можете зарегистрировать подписчики для всех спецификаций используя None:: + + >>> registry.subscribe([None], IP1, 'sub_1') + >>> registry.subscriptions([IR2], IP1) + ['sub_1', 'sub12 1', 'sub12 2'] + +Заметьте, что новый подписчик возвращается первым. Подписчики определенные +для менее общих требуемых интерфейсов возвращаются перед подписчиками +для более общих интерфейсов. + +Подписки могут смешиваться между несколькими совместимыми спецификациями:: + + >>> registry.subscriptions([IR2], IP1) + ['sub_1', 'sub12 1', 'sub12 2'] + >>> registry.subscribe([IR1], IP1, 'sub11') + >>> registry.subscriptions([IR2], IP1) + ['sub_1', 'sub12 1', 'sub12 2', 'sub11'] + >>> registry.subscribe([IR2], IP2, 'sub22') + >>> registry.subscriptions([IR2], IP1) + ['sub_1', 'sub12 1', 'sub12 2', 'sub11', 'sub22'] + >>> registry.subscriptions([IR2], IP2) + ['sub12 1', 'sub12 2', 'sub22'] + +Подписки могут существовать для нескольких спецификаций:: + + >>> registry.subscribe([IR1, IQ], IP2, 'sub1q2') + >>> registry.subscriptions([IR1, IQ], IP2) + ['sub1q2'] + +Как и с одиночными подписчиками и адаптерами без подписок, вы можете определить +None для первого требуемого интерфейса, что бы задать значение по умолчанию:: + + >>> registry.subscribe([None, IQ], IP2, 'sub_q2') + >>> registry.subscriptions([IS, IQ], IP2) + ['sub_q2'] + >>> registry.subscriptions([IR1, IQ], IP2) + ['sub_q2', 'sub1q2'] + +Вы можете создать подписки которые независимы от любых спецификаций:: + + >>> list(registry.subscriptions([], IP1)) + [] + + >>> registry.subscribe([], IP2, 'sub2') + >>> registry.subscriptions([], IP1) + ['sub2'] + >>> registry.subscribe([], IP1, 'sub1') + >>> registry.subscriptions([], IP1) + ['sub2', 'sub1'] + >>> registry.subscriptions([], IP2) + ['sub2'] + +Удаление регистрации подписчиков +-------------------------------- + +Мы можем удалять регистрацию подписчиков. При удалении регистрации подписчика +мы можем удалить регистрацию заданного адаптера:: + + >>> registry.unsubscribe([IR1], IP1, 'sub11') + >>> registry.subscriptions([IR1], IP1) + ['sub_1', 'sub12 1', 'sub12 2'] + +Если мы не задаем никакого значения тогда подписки будут удалены для всех +подписчиков совпадающих с заданным интерфейсом:: + + >>> registry.unsubscribe([IR1], IP2) + >>> registry.subscriptions([IR1], IP1) + ['sub_1'] + +Адаптеры подписки +----------------- + +Обычно мы регистрируем фабрики для адаптеров которые затем позволяют нам +вычислять адаптеры, но с подписками мы получаем несколько адаптеров. Это пример +подписчика для нескольких объектов:: + + >>> registry.subscribe([IR, IQ], IM, M) + >>> registry.subscribe([IR, IQ], IM, M2) + + >>> subscribers = registry.subscribers((x, q), IM) + >>> len(subscribers) + 2 + >>> class_names = [s.__class__.__name__ for s in subscribers] + >>> class_names.sort() + >>> class_names + ['M', 'M2'] + >>> [(s.x is x and s.q is q) for s in subscribers] + [True, True] + +подписчики фабрик адаптеров не могут возвращать None:: + + >>> def M3(x, y): + ... return None + + >>> registry.subscribe([IR, IQ], IM, M3) + >>> subscribers = registry.subscribers((x, q), IM) + >>> len(subscribers) + 2 + +Обработчики +----------- + +Обработчик - это подписанная фабрика которая не возвращает нормального +значения. Она возвращает None. Обработчик отличается от адаптеров тем, что он +делает всю работу когда вызывается фабрика. + +Для регистрации обработчика надо просто передать None как предоставляемый +интерфейс:: + + >>> def handler(event): + ... print 'handler', event + + >>> registry.subscribe([IR1], None, handler) + >>> registry.subscriptions([IR1], None) == [handler] + True diff --git a/src/zope/interface/adapter.txt b/src/zope/interface/adapter.txt index c065475..1ad6c4e 100644 --- a/src/zope/interface/adapter.txt +++ b/src/zope/interface/adapter.txt @@ -436,7 +436,7 @@ You can register subscribers for all specifications using None:: ['sub_1', 'sub12 1', 'sub12 2'] Note that the new subscriber is returned first. Subscribers defined -for more general required interfaces are returned before subscribers +for less general required interfaces are returned before subscribers for more general interfaces. Subscriptions may be combined over multiple compatible specifications:: @@ -485,7 +485,7 @@ Unregistering subscribers ------------------------- We can unregister subscribers. When unregistering a subscriber, we -can unregister a specific subscriber: +can unregister a specific subscriber:: >>> registry.unsubscribe([IR1], IP1, 'sub11') >>> registry.subscriptions([IR1], IP1) @@ -519,7 +519,7 @@ example of multiple-object subscribers:: >>> [(s.x is x and s.q is q) for s in subscribers] [True, True] -adapter factory subcribers can't return None values +adapter factory subcribers can't return None values:: >>> def M3(x, y): ... return None diff --git a/src/zope/interface/tests/test_adapter.py b/src/zope/interface/tests/test_adapter.py index 33fb5e1..ee457c2 100644 --- a/src/zope/interface/tests/test_adapter.py +++ b/src/zope/interface/tests/test_adapter.py @@ -347,8 +347,9 @@ def test_register_objects_with_cmp(): def test_suite(): from zope.testing import doctest, doctestunit return unittest.TestSuite(( - doctestunit.DocFileSuite('../adapter.txt', '../human.txt', - '../human.ru.txt', 'foodforthought.txt', + doctestunit.DocFileSuite('../adapter.txt', '../adapter.ru.txt', + '../human.txt', '../human.ru.txt', + 'foodforthought.txt', globs={'__name__': '__main__'}), doctest.DocTestSuite(), )) |
