diff --git a/docs/source/config_reference/scripting/scripting_functions.rst b/docs/source/config_reference/scripting/scripting_functions.rst index ebb777d4..d04a05e4 100644 --- a/docs/source/config_reference/scripting/scripting_functions.rst +++ b/docs/source/config_reference/scripting/scripting_functions.rst @@ -595,6 +595,13 @@ contains :description: Returns True if ``contains`` is in ``string``. False otherwise. +contains_any +~~~~~~~~~~~~ +:spec: ``contains_any(string: String, contains_array: Array) -> Boolean`` + +:description: + Returns true if any element in ``contains_array`` is in ``string``. False otherwise. + lower ~~~~~ :spec: ``lower(string: String) -> String`` diff --git a/src/ytdl_sub/script/functions/string_functions.py b/src/ytdl_sub/script/functions/string_functions.py index fd0cac9f..0819a6f5 100644 --- a/src/ytdl_sub/script/functions/string_functions.py +++ b/src/ytdl_sub/script/functions/string_functions.py @@ -3,6 +3,7 @@ from typing import Optional from ytdl_sub.script.types.array import Array from ytdl_sub.script.types.resolvable import AnyArgument from ytdl_sub.script.types.resolvable import Boolean +from ytdl_sub.script.types.resolvable import Float from ytdl_sub.script.types.resolvable import Integer from ytdl_sub.script.types.resolvable import Numeric from ytdl_sub.script.types.resolvable import String @@ -25,6 +26,20 @@ class StringFunctions: """ return Boolean(contains.value in string.value) + @staticmethod + def contains_any(string: String, contains_array: Array) -> Boolean: + """ + :description: + Returns true if any element in ``contains_array`` is in ``string``. False otherwise. + """ + return Boolean( + any( + str(val) in string.value + for val in contains_array.value + if isinstance(val, (String, Integer, Boolean, Float)) + ) + ) + @staticmethod def slice(string: String, start: Integer, end: Optional[Integer] = None) -> String: """ diff --git a/src/ytdl_sub/subscriptions/subscription_validators.py b/src/ytdl_sub/subscriptions/subscription_validators.py index 35bbbcb7..9287a15b 100644 --- a/src/ytdl_sub/subscriptions/subscription_validators.py +++ b/src/ytdl_sub/subscriptions/subscription_validators.py @@ -11,7 +11,7 @@ from ytdl_sub.config.config_file import ConfigFile from ytdl_sub.config.overrides import Overrides from ytdl_sub.entries.variables.override_variables import SubscriptionVariables from ytdl_sub.utils.script import ScriptUtils -from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator +from ytdl_sub.validators.string_formatter_validators import UnstructuredDictFormatterValidator from ytdl_sub.validators.validators import DictValidator from ytdl_sub.validators.validators import LiteralDictValidator from ytdl_sub.validators.validators import StringListValidator @@ -196,7 +196,9 @@ class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValid ) -class SubscriptionWithOverridesValidator(SubscriptionLeafValidator, DictFormatterValidator): +class SubscriptionWithOverridesValidator( + SubscriptionLeafValidator, UnstructuredDictFormatterValidator +): def __init__( self, name, diff --git a/tests/unit/config/test_subscription.py b/tests/unit/config/test_subscription.py index ff9feb93..574da070 100644 --- a/tests/unit/config/test_subscription.py +++ b/tests/unit/config/test_subscription.py @@ -159,6 +159,12 @@ def preset_with_subscription_overrides_tilda( "parent_preset_2 | parent_preset_1": { "~ test_2_1": { "current_override": "test_2_1", + "custom_list": [ + "elem1", + "elem2", + "elem3", + ], + "passed_list_elem": "{%contains_any('elem2', custom_list)}", } }, }, @@ -262,6 +268,8 @@ def test_subscription_overrides_tilda( assert sub_2_1.get("subscription_name").native == "test_2_1" assert sub_2_1.get("current_override").native == "test_2_1" # tilda sub takes precedence + assert sub_2_1.get("passed_list_elem").native is True + assert sub_2_1.get("custom_list").native == ["elem1", "elem2", "elem3"] def test_subscription_overrides_map( diff --git a/tests/unit/script/functions/test_string_functions.py b/tests/unit/script/functions/test_string_functions.py index cfa5175e..e5d898f8 100644 --- a/tests/unit/script/functions/test_string_functions.py +++ b/tests/unit/script/functions/test_string_functions.py @@ -118,6 +118,14 @@ class TestNumericFunctions: output = single_variable_output(f"{{%contains('a brown dog', '{value}')}}") assert output == expected_output + @pytest.mark.parametrize( + "value, expected_output", + [("['a', 'b', 'c']", True), ("['nope', [], {}]", False), ("['at', 'dog']", True)], + ) + def test_contains_any(self, value, expected_output): + output = single_variable_output(f"{{%contains_any('a brown dog', {value})}}") + assert output == expected_output + @pytest.mark.parametrize( "input_string, split, max_split, expected_output", [