Skip to content

Commit fb5f401

Browse files
committed
Add class for phrases containing multiple linked plurals.
1 parent 9f53552 commit fb5f401

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

doc-source/api/words.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,22 @@ Functions
107107
:html: 31/100
108108

109109
.. automodulesumm:: domdf_python_tools.words
110-
:autosummary-members: alpha_sort,get_words_list,get_random_word,as_text,word_join,Plural
110+
:autosummary-members: alpha_sort,get_words_list,get_random_word,as_text,word_join
111111

112112
.. autofunction:: domdf_python_tools.words.alpha_sort
113113
.. autofunction:: domdf_python_tools.words.as_text
114114
.. autofunction:: domdf_python_tools.words.get_words_list
115115
.. autofunction:: domdf_python_tools.words.get_random_word
116116
.. autofunction:: domdf_python_tools.words.word_join
117+
118+
Classes
119+
-------------
120+
121+
.. autosummary-widths:: 8/16
122+
:html: 31/100
123+
124+
.. automodulesumm:: domdf_python_tools.words
125+
:autosummary-members: Plural,PluralPhrase
126+
117127
.. autoclass:: domdf_python_tools.words.Plural
128+
.. autonamedtuple:: domdf_python_tools.words.PluralPhrase

domdf_python_tools/words.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from gettext import ngettext
4444
from reprlib import recursive_repr
4545
from string import ascii_lowercase, ascii_uppercase
46-
from typing import Any, Dict, Iterable, List, Optional
46+
from typing import Any, Dict, Iterable, List, NamedTuple, Optional, Tuple
4747

4848
# this package
4949
import domdf_python_tools
@@ -75,6 +75,7 @@
7575
"CR",
7676
"LF",
7777
"Plural",
78+
"PluralPhrase",
7879
]
7980

8081
ascii_digits = "0123456789"
@@ -615,3 +616,72 @@ def __repr__(self):
615616
args.extend(repr(x) for x in self.args)
616617
args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items())
617618
return f"{qualname}({', '.join(args)})"
619+
620+
621+
@prettify_docstrings
622+
class PluralPhrase(NamedTuple):
623+
"""
624+
Represents a phrase which varies depending on a numerical count.
625+
626+
.. versionadded:: 3.3.0
627+
628+
:param template: The phrase template.
629+
:param words: The words to insert into the template.
630+
631+
For example, consider the phase::
632+
633+
The proposed changes are to ...
634+
635+
The "phrase template" would be:
636+
637+
.. code-block:: python
638+
639+
"The proposed {} {} to ..."
640+
641+
and the two words to insert are:
642+
643+
.. code-block:: python
644+
645+
Plural("change", "changes")
646+
Plural("is", "are")
647+
648+
The phrase is constructed as follows:
649+
650+
.. code-block:: python
651+
652+
>>> phrase = PluralPhrase(
653+
... "The proposed {} {} to ...",
654+
... (Plural("change", "changes"), Plural("is", "are"))
655+
... )
656+
>>> phrase(1)
657+
'The proposed change is to ...'
658+
>>> phrase(2)
659+
'The proposed changes are to ...'
660+
661+
The phrase template can use any `valid syntax`_ for :meth:`str.format`,
662+
except for keyword arguments. The exception if the keyword ``n``,
663+
which is replaced with the count (e.g. ``2``) passed in when the phrase is constructed.
664+
For example:
665+
666+
.. code-block:: python
667+
668+
>>> phrase2 = PluralPhrase("The farmer has {n} {0}.", (Plural("cow", "cows"), ))
669+
>>> phrase2(2)
670+
'The farmer has 2 cows.'
671+
672+
.. _valid syntax: https://docs.python.org/3/library/string.html#formatstrings
673+
674+
"""
675+
676+
template: str
677+
words: Tuple[Plural, ...]
678+
679+
def __call__(self, n: int) -> str: # noqa: TYP004 # TODO
680+
"""
681+
Construct the phrase based on the value of ``n``.
682+
683+
:param n:
684+
"""
685+
686+
plural_words = [x(n) for x in self.words]
687+
return self.template.format(*plural_words, n=n)

tests/test_words.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@
1212
from domdf_python_tools import words
1313
from domdf_python_tools.paths import PathPlus
1414
from domdf_python_tools.stringlist import StringList
15-
from domdf_python_tools.words import DOUBLESTRUCK_LETTERS, Plural, alpha_sort, get_random_word, get_words_list
15+
from domdf_python_tools.words import (
16+
DOUBLESTRUCK_LETTERS,
17+
Plural,
18+
PluralPhrase,
19+
alpha_sort,
20+
get_random_word,
21+
get_words_list
22+
)
1623

1724

1825
@pytest.mark.parametrize(
@@ -167,3 +174,37 @@ def test_plural():
167174

168175
assert repr(cow) == "Plural('cow', 'cows')"
169176
assert repr(glass) == "Plural('glass', 'glasses')"
177+
178+
179+
def test_pluralphrase():
180+
phrase1 = PluralPhrase("The proposed {} {} to ...", (Plural("change", "changes"), Plural("is", "are")))
181+
phrase2 = PluralPhrase("The farmer has {n} {0}.", (Plural("cow", "cows"), ))
182+
phrase3 = PluralPhrase("The proposed {1} {0} to ...", (Plural("is", "are"), Plural("change", "changes")))
183+
phrase4 = PluralPhrase(
184+
"The farmer has {n} {0}. The {0} {1} brown.", (Plural("cow", "cows"), Plural("is", "are"))
185+
)
186+
n = 1
187+
assert phrase1(n) == "The proposed change is to ..."
188+
assert phrase2(n) == "The farmer has 1 cow."
189+
assert phrase3(n) == "The proposed change is to ..."
190+
assert phrase4(n) == "The farmer has 1 cow. The cow is brown."
191+
192+
n = 2
193+
assert phrase1(n) == "The proposed changes are to ..."
194+
assert phrase2(n) == "The farmer has 2 cows."
195+
assert phrase3(n) == "The proposed changes are to ..."
196+
assert phrase4(n) == "The farmer has 2 cows. The cows are brown."
197+
198+
n = 3
199+
assert phrase1(n) == "The proposed changes are to ..."
200+
assert phrase2(n) == "The farmer has 3 cows."
201+
assert phrase3(n) == "The proposed changes are to ..."
202+
assert phrase4(n) == "The farmer has 3 cows. The cows are brown."
203+
204+
phrase1_repr = "PluralPhrase(template='The proposed {} {} to ...', words=(Plural('change', 'changes'), Plural('is', 'are')))"
205+
assert repr(phrase1) == phrase1_repr
206+
assert repr(phrase2) == "PluralPhrase(template='The farmer has {n} {0}.', words=(Plural('cow', 'cows'),))"
207+
phrase3_repr = "PluralPhrase(template='The proposed {1} {0} to ...', words=(Plural('is', 'are'), Plural('change', 'changes')))"
208+
assert repr(phrase3) == phrase3_repr
209+
phrase4_repr = "PluralPhrase(template='The farmer has {n} {0}. The {0} {1} brown.', words=(Plural('cow', 'cows'), Plural('is', 'are')))"
210+
assert repr(phrase4) == phrase4_repr

0 commit comments

Comments
 (0)