1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
import unittest
import mop
# in a real implementation, we'd add more functionality to the mop itself to
# allow for calling superclass methods, but that would be complicated enough to
# obscure the implementation and make it not as easy to follow (we would have
# to manage call stacks ourselves), and so we just do this instead for now
def call_method_at_class(c, method_name, invocant, *args, **kwargs):
return c.get_all_methods()[method_name].slots["body"](
invocant, *args, **kwargs
)
class SimpleOverridesTest(unittest.TestCase):
def test_accessor_generation(self):
AccessorsMetaclass = mop.Class.new(
name="AccessorsMetaclass",
superclass=mop.Class,
)
def add_attribute(self, attr):
name = attr.get_name()
call_method_at_class(mop.Class, "add_attribute", self, attr)
self.add_method(self.method_class().new(
name=name,
body=lambda self: self.metaclass.get_all_attributes()[name].get_value(self),
))
AccessorsMetaclass.add_method(AccessorsMetaclass.metaclass.method_class().new(
name="add_attribute",
body=add_attribute,
))
AccessorsMetaclass.finalize()
Point = AccessorsMetaclass.new(
name="Point",
superclass=AccessorsMetaclass.base_object_class(),
)
Point.add_attribute(Point.attribute_class().new(name="x", default=0))
Point.add_attribute(Point.attribute_class().new(name="y", default=0))
Point.finalize()
point = Point.new(x=1, y=2)
assert point.x() == 1
assert point.y() == 2
def test_trace_method_calls(self):
methods_called = []
TraceMethod = mop.Class.new(
name="TraceMethod",
superclass=mop.Method,
)
def execute(self, invocant, args, kwargs):
methods_called.append(self.get_name())
return call_method_at_class(mop.Method, "execute", self, invocant, args, kwargs)
TraceMethod.add_method(TraceMethod.metaclass.method_class().new(
name="execute",
body=execute,
))
TraceMethod.finalize()
TraceClass = mop.Class.new(
name="TraceClass",
superclass=mop.Class,
)
TraceClass.add_method(TraceClass.metaclass.method_class().new(
name="method_class",
body=lambda self: TraceMethod,
))
TraceClass.finalize()
Point = TraceClass.new(
name="Point",
superclass=TraceClass.base_object_class(),
)
Point.add_attribute(Point.attribute_class().new(name="x", default=0))
Point.add_attribute(Point.attribute_class().new(name="y", default=0))
Point.add_method(Point.method_class().new(
name="x",
body=lambda self: self.metaclass.get_all_attributes()["x"].get_value(self)
))
Point.add_method(Point.method_class().new(
name="y",
body=lambda self: self.metaclass.get_all_attributes()["y"].get_value(self)
))
Point.finalize()
point = Point.new(x=1, y=2)
assert methods_called == []
assert point.x() == 1
assert methods_called == ['x']
assert point.y() == 2
assert methods_called == ['x', 'y']
|