changeset 411:3fb050ad01ae

More plural module cleanup and fixes.
author cmlenz
date Mon, 25 Aug 2008 11:49:19 +0000
parents be5e0f69137b
children ea0da9db79ef
files babel/plural.py babel/tests/__init__.py babel/tests/plural.py
diffstat 3 files changed, 70 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/babel/plural.py
+++ b/babel/plural.py
@@ -19,18 +19,21 @@
 except NameError:
     from sets import ImmutableSet as frozenset, Set as set
 
+__all__ = ['PluralRule', 'RuleError', 'to_gettext', 'to_javascript',
+           'to_python']
+__docformat__ = 'restructuredtext en'
+
 
 _plural_tags = ('zero', 'one', 'two', 'few', 'many', 'other')
 _fallback_tag = 'other'
 
 
 class PluralRule(object):
-    """Represents a CLDR language pluralization rules.  The constructors
-    accepts a list of (tag, expr) tuples or a dict of CLDR rules.
-    The resulting object is callable and accepts one parameter with a
-    positive or negative number (both integer and float) for the number
-    that indicates the plural form for a string and returns the tag for
-    the format:
+    """Represents a set of language pluralization rules.  The constructor
+    accepts a list of (tag, expr) tuples or a dict of CLDR rules. The
+    resulting object is callable and accepts one parameter with a positive or
+    negative number (both integer and float) for the number that indicates the
+    plural form for a string and returns the tag for the format:
 
     >>> rule = PluralRule({'one': 'n is 1'})
     >>> rule(1)
@@ -42,16 +45,18 @@
     other where other is an implicit default.  Rules should be mutually
     exclusive; for a given numeric value, only one rule should apply (i.e.
     the condition should only be true for one of the plural rule elements.
-
-    :param rules: a list of ``(tag, expr)``) tuples with the rules conforming
-                  to UTS #35 or a dict with the tags as keys and expressions
-                  as values.
-    :raise: a `RuleError` if the expression is malformed
     """
 
     __slots__ = ('abstract', '_func')
 
     def __init__(self, rules):
+        """Initialize the rule instance.
+
+        :param rules: a list of ``(tag, expr)``) tuples with the rules
+                      conforming to UTS #35 or a dict with the tags as keys
+                      and expressions as values.
+        :raise RuleError: if the expression is malformed
+        """
         if isinstance(rules, dict):
             rules = rules.items()
         found = set()
@@ -86,29 +91,16 @@
     parse = classmethod(parse)
 
     def rules(self):
-        """The `PluralRule` as a dict of unicode plural rules."""
+        """The `PluralRule` as a dict of unicode plural rules.
+        
+        >>> rule = PluralRule({'one': 'n is 1'})
+        >>> rule.rules
+        {'one': 'n is 1'}
+        """
         _compile = _UnicodeCompiler().compile
         return dict([(tag, _compile(ast)) for tag, ast in self.abstract])
     rules = property(rules, doc=rules.__doc__)
 
-    def gettext_expr(self):
-        """The plural rule as gettext expression.  The gettext expression is
-        technically limited to integers and returns indices rather than tags.
-
-        >>> PluralRule({'one': 'n is 1', 'two': 'n is 2'}).gettext_expr
-        'nplurals=3; plural=((n == 2) ? 1 : (n == 1) ? 0 : 2)'
-        """
-        used_tags = self.tags | set([_fallback_tag])
-        _compile = _GettextCompiler().compile
-        _get_index = [tag for tag in _plural_tags if tag in used_tags].index
-
-        result = ['nplurals=%d; plural=(' % len(used_tags)]
-        for tag, ast in self.abstract:
-            result.append('%s ? %d : ' % (_compile(ast), _get_index(tag)))
-        result.append('%d)' % _get_index(_fallback_tag))
-        return ''.join(result)
-    gettext_expr = property(gettext_expr, doc=gettext_expr.__doc__)
-
     tags = property(lambda x: frozenset([i[0] for i in x.abstract]), doc="""
         A set of explicitly defined tags in this rule.  The implicit default
         ``'other'`` rules is not part of this set unless there is an explicit
@@ -138,7 +130,7 @@
     advantage that external helper functions are not required and is not a
     big performance hit for these simple calculations.
 
-    :param rules: the rules as list or dict, or a `PluralRule` object
+    :param rule: the rules as list or dict, or a `PluralRule` object
     :return: a corresponding JavaScript function as `str`
     :raise RuleError: if the expression is malformed
     """
@@ -161,7 +153,7 @@
     >>> func(3)
     'few'
 
-    :param rules: the rules as list or dict, or a `PluralRule` object
+    :param rule: the rules as list or dict, or a `PluralRule` object
     :return: a corresponding Python function
     :raise RuleError: if the expression is malformed
     """
@@ -172,7 +164,7 @@
     }
     to_python = _PythonCompiler().compile
     result = ['def evaluate(n):']
-    for tag, ast in rule.abstract:
+    for tag, ast in PluralRule.parse(rule).abstract:
         result.append(' if (%s): return %r' % (to_python(ast), tag))
     result.append(' return %r' % _fallback_tag)
     exec '\n'.join(result) in namespace
@@ -185,8 +177,22 @@
 
     >>> to_gettext({'one': 'n is 1', 'two': 'n is 2'})
     'nplurals=3; plural=((n == 2) ? 1 : (n == 1) ? 0 : 2)'
+
+    :param rule: the rules as list or dict, or a `PluralRule` object
+    :return: an equivalent gettext-style plural expression
+    :raise RuleError: if the expression is malformed
     """
-    return PluralRule.parse(rule).gettext_expr
+    rule = PluralRule.parse(rule)
+
+    used_tags = rule.tags | set([_fallback_tag])
+    _compile = _GettextCompiler().compile
+    _get_index = [tag for tag in _plural_tags if tag in used_tags].index
+
+    result = ['nplurals=%d; plural=(' % len(used_tags)]
+    for tag, ast in rule.abstract:
+        result.append('%s ? %d : ' % (_compile(ast), _get_index(tag)))
+    result.append('%d)' % _get_index(_fallback_tag))
+    return ''.join(result)
 
 
 def in_range(num, min, max):
--- a/babel/tests/__init__.py
+++ b/babel/tests/__init__.py
@@ -14,7 +14,8 @@
 import unittest
 
 def suite():
-    from babel.tests import core, dates, localedata, numbers, support, util
+    from babel.tests import core, dates, localedata, numbers, plural, \
+                            support, util
     from babel.messages import tests as messages
     suite = unittest.TestSuite()
     suite.addTest(core.suite())
@@ -22,6 +23,7 @@
     suite.addTest(localedata.suite())
     suite.addTest(messages.suite())
     suite.addTest(numbers.suite())
+    suite.addTest(plural.suite())
     suite.addTest(support.suite())
     suite.addTest(util.suite())
     return suite
new file mode 100644
--- /dev/null
+++ b/babel/tests/plural.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://babel.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://babel.edgewall.org/log/.
+
+import doctest
+import unittest
+
+from babel import plural
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocTestSuite(plural))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')
Copyright (C) 2012-2017 Edgewall Software