diff --git a/README.md b/README.md index 1b8c3a05..1f1f9266 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Read the [contributing guide](https://docs.pyscript.net/latest/contributing/) to learn about our development process, reporting bugs and improvements, creating issues and asking questions. -Check out the [developing process](https://docs.pyscript.net/latest/developers/) +Check out the [development process](https://docs.pyscript.net/latest/developers/) documentation for more information on how to setup your development environment. ## Governance diff --git a/core/tests/python/tests/test_when.py b/core/tests/python/tests/test_when.py index 5dd66647..b2764e4d 100644 --- a/core/tests/python/tests/test_when.py +++ b/core/tests/python/tests/test_when.py @@ -214,3 +214,130 @@ def test_when_decorator_invalid_selector(): def foo(evt): ... assert "'#.bad' is not a valid selector" in str(e.exception), str(e.exception) + + +def test_when_decorates_a_whenable(): + """ + When the @when decorator is used on a function to handle a whenable object, + the function should be called when the whenable object is triggered. + """ + + class MyWhenable: + """ + A simple whenable object that can be triggered. + """ + + def __init__(self): + self.handler = None + self.args = None + self.kwargs = None + + def trigger(self): + """ + Triggers the whenable object, resulting in the handler being + called. + """ + if self.handler: + result = { + "args": self.args, + "kwargs": self.kwargs, + } + self.handler(result) # call the handler + + def __when__(self, handler, *args, **kwargs): + """ + These implementation details depend on the sort of thing the + whenable object represents. This is just a simple example. + """ + self.handler = handler + self.args = args + self.kwargs = kwargs + + whenable = MyWhenable() + counter = 0 + + # When as a decorator. + @web.when(whenable, "foo", "bar", baz="qux") + def foo(result): + """ + A function that should be called when the whenable object is triggered. + + The result generated by the whenable object should be passed to the + function. + """ + nonlocal counter + counter += 1 + assert result["args"] == ("foo", "bar") + assert result["kwargs"] == {"baz": "qux"} + + # The function should not be called until the whenable object is triggered. + assert counter == 0 + # Trigger the whenable object. + whenable.trigger() + # The function should have been called when the whenable object was + # triggered. + assert counter == 1 + + +def test_when_called_with_a_whenable(): + """ + The when function should be able to be called with a whenable object, + a handler function, and arguments. + """ + + class MyWhenable: + """ + A simple whenable object that can be triggered. + """ + + def __init__(self): + self.handler = None + self.args = None + self.kwargs = None + + def trigger(self): + """ + Triggers the whenable object, resulting in the handler being + called. + """ + if self.handler: + result = { + "args": self.args, + "kwargs": self.kwargs, + } + self.handler(result) # call the handler + + def __when__(self, handler, *args, **kwargs): + """ + These implementation details depend on the sort of thing the + whenable object represents. This is just a simple example. + """ + self.handler = handler + self.args = args + self.kwargs = kwargs + + whenable = MyWhenable() + counter = 0 + + def handler(result): + """ + A function that should be called when the whenable object is triggered. + + The result generated by the whenable object should be passed to the + function. + """ + nonlocal counter + counter += 1 + assert result["args"] == ("foo", "bar") + assert result["kwargs"] == {"baz": "qux"} + + # When as a function. + web.when(whenable, handler, "foo", "bar", baz="qux") + + # The function should not be called until the whenable object is triggered. + assert counter == 0 + # Trigger the whenable object. + whenable.trigger() + # The function should have been called when the whenable object was + # triggered. + assert counter == 1 \ No newline at end of file