Final unit tests for evmenu templating
This commit is contained in:
parent
a94e723d6b
commit
1746aaf06b
3 changed files with 77 additions and 30 deletions
|
|
@ -290,10 +290,20 @@ def goto_command_demo_room(caller, raw_string, **kwargs):
|
|||
_maintain_demo_room(caller)
|
||||
caller.cmdset.remove(DemoCommandSetHelp)
|
||||
caller.cmdset.remove(DemoCommandSetComms)
|
||||
caller.cmdset.add(DemoCommandSetRoom) # TODO - make persistent
|
||||
caller.cmdset.add(DemoCommandSetRoom)
|
||||
return "command_demo_room"
|
||||
|
||||
|
||||
def goto_cleanup_cmdsets(caller, raw_strings, **kwargs):
|
||||
"""
|
||||
Cleanup all cmdsets.
|
||||
"""
|
||||
caller.cmdset.remove(DemoCommandSetHelp)
|
||||
caller.cmdset.remove(DemoCommandSetComms)
|
||||
caller.cmdset.remove(DemoCommandSetRoom)
|
||||
return kwargs.get("gotonode")
|
||||
|
||||
|
||||
# register all callables that can be used in the menu template
|
||||
|
||||
GOTO_CALLABLES = {
|
||||
|
|
@ -302,6 +312,7 @@ GOTO_CALLABLES = {
|
|||
"goto_command_demo_help": goto_command_demo_help,
|
||||
"goto_command_demo_comms": goto_command_demo_comms,
|
||||
"goto_command_demo_room": goto_command_demo_room,
|
||||
"goto_cleanup_cmdsets": goto_cleanup_cmdsets,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -365,7 +376,7 @@ gaming style you like and possibly any new ones you can come up with!
|
|||
## OPTIONS
|
||||
|
||||
next;n: About Evennia -> about_evennia
|
||||
back to start;start;t: start
|
||||
back to start;back;start;t: start
|
||||
>: about_evennia
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
|
@ -498,7 +509,7 @@ those channels ...
|
|||
## OPTIONS
|
||||
|
||||
next;n: Talk on Channels -> talk on channels
|
||||
back;b: Using the webclient -> using webclient
|
||||
back;b: Using the webclient -> goto_cleanup_cmdsets(gotonode='using webclient')
|
||||
back to start;start: start
|
||||
>: talk on channels
|
||||
|
||||
|
|
@ -556,7 +567,7 @@ include other people/objects in the emote, reference things by a short-descripti
|
|||
## OPTIONS
|
||||
|
||||
next;n: Paging people -> paging_people
|
||||
back;b: Talk on Channels -> talk on channels
|
||||
back;b: Talk on Channels -> goto_command_demo_help(gotonode='talk on channels')
|
||||
back to start;start: start
|
||||
>: paging_people
|
||||
|
||||
|
|
@ -627,7 +638,7 @@ color codes printed, try
|
|||
## OPTIONS
|
||||
|
||||
next;n: Moving and Exploring -> goto_command_demo_room()
|
||||
back;b: Paging people -> paging_people
|
||||
back;b: Paging people -> goto_command_demo_comms(gotonode='paging_people')
|
||||
back to start;start: start
|
||||
>: goto_command_demo_room()
|
||||
|
||||
|
|
@ -650,7 +661,7 @@ around in. Explore a little and use |ynext|n when you are done.
|
|||
## OPTIONS
|
||||
|
||||
next;n: Conclusions -> conclusions
|
||||
back;b: Channel commands -> testing_colors
|
||||
back;b: Channel commands -> goto_command_demo_comms(gotonode='testing_colors')
|
||||
back to start;start: start
|
||||
>: conclusions
|
||||
|
||||
|
|
@ -667,13 +678,11 @@ if you get stuck!
|
|||
Write |ynext|n to end this wizard and continue to the tutorial-world quest!
|
||||
If you want there is also some |wextra|n info for where to go beyond that.
|
||||
|
||||
Good luck!
|
||||
|
||||
## OPTIONS
|
||||
|
||||
extra: Some more help on where to go next -> post scriptum
|
||||
next;next;n: end
|
||||
back;b: goto_command_demo_room()
|
||||
extra: Where to go next -> post scriptum
|
||||
next;next;n: End -> end
|
||||
back;b: Moving and Exploring -> goto_command_demo_room()
|
||||
back to start;start: start
|
||||
>: end
|
||||
|
||||
|
|
@ -718,7 +727,7 @@ back: conclusions
|
|||
|
||||
## NODE end
|
||||
|
||||
Thanks for trying out the tutorial!
|
||||
|gGood luck!|n
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -1634,7 +1634,7 @@ _RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S[\S\s]*?)$", re.I + re.M)
|
|||
_RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M)
|
||||
_RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M)
|
||||
_RE_CALLABLE = re.compile(
|
||||
r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?=[\S\s]+?)\)|\(\))", re.I + re.M
|
||||
r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M
|
||||
)
|
||||
|
||||
_HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.")
|
||||
|
|
@ -1664,23 +1664,23 @@ def _process_callable(caller, goto, goto_callables, raw_string,
|
|||
gotokwargs = match.group("kwargs") or ""
|
||||
if gotofunc in goto_callables:
|
||||
for kwarg in gotokwargs.split(","):
|
||||
if kwarg and "=" in kwarg:
|
||||
key, value = [part.strip() for part in kwarg.split("=", 1)]
|
||||
if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename",
|
||||
"evmenu_current_nodename", "evmenu_goto_callables"):
|
||||
raise RuntimeError(
|
||||
f"EvMenu template error: goto-callable '{goto}' uses a "
|
||||
f"kwarg ({key}) that is reserved for the EvMenu templating "
|
||||
"system. Rename the kwarg.")
|
||||
try:
|
||||
key = literal_eval(key)
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
value = literal_eval(value)
|
||||
except ValueError:
|
||||
pass
|
||||
kwargs[key] = value
|
||||
key, value = [part.strip() for part in kwarg.split("=", 1)]
|
||||
if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename",
|
||||
"evmenu_current_nodename", "evmenu_goto_callables"):
|
||||
raise RuntimeError(
|
||||
f"EvMenu template error: goto-callable '{goto}' uses a "
|
||||
f"kwarg ({kwarg}) that is reserved for the EvMenu templating "
|
||||
"system. Rename the kwarg.")
|
||||
try:
|
||||
key = literal_eval(key)
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
value = literal_eval(value)
|
||||
except ValueError:
|
||||
pass
|
||||
kwargs[key] = value
|
||||
|
||||
goto = goto_callables[gotofunc](caller, raw_string, **kwargs)
|
||||
if goto is None:
|
||||
return goto, {"generated_nodename": current_nodename}
|
||||
|
|
@ -1755,6 +1755,23 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
|||
dict: A `{"node": nodefunc}` menutree suitable to pass into EvMenu.
|
||||
|
||||
"""
|
||||
def _validate_kwarg(goto, kwarg):
|
||||
"""
|
||||
Validate goto-callable kwarg is on correct form.
|
||||
"""
|
||||
if not "=" in kwarg:
|
||||
raise RuntimeError(
|
||||
f"EvMenu template error: goto-callable '{goto}' has a "
|
||||
f"non-kwarg argument ({kwarg}). All callables in the "
|
||||
"template must have only keyword-arguments, or no "
|
||||
"args at all.")
|
||||
key, _ = [part.strip() for part in kwarg.split("=", 1)]
|
||||
if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename",
|
||||
"evmenu_current_nodename", "evmenu_goto_callables"):
|
||||
raise RuntimeError(
|
||||
f"EvMenu template error: goto-callable '{goto}' uses a "
|
||||
f"kwarg ({kwarg}) that is reserved for the EvMenu templating "
|
||||
"system. Rename the kwarg.")
|
||||
|
||||
def _parse_options(nodename, optiontxt, goto_callables):
|
||||
"""
|
||||
|
|
@ -1779,6 +1796,14 @@ def parse_menu_template(caller, menu_template, goto_callables=None):
|
|||
if _OPTION_CALL_MARKER in goto:
|
||||
desc, goto = [part.strip() for part in goto.split(_OPTION_CALL_MARKER, 1)]
|
||||
|
||||
# validate callable
|
||||
match = _RE_CALLABLE.match(goto)
|
||||
if match:
|
||||
kwargs = match.group("kwargs")
|
||||
if kwargs:
|
||||
for kwarg in kwargs.split(','):
|
||||
_validate_kwarg(goto, kwarg)
|
||||
|
||||
# parse key [;aliases|pattern]
|
||||
key = [part.strip() for part in key.split(_OPTION_ALIAS_MARKER)]
|
||||
if not key:
|
||||
|
|
|
|||
|
|
@ -327,3 +327,16 @@ class TestMenuTemplateParse(EvenniaTest):
|
|||
|
||||
def test_template2menu(self):
|
||||
evmenu.template2menu(self.char1, self.menu_template, self.goto_callables)
|
||||
|
||||
def test_parse_menu_fail(self):
|
||||
template = """
|
||||
## NODE
|
||||
|
||||
Text
|
||||
|
||||
## OPTIONS
|
||||
|
||||
next: callnode2(invalid)
|
||||
"""
|
||||
with self.assertRaises(RuntimeError):
|
||||
evmenu.parse_menu_template(self.char1, template, self.goto_callables)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue