summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2009-01-04 07:40:06 (GMT)
committerSteven Knight <knight@baldmt.com>2009-01-04 07:40:06 (GMT)
commita46317bc7a48afe35b6d591146d231871837a5ae (patch)
tree07195185dce4de3b16a09de1b9aa339a6d733fa7
parenta35f5af91bb55f3f522a92a0927a4567d8bbfafa (diff)
downloadSCons-a46317bc7a48afe35b6d591146d231871837a5ae.zip
SCons-a46317bc7a48afe35b6d591146d231871837a5ae.tar.gz
SCons-a46317bc7a48afe35b6d591146d231871837a5ae.tar.bz2
Simplify how NodeLists expand callable methods by making the NodeList
class itself callable, instead of relying on a subsidiary CallableComposite class for that behavior.
-rw-r--r--src/engine/SCons/Util.py36
-rw-r--r--src/engine/SCons/UtilTests.py74
2 files changed, 63 insertions, 47 deletions
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index b47e262..cbec5dd 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -107,18 +107,6 @@ def updrive(path):
path = string.upper(drive) + rest
return path
-class CallableComposite(UserList):
- """A simple composite callable class that, when called, will invoke all
- of its contained callables with the same arguments."""
- def __call__(self, *args, **kwargs):
- retvals = map(lambda x, args=args, kwargs=kwargs: apply(x,
- args,
- kwargs),
- self.data)
- if self.data and (len(self.data) == len(filter(callable, retvals))):
- return self.__class__(retvals)
- return NodeList(retvals)
-
class NodeList(UserList):
"""This class is almost exactly like a regular list of Nodes
(actually it can hold any object), with one important difference.
@@ -135,18 +123,20 @@ class NodeList(UserList):
def __str__(self):
return string.join(map(str, self.data))
+ def __iter__(self):
+ return iter(self.data)
+
+ def __call__(self, *args, **kwargs):
+ result = map(lambda x, args=args, kwargs=kwargs: apply(x,
+ args,
+ kwargs),
+ self.data)
+ return self.__class__(result)
+
def __getattr__(self, name):
- # Return a list of the attribute, gotten from every element
- # in the list
- attrList = map(lambda x, n=name: getattr(x, n), self.data)
-
- # Special case. If the attribute is callable, we do not want
- # to return a list of callables. Rather, we want to return a
- # single callable that, when called, will invoke the function on
- # all elements of this list.
- if self.data and (len(self.data) == len(filter(callable, attrList))):
- return CallableComposite(attrList)
- return self.__class__(attrList)
+ result = map(lambda x, n=name: getattr(x, n), self.data)
+ return self.__class__(result)
+
_get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index a27f8c3..483591f 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -494,30 +494,6 @@ class UtilTestCase(unittest.TestCase):
p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
- def test_NodeList(self):
- """Test NodeList class"""
- class TestClass:
- def __init__(self, name, child=None):
- self.child = child
- self.bar = name
- def foo(self):
- return self.bar + "foo"
- def getself(self):
- return self
-
- t1 = TestClass('t1', TestClass('t1child'))
- t2 = TestClass('t2', TestClass('t2child'))
- t3 = TestClass('t3')
-
- nl = NodeList([t1, t2, t3])
- assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
- assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
- assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
- assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
- nl[0:2].child.foo()
- assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
- nl[0:2].child.bar
-
def test_CLVar(self):
"""Test the command-line construction variable class"""
f = SCons.Util.CLVar('a b')
@@ -738,6 +714,55 @@ class MD5TestCase(unittest.TestCase):
s = MD5signature('222')
assert 'bcbe3365e6ac95ea2c0343a2395834dd' == s, s
+class NodeListTestCase(unittest.TestCase):
+ def test_simple_attributes(self):
+ """Test simple attributes of a NodeList class"""
+ class TestClass:
+ def __init__(self, name, child=None):
+ self.child = child
+ self.bar = name
+
+ t1 = TestClass('t1', TestClass('t1child'))
+ t2 = TestClass('t2', TestClass('t2child'))
+ t3 = TestClass('t3')
+
+ nl = NodeList([t1, t2, t3])
+ assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
+ assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
+ nl[0:2].child.bar
+
+ def test_callable_attributes(self):
+ """Test callable attributes of a NodeList class"""
+ class TestClass:
+ def __init__(self, name, child=None):
+ self.child = child
+ self.bar = name
+ def foo(self):
+ return self.bar + "foo"
+ def getself(self):
+ return self
+
+ t1 = TestClass('t1', TestClass('t1child'))
+ t2 = TestClass('t2', TestClass('t2child'))
+ t3 = TestClass('t3')
+
+ nl = NodeList([t1, t2, t3])
+ assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
+ assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
+ assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
+ assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
+ nl[0:2].child.foo()
+ assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
+ nl[0:2].child.bar
+
+ def test_null(self):
+ """Test a null NodeList"""
+ nl = NodeList([])
+ r = str(nl)
+ assert r == '', r
+ for node in nl:
+ raise Exception, "should not enter this loop"
+
class flattenTestCase(unittest.TestCase):
@@ -751,6 +776,7 @@ if __name__ == "__main__":
tclasses = [ dictifyTestCase,
flattenTestCase,
MD5TestCase,
+ NodeListTestCase,
UtilTestCase,
]
for tclass in tclasses: