diff --git a/docs/source/config_reference/scripting/scripting_functions.rst b/docs/source/config_reference/scripting/scripting_functions.rst index c271669e..5a02ca39 100644 --- a/docs/source/config_reference/scripting/scripting_functions.rst +++ b/docs/source/config_reference/scripting/scripting_functions.rst @@ -225,6 +225,27 @@ xor Conditional Functions --------------------- +elif +~~~~ +:spec: ``elif(if_elif_else: AnyArgument, ...) -> AnyArgument`` + +:description: + Conditional ``if`` statement that is capable of doing else-ifs (``elif``) via + adjacent arguments. It is expected for there to be an odd number of arguments >= 3 to + supply at least one conditional and an else. +:usage: + + .. code-block:: python + + %elif( + condition1, + return1, + condition2, + return2, + ... + else_return + ) + if ~~ :spec: ``if(condition: Boolean, true: ReturnableArgumentA, false: ReturnableArgumentB) -> Union[ReturnableArgumentA, ReturnableArgumentB]`` diff --git a/src/ytdl_sub/script/functions/conditional_functions.py b/src/ytdl_sub/script/functions/conditional_functions.py index e532031b..8b9da74b 100644 --- a/src/ytdl_sub/script/functions/conditional_functions.py +++ b/src/ytdl_sub/script/functions/conditional_functions.py @@ -1,8 +1,10 @@ from typing import Union +from ytdl_sub.script.types.resolvable import AnyArgument from ytdl_sub.script.types.resolvable import Boolean from ytdl_sub.script.types.resolvable import ReturnableArgumentA from ytdl_sub.script.types.resolvable import ReturnableArgumentB +from ytdl_sub.script.utils.exceptions import FunctionRuntimeException class ConditionalFunctions: @@ -19,6 +21,39 @@ class ConditionalFunctions: return true return false + @staticmethod + def elif_(*if_elif_else: AnyArgument) -> AnyArgument: + """ + :description: + Conditional ``if`` statement that is capable of doing else-ifs (``elif``) via + adjacent arguments. It is expected for there to be an odd number of arguments >= 3 to + supply at least one conditional and an else. + :usage: + + .. code-block:: python + + %elif( + condition1, + return1, + condition2, + return2, + ... + else_return + ) + """ + arguments = list(if_elif_else) + if len(arguments) < 3: + raise FunctionRuntimeException("elif requires at least 3 arguments") + + if len(arguments) % 2 == 0: + raise FunctionRuntimeException("elif must have an odd number of arguments") + + for idx in range(0, len(arguments) - 1, 2): + if bool(arguments[idx].value): + return arguments[idx + 1] + + return arguments[-1] + @staticmethod def if_passthrough( maybe_true_arg: ReturnableArgumentA, else_arg: ReturnableArgumentB diff --git a/tests/unit/script/functions/test_conditional_functions.py b/tests/unit/script/functions/test_conditional_functions.py index f7217915..5cf04a18 100644 --- a/tests/unit/script/functions/test_conditional_functions.py +++ b/tests/unit/script/functions/test_conditional_functions.py @@ -1,6 +1,10 @@ +import re + import pytest from unit.script.conftest import single_variable_output +from ytdl_sub.script.utils.exceptions import FunctionRuntimeException + class TestConditionalFunction: @pytest.mark.parametrize( @@ -33,3 +37,67 @@ class TestConditionalFunction: }""" ) assert output == "winner" + + def test_elif_function(self): + output = single_variable_output( + """{ + %elif( + False, + "nope", + False, + "still nope", + True, + "yes", + "default value" + ) + }""" + ) + assert output == "yes" + + def test_elif_function_default_value(self): + output = single_variable_output( + """{ + %elif( + False, + "nope", + False, + "still nope", + False, + "will be default", + "default value" + ) + }""" + ) + assert output == "default value" + + def test_elif_function_errors_lt3(self): + with pytest.raises( + FunctionRuntimeException, + match=re.escape("elif requires at least 3 arguments"), + ): + single_variable_output( + """ + { + %elif( + False, + "only two args" + ) + }""" + ) + + def test_elif_function_errors_odd(self): + with pytest.raises( + FunctionRuntimeException, + match=re.escape("elif must have an odd number of arguments"), + ): + single_variable_output( + """ + { + %elif( + False, + "1", + False, + "even number args bad" + ) + }""" + )