diff --git a/hypermedia/models/base.py b/hypermedia/models/base.py index 7083bd4..f3d9aad 100644 --- a/hypermedia/models/base.py +++ b/hypermedia/models/base.py @@ -125,6 +125,20 @@ def extend(self, slot: str, *children: AnyChildren) -> Self: ) return self + def replace(self, slot: str, *children: AnyChildren) -> Self: + """Extend the child with the given slots children.""" + if slot not in self.slots: + raise ValueError(f"Could not find a slot with name: {slot}") + element = self.slots[slot] + + new_children = tuple(child for child in children if child is not None) + element.children = new_children + + get_child_slots( + self.slots, [c for c in new_children if isinstance(c, Element)] + ) + return self + def _render_attributes(self) -> str: # noqa: C901 result = [] diff --git a/tests/models/element/test_replace.py b/tests/models/element/test_replace.py new file mode 100644 index 0000000..c4511f3 --- /dev/null +++ b/tests/models/element/test_replace.py @@ -0,0 +1,68 @@ +from tests.utils import TestElement + + +def test_adds_child_to_slot() -> None: + element = TestElement(slot="my_slot") + child = TestElement() + + element.replace("my_slot", child) + + assert element.children == (child,) + + +def test_skips_adding_none_child_to_slot() -> None: + element = TestElement(slot="my_slot") + + element.replace("my_slot", None) + + assert element.children == () + + +def test_skips_only_none_values() -> None: + element = TestElement(slot="my_slot") + child = TestElement() + + element.replace("my_slot", child, None) + + assert element.children == (child,) + + +def test_adds_children_to_slot() -> None: + element = TestElement(slot="my_slot") + child_1 = TestElement() + child_2 = TestElement() + + element.replace("my_slot", child_1, child_2) + + assert element.children == (child_1, child_2) + + +def test_replaces_children_in_slot() -> None: + element = TestElement(TestElement("1"), slot="my_slot") + child_2 = TestElement("2") + + element.replace("my_slot", child_2) + + assert element.children == (child_2,) + + +def test_children_slots_calculated_() -> None: + element = TestElement(slot="my_slot") + child_1 = TestElement("1", slot="child_slot") + child_2 = TestElement("2") + + element.replace("my_slot", child_1) + element.replace("child_slot", child_2) + + assert element.children == (child_1,) + assert child_1.children == (child_2,) + + +def test_adds_child_to_any_descendant_slot() -> None: + child = TestElement(slot="descendant_slot") + parent = TestElement(child) + element = TestElement() + + parent.replace("descendant_slot", element) + + assert child.children == (element,)