From 1aa33783821fb019d079f792f5f04e4b376f0e42 Mon Sep 17 00:00:00 2001 From: Chiizujin Date: Tue, 16 Apr 2024 00:06:15 +1000 Subject: [PATCH] Add support for article=True and format=fmt to $You(r) and $you(r) Where fmt = upper|lower|capital|title --- evennia/utils/funcparser.py | 67 +++++++++++++---- evennia/utils/tests/test_funcparser.py | 99 ++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 13 deletions(-) diff --git a/evennia/utils/funcparser.py b/evennia/utils/funcparser.py index 2c434badcf..8a40238caa 100644 --- a/evennia/utils/funcparser.py +++ b/evennia/utils/funcparser.py @@ -70,6 +70,12 @@ _CLIENT_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH _MAX_NESTING = settings.FUNCPARSER_MAX_NESTING _START_CHAR = settings.FUNCPARSER_START_CHAR _ESCAPE_CHAR = settings.FUNCPARSER_ESCAPE_CHAR +_YOU_FORMAT_FUNCS = { + "upper": str.upper, + "lower": str.lower, + "capital": str.capitalize, + "title": str.title, +} @dataclasses.dataclass @@ -1230,12 +1236,30 @@ def funcparser_callable_you( capitalize = bool(capitalize) if caller == receiver: - return "You" if capitalize else "you" - return ( - caller.get_display_name(looker=receiver) - if hasattr(caller, "get_display_name") - else str(caller) - ) + name = "You" if capitalize else "you" + else: + if kwargs.get("article"): + name = ( + caller.get_numbered_name(1, looker=receiver, return_string=True) + if hasattr(caller, "get_numbered_name") + else str(caller) + ) + else: + name = ( + caller.get_display_name(looker=receiver) + if hasattr(caller, "get_display_name") + else str(caller) + ) + + # a specified format overrides 'capitalize' and also applies to "you" + if (fmt := kwargs.get('format')): + try: + name = _YOU_FORMAT_FUNCS[fmt](name) + except KeyError: + callable_name = "$You" if capitalize else "$you" + raise ParsingError(f"Unsupported format supplied to {callable_name} callable: {fmt}.") + + return name def funcparser_callable_you_capitalize( @@ -1297,15 +1321,32 @@ def funcparser_callable_your( capitalize = bool(capitalize) if caller == receiver: - return "Your" if capitalize else "your" + name = "Your" if capitalize else "your" + else: + if kwargs.get("article"): + name = ( + caller.get_numbered_name(1, looker=receiver, return_string=True) + if hasattr(caller, "get_numbered_name") + else str(caller) + ) + else: + name = ( + caller.get_display_name(looker=receiver) + if hasattr(caller, "get_display_name") + else str(caller) + ) - name = ( - caller.get_display_name(looker=receiver) - if hasattr(caller, "get_display_name") - else str(caller) - ) + # a specified format overrides 'capitalize' and also applies to "your" + if (fmt := kwargs.get('format')): + try: + name = _YOU_FORMAT_FUNCS[fmt](name) + except KeyError: + callable_name = "$Your" if capitalize else "$your" + raise ParsingError(f"Unsupported format supplied to {callable_name} callable: {fmt}.") - return name + "'s" + if caller != receiver: + name += "'s" + return name def funcparser_callable_your_capitalize( diff --git a/evennia/utils/tests/test_funcparser.py b/evennia/utils/tests/test_funcparser.py index 7b13926ede..bf7706b81d 100644 --- a/evennia/utils/tests/test_funcparser.py +++ b/evennia/utils/tests/test_funcparser.py @@ -5,6 +5,7 @@ Test the funcparser module. """ import time +import inflect import unittest from ast import literal_eval from unittest.mock import MagicMock, patch @@ -392,6 +393,7 @@ class TestFuncParser(TestCase): ret = parser.parse("This is a $foo(foo=moo) string", foo="bar") self.assertEqual("This is a _test(test=foo, foo=bar) string", ret) +_INFLECT = inflect.engine() class _DummyObj: def __init__(self, name): @@ -400,6 +402,8 @@ class _DummyObj: def get_display_name(self, looker=None): return self.name + def get_numbered_name(self, *args, **kwargs): + return _INFLECT.an(self.name) class TestDefaultCallables(TestCase): """ @@ -599,7 +603,102 @@ class TestDefaultCallables(TestCase): """ ret = self.parser.parse(string, raise_errors=True) self.assertEqual(expected, ret) + def test_you_article(self): + """ + Test article kwarg passed to $You/$you + """ + + self.obj1.name = "mouse" + string = "$You() $conj(run) around" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, raise_errors=True + ) + self.assertEqual("mouse runs around", ret) + + self.obj1.name = "mouse" + string = "$You(article=True) $conj(run) around" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, raise_errors=True + ) + self.assertEqual("a mouse runs around", ret) + + def test_you_format(self): + """ + Test format kwarg passed to $You/$you + + """ + + mapping = {"char2": self.obj2} + self.obj1.name = "char One" + + string = "$You() $conj(smile) at $you(char2)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("char One smiles at you", ret) + + string = "$You(format=upper) $conj(smile) at $you(char2, format=upper)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("CHAR ONE smiles at YOU", ret) + + string = "$You(format=lower) $conj(smile) at $you(char2, format=lower)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("char one smiles at you", ret) + + string = "$You(format=title) $conj(smile) at $you(char2, format=title)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("Char One smiles at You", ret) + + string = "$You(format=capital) $conj(smile) at $you(char2, format=capital)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("Char one smiles at You", ret) + def test_your_format(self): + """ + Test format kwarg passed to $Your/$your + + """ + + self.obj1.name = "char One" + mapping = {"char2": self.obj2} + + string = "$Your() attack hits $you(char2)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("char One's attack hits you", ret) + + string = "$Your(format=upper) attack hits $you(char2, format=upper)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("CHAR ONE's attack hits YOU", ret) + + string = "$Your(format=lower) attack hits $you(char2, format=lower)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("char one's attack hits you", ret) + + string = "$Your(format=title) attack hits $you(char2, format=title)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("Char One's attack hits You", ret) + + string = "$Your(format=capital) attack hits $you(char2, format=capital)" + ret = self.parser.parse( + string, caller=self.obj1, receiver=self.obj2, mapping=mapping, raise_errors=True + ) + self.assertEqual("Char one's attack hits You", ret) def test_random(self): """ Test random callable, with ranges of expected values.