Refactor DictCmdGenerator to be a subclass of Selector.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Mon, 18 Aug 2003 05:31:42 +0000 (05:31 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Mon, 18 Aug 2003 05:31:42 +0000 (05:31 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@772 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Builder.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py

index 375bb81fea440d3aaad7e03e3eb7a96a301554dd..a990f934ff7949ac7a1a790e4b4f9acaeacdd4ad 100644 (file)
@@ -14,6 +14,10 @@ RELEASE X.XX - XXX, XX XXX XXXX XX:XX:XX XXXXX
 
   - Fix Tool import problems with the Intel and PharLap linkers.
 
+  From Steven Knight
+
+  - Refactor the DictCmdGenerator class to be a Selector subclass.
+
   From Gerard Patel
 
   - When the yacc -d flag is used, take the .h file base name from the
index f7630e63e3cefee1b73585d1545f489fa0d0e0be..af03e82360708c758f567aea04dc6879de3bd30b 100644 (file)
@@ -59,23 +59,20 @@ class _Null:
 
 _null = _Null
 
-class DictCmdGenerator:
+class DictCmdGenerator(SCons.Util.Selector):
     """This is a callable class that can be used as a
     command generator function.  It holds on to a dictionary
     mapping file suffixes to Actions.  It uses that dictionary
     to return the proper action based on the file suffix of
     the source file."""
-    
-    def __init__(self, action_dict):
-        self.action_dict = action_dict
 
     def src_suffixes(self):
-        return self.action_dict.keys()
+        return self.keys()
 
     def add_action(self, suffix, action):
         """Add a suffix-action pair to the mapping.
         """
-        self.action_dict[suffix] = action
+        self[suffix] = action
 
     def __call__(self, target, source, env, for_signature):
         ext = None
@@ -87,62 +84,25 @@ class DictCmdGenerator:
 
         if not ext:
             raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source))))
-        try:
-            return self.action_dict[ext]
-        except KeyError:
-            # Before raising the user error, try to perform Environment
-            # substitution on the keys of action_dict.
-            s_dict = {}
-            for (k,v) in self.action_dict.items():
-                s_k = env.subst(k)
-                if s_dict.has_key(s_k):
-                    # XXX Note that we do only raise errors, when variables
-                    # point to the same suffix. If one suffix is a
-                    # literal and a variable suffix contains this literal
-                    # we don't raise an error (cause the literal 'wins')
-                    raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (s_dict[s_k][0], k, s_k))
-                s_dict[s_k] = (k,v)
-            try:
-                return s_dict[ext][1]
-            except KeyError:
-                raise UserError("While building `%s': Don't know how to build a file with suffix %s." % (repr(map(str, target)), repr(ext)))
 
-    def __cmp__(self, other):
-        return cmp(self.action_dict, other.action_dict)
-
-class Selector(UserDict.UserDict):
-    """A callable dictionary that maps file suffixes to dictionary
-    values."""
-    def __call__(self, env, source):
-        ext = SCons.Util.splitext(str(source[0]))[1]
         try:
-            return self[ext]
-        except KeyError:
-            # Try to perform Environment substitution on the keys of
-            # emitter_dict before giving up.
-            s_dict = {}
-            for (k,v) in self.items():
-                if not k is None:
-                    s_k = env.subst(k)
-                    s_dict[s_k] = v
-            try:
-                return s_dict[ext]
-            except KeyError:
-                try:
-                    return self[None]
-                except KeyError:
-                    return None
+            ret = SCons.Util.Selector.__call__(self, env, source)
+        except KeyError, e:
+            raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[2]))
+        if ret is None:
+            raise UserError("While building `%s': Don't know how to build a file with suffix `%s'." % (repr(map(str, target)), ext))
+        return ret
 
-class CallableSelector(Selector):
-    """A callable dictionary that wills, in turn, call the value it
+class CallableSelector(SCons.Util.Selector):
+    """A callable dictionary that will, in turn, call the value it
     finds if it can."""
     def __call__(self, env, source):
-        value = Selector.__call__(self, env, source)
+        value = SCons.Util.Selector.__call__(self, env, source)
         if callable(value):
             value = value(env, source)
         return value
 
-class DictEmitter(Selector):
+class DictEmitter(SCons.Util.Selector):
     """A callable dictionary that maps file suffixes to emitters.
     When called, it finds the right emitter in its dictionary for the
     suffix of the first source file, and calls that emitter to get the
@@ -151,7 +111,7 @@ class DictEmitter(Selector):
     returned.
     """
     def __call__(self, target, source, env):
-        emitter = Selector.__call__(self, env, source)
+        emitter = SCons.Util.Selector.__call__(self, env, source)
         if emitter:
             target, source = emitter(target, source, env)
         return (target, source)
@@ -188,7 +148,7 @@ def Builder(**kw):
     else:
         ret = apply(BuilderBase, (), kw)
 
-    if composite:
+    if not composite is None:
         ret = CompositeBuilder(ret, composite)
 
     return ret
index f65230ca7386dad7490be8d064f8ca5f46d72938..e0ba2febe8060229b92fd2f40ad80978b20661d8 100644 (file)
@@ -700,7 +700,7 @@ class BuilderTestCase(unittest.TestCase):
         except SCons.Errors.UserError, e:
             flag = 1
         assert flag, "UserError should be thrown when we build targets with files of different suffixes."
-        match = str(e) == "While building `['t8']': Don't know how to build a file with suffix '.unknown'."
+        match = str(e) == "While building `['t8']': Don't know how to build a file with suffix `.unknown'."
         assert match, e
 
     def test_build_scanner(self):
index cba61e5ec09a041167a849fe0946cc3ac2b7d4a4..3d3f563bdde54b593954dce18aec99b0b527c9a1 100644 (file)
@@ -1006,3 +1006,32 @@ else:
         return path
 
 display = DisplayEngine()
+
+class Selector(UserDict.UserDict):
+    """A callable dictionary that maps file suffixes to dictionary
+    values."""
+    def __call__(self, env, source):
+        ext = splitext(str(source[0]))[1]
+        try:
+            return self[ext]
+        except KeyError:
+            # Try to perform Environment substitution on the keys of
+            # emitter_dict before giving up.
+            s_dict = {}
+            for (k,v) in self.items():
+                if not k is None:
+                    s_k = env.subst(k)
+                    if s_dict.has_key(s_k):
+                        # We only raise an error when variables point
+                        # to the same suffix.  If one suffix is literal
+                        # and a variable suffix contains this literal,
+                        # the literal wins and we don't raise an error.
+                        raise KeyError, (s_dict[s_k][0], k, s_k)
+                    s_dict[s_k] = (k,v)
+            try:
+                return s_dict[ext][1]
+            except KeyError:
+                try:
+                    return self[None]
+                except KeyError:
+                    return None
index b7b41be06bff93850c56c0550602cada5f204da0..23120e6163c3a140210d469b2b61267a78bd0ce8 100644 (file)
@@ -863,6 +863,48 @@ class UtilTestCase(unittest.TestCase):
         assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
                nl[0:2].child.bar
 
+    def test_Selector(self):
+        """Test the Selector class"""
+
+        s = Selector({'a' : 'AAA', 'b' : 'BBB'})
+        assert s['a'] == 'AAA', s['a']
+        assert s['b'] == 'BBB', s['b']
+        exc_caught = None
+        try:
+            x = s['c']
+        except KeyError:
+            exc_caught = 1
+        assert exc_caught, "should have caught a KeyError"
+        s['c'] = 'CCC'
+        assert s['c'] == 'CCC', s['c']
+
+        class DummyEnv(UserDict.UserDict):
+            def subst(self, key):
+                if key[0] == '$':
+                    return self[key[1:]]
+                return key
+
+        env = DummyEnv()
+
+        s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
+        ret = s(env, ['foo.d'])
+        assert ret == 'DDD', ret
+        ret = s(env, ['bar.e'])
+        assert ret == 'EEE', ret
+        ret = s(env, ['bar.x'])
+        assert ret == None, ret
+        s[None] = 'XXX'
+        ret = s(env, ['bar.x'])
+        assert ret == 'XXX', ret
+
+        env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
+
+        s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
+        ret = s(env, ['foo.f'])
+        assert ret == 'FFF', ret
+        ret = s(env, ['bar.g'])
+        assert ret == 'GGG', ret
+
 if __name__ == "__main__":
     suite = unittest.makeSuite(UtilTestCase, 'test_')
     if not unittest.TextTestRunner().run(suite).wasSuccessful():