~divmod-dev/divmod.org/trunk

« back to all changes in this revision

Viewing changes to Epsilon/epsilon/modal.py

  • Committer: Jean-Paul Calderone
  • Date: 2014-06-29 20:33:04 UTC
  • mfrom: (2749.1.1 remove-epsilon-1325289)
  • Revision ID: exarkun@twistedmatrix.com-20140629203304-gdkmbwl1suei4m97
mergeĀ lp:~exarkun/divmod.org/remove-epsilon-1325289

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- test-case-name: epsilon.test.test_modes -*-
2
 
 
3
 
import new
4
 
 
5
 
class ModalMethod(object):
6
 
    """A descriptor wrapping multiple implementations of a particular method.
7
 
 
8
 
    When called on an instance, the implementation used will be
9
 
    selected based on an attribute of the instance.  There are no
10
 
    unbound ModalMethods at this point.
11
 
 
12
 
    @ivar name: The name of this method.
13
 
    @ivar methods: A mapping of modes to callable objects.
14
 
 
15
 
    @ivar modeAttribute: The name of the attribute on instances which
16
 
    is bound to the instance's current mode.
17
 
    """
18
 
 
19
 
    def __init__(self, name, methods, modeAttribute):
20
 
        self.name = name
21
 
        self.methods = methods
22
 
        self.modeAttribute = modeAttribute
23
 
 
24
 
    def __get__(self, instance, owner):
25
 
        if instance is None:
26
 
            raise AttributeError(self.name)
27
 
        try:
28
 
            mode = getattr(instance, self.modeAttribute)
29
 
        except AttributeError:
30
 
            raise AttributeError(
31
 
                "Mode attribute %r missing from %r, "
32
 
                "cannot get %r" % (self.modeAttribute, instance, self.name))
33
 
 
34
 
        try:
35
 
            func = self.methods[mode]
36
 
        except KeyError:
37
 
            raise AttributeError(
38
 
                "Method %r missing from mode %r on %r" % (self.name, mode, instance))
39
 
 
40
 
        return new.instancemethod(func, instance, owner)
41
 
 
42
 
class mode(object):
43
 
    """
44
 
    Base class for mode definitions.  Subclass this in classes of type
45
 
    ModalType and provide the implementations of various methods for
46
 
    that particular mode as methods of the mode subclass.  The
47
 
    subclass should have the same name as the mode it is defining.
48
 
    """
49
 
 
50
 
    # XXX fix the simple, but wrong, __dict__ magic in ModalType.__new__ so
51
 
    # that this __enter__ and __exit__ are actually called, maybe we can even
52
 
    # do some logging or something.
53
 
 
54
 
    def __exit__(self):
55
 
        """
56
 
        The mode has just been exited.
57
 
        """
58
 
 
59
 
    def __enter__(self):
60
 
        """
61
 
        The mode has just been entered.
62
 
        """
63
 
 
64
 
def _getInheritedAttribute(classname, attrname, bases, attrs):
65
 
    try:
66
 
        return attrs[attrname]
67
 
    except KeyError:
68
 
        for base in bases:
69
 
            try:
70
 
                return _getInheritedAttribute(classname, attrname,
71
 
                                              base.__bases__,
72
 
                                              base.__dict__)
73
 
            except TypeError:
74
 
                pass
75
 
        else:
76
 
            raise TypeError('%r does not define required attribute %r' %
77
 
                            (classname,
78
 
                             attrname))
79
 
 
80
 
 
81
 
 
82
 
class ModalType(type):
83
 
    """Metaclass for defining modal classes.
84
 
 
85
 
    @type modeAttribute: C{str}
86
 
    @ivar modeAttribute: The attribute to which the current mode is
87
 
    bound.  Classes should not define the attribute this names; it
88
 
    will be bound automatically to the value of initialMode.
89
 
 
90
 
    @type initialMode: C{str} (for now)
91
 
    @ivar initialMode: The mode in which instances will start.
92
 
    """
93
 
    def __new__(cls, name, bases, attrs):
94
 
        modeAttribute = _getInheritedAttribute(name, 'modeAttribute', bases, attrs)
95
 
        initialMode = attrs['initialMode'] = _getInheritedAttribute(name, 'initialMode', bases, attrs)
96
 
 
97
 
        # Dict mapping names of methods to another dict.  The inner
98
 
        # dict maps names of modes to implementations of that method
99
 
        # for that mode.
100
 
        implementations = {}
101
 
 
102
 
        keepAttrs = {'mode': initialMode}
103
 
        for (k, v) in attrs.iteritems():
104
 
            if isinstance(v, type) and issubclass(v, mode):
105
 
                for (methName, methDef) in v.__dict__.iteritems():
106
 
                    if methName not in ('__module__', '__file__', '__name__'):
107
 
                        implementations.setdefault(methName, {})[k] = methDef
108
 
            keepAttrs[k] = v
109
 
 
110
 
        for (methName, methDefs) in implementations.iteritems():
111
 
            keepAttrs[methName] = ModalMethod(methName, methDefs, modeAttribute)
112
 
 
113
 
        return super(ModalType, cls).__new__(cls, name, bases, keepAttrs)
114
 
 
115
 
class Modal(object):
116
 
 
117
 
    __metaclass__ = ModalType
118
 
    modeAttribute = 'mode'
119
 
    initialMode = 'nil'
120
 
 
121
 
    class nil(mode):
122
 
        def __enter__(self):
123
 
            pass
124
 
        def __exit__(self):
125
 
            pass
126
 
 
127
 
    def transitionTo(self, stateName):
128
 
        self.__exit__()
129
 
        self.mode = stateName
130
 
        self.__enter__()
131