diff --git a/README.md b/README.md index e53072d..b85fa85 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,11 @@ Python port of [KeySet in TypeScript](https://github.com/eturino/ts-key-set) and TBD +## TODO + +- remove +- union + ## Limitations - for now, only KeySet of strings @@ -22,22 +27,22 @@ Enum that represents the 4 types of KeySets: Methods exposed: -### `key_set_type` +### `key_set_type()` returns the `KeySetType` enum -### `elements` +### `elements()` returns the set with the elements. It will be blank for `All` and `None`. -### `represents_xxx` methods +### `represents_xxx()` methods - `represents_all`: returns True if the KeySet is ALL - `represents_none`: returns True if the KeySet is NONE - `represents_some`: returns True if the KeySet is SOME - `represents_all_except_some`: returns True if the KeySet is ALL_EXCEPT_SOME -### `invert` +### `invert()` Returns a new KeySet that represents the inverse Set of this one. @@ -47,3 +52,7 @@ Returns a new KeySet that represents the inverse Set of this one. ### `intersect(other)` Returns a new KeySet with the intersection (A ∩ B) of both Sets. + +### `includes(element)` + +Returns a new KeySet with the intersection (A ∩ B) of both Sets. diff --git a/key_set/base.py b/key_set/base.py index 18293c6..3e19daa 100644 --- a/key_set/base.py +++ b/key_set/base.py @@ -49,6 +49,11 @@ def invert(self) -> KeySet: """ pass + @abstractmethod + def includes(self, _elem: str) -> bool: + """Returns True if the set represented by this includes the elem.""" + pass + @abstractmethod def clone(self) -> KeySet: """Returns a new KeySet that represents the same Set of this one.""" @@ -86,6 +91,10 @@ def clone(self) -> KeySetAll: """Returns a new KeySet that represents the same Set of this one.""" return KeySetAll() + def includes(self, _elem: str) -> bool: + """Returns True if the set represented by this includes the elem.""" + return True + def intersect(self, other: KeySet) -> KeySet: """Returns a new KeySet that represents the intersection (A ∩ B).""" return other.clone() @@ -122,6 +131,10 @@ def clone(self) -> KeySetNone: """Returns a new KeySet that represents the same Set of this one.""" return KeySetNone() + def includes(self, _elem: str) -> bool: + """Returns True if the set represented by this includes the elem.""" + return False + def intersect(self, _other: KeySet) -> KeySetNone: """Returns a new KeySet that represents the intersection (A ∩ B).""" return self.clone() @@ -165,6 +178,10 @@ def clone(self) -> KeySetSome: """Returns a new KeySet that represents the same Set of this one.""" return KeySetSome(self.elements()) + def includes(self, elem: str) -> bool: + """Returns True if the set represented by this includes the elem.""" + return elem in self._elements + def intersect(self, other: KeySet) -> KeySet: """Returns a new KeySet that represents the intersection (A ∩ B).""" if other.represents_all(): @@ -172,11 +189,11 @@ def intersect(self, other: KeySet) -> KeySet: if other.represents_none(): return other.clone() if other.represents_some(): - els = self._elements.intersection(other.elements()) - return build_some(els) + elems = self._elements.intersection(other.elements()) + return build_some_or_none(elems) if other.represents_all_except_some(): - els = self._elements.difference(other.elements()) - return build_some(els) + elems = self._elements.difference(other.elements()) + return build_some_or_none(elems) return NotImplemented @@ -221,6 +238,10 @@ def clone(self) -> KeySetAllExceptSome: """Returns a new KeySet that represents the same Set of this one.""" return KeySetAllExceptSome(self.elements()) + def includes(self, elem: str) -> bool: + """Returns True if the set represented by this includes the elem.""" + return elem not in self._elements + def intersect(self, other: KeySet) -> KeySet: """Returns a new KeySet that represents the intersection (A ∩ B).""" if other.represents_all(): @@ -228,11 +249,11 @@ def intersect(self, other: KeySet) -> KeySet: if other.represents_none(): return other.clone() if other.represents_some(): - els = other.elements().difference(self._elements) - return build_some(els) + elems = other.elements().difference(self._elements) + return build_some_or_none(elems) if other.represents_all_except_some(): - els = self._elements.union(other.elements()) - return build_all_except_some(els) + elems = self._elements.union(other.elements()) + return build_all_except_some_or_all(elems) return NotImplemented @@ -240,7 +261,7 @@ def intersect(self, other: KeySet) -> KeySet: TAES = Union[KeySetAllExceptSome, KeySetAll] -def build_some(seq: TKS) -> TS: +def build_some_or_none(seq: TKS) -> TS: """Returns NONE if seq is blank, or SOME otherwise.""" if len(seq) > 0: return KeySetSome(seq) @@ -248,7 +269,7 @@ def build_some(seq: TKS) -> TS: return KeySetNone() -def build_all_except_some(seq: TKS) -> TAES: +def build_all_except_some_or_all(seq: TKS) -> TAES: """Returns ALL if seq is blank, or ALL_EXCEPT_SOME otherwise.""" if len(seq) > 0: return KeySetAllExceptSome(seq) diff --git a/tests/test_all.py b/tests/test_all.py index 0e8e1f4..74ef907 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -58,3 +58,7 @@ def test_intersect_all_except_some(self) -> None: assert actual.elements() == {'a', 'b'} assert actual == other assert actual is not other + + def test_includes(self) -> None: + ks = KeySetAll() + assert ks.includes('a') diff --git a/tests/test_all_except_some.py b/tests/test_all_except_some.py index 218946f..efa8c39 100644 --- a/tests/test_all_except_some.py +++ b/tests/test_all_except_some.py @@ -114,3 +114,11 @@ def test_intersect_all_except_some_without_common_keys(self) -> None: actual = ks.intersect(other) assert actual.represents_all_except_some() assert actual.elements() == {'a', 'b', 'c', 'd'} + + def test_includes_included(self) -> None: + ks = KeySetAllExceptSome({'a', 'b'}) + assert not ks.includes('a') + + def test_includes_missing(self) -> None: + ks = KeySetAllExceptSome({'a', 'b'}) + assert ks.includes('c') diff --git a/tests/test_builds.py b/tests/test_builds.py index 3d60edf..d7f11ce 100644 --- a/tests/test_builds.py +++ b/tests/test_builds.py @@ -5,27 +5,27 @@ from typing import List import key_set # noqa: F401 -from key_set.base import build_all_except_some, build_some +from key_set.base import build_all_except_some_or_all, build_some_or_none class TestBuilds: # noqa: D101 def test_build_some_with_blank(self) -> None: keys: List[str] = [] - actual = build_some(keys) + actual = build_some_or_none(keys) assert actual.represents_none() def test_build_some_with_elements(self) -> None: - actual = build_some(['A']) + actual = build_some_or_none(['A']) assert actual.represents_some() assert actual.elements() == {'A'} def test_build_all_except_some_with_blank(self) -> None: keys: List[str] = [] - actual = build_all_except_some(keys) + actual = build_all_except_some_or_all(keys) assert actual.represents_all() def test_build_all_except_some_with_elements(self) -> None: - actual = build_all_except_some(['A']) + actual = build_all_except_some_or_all(['A']) assert actual.represents_all_except_some() assert actual.elements() == {'A'} diff --git a/tests/test_none.py b/tests/test_none.py index 5250b22..070ee27 100644 --- a/tests/test_none.py +++ b/tests/test_none.py @@ -60,3 +60,7 @@ def test_intersect_all_except_some(self) -> None: assert actual.represents_none() assert actual == ks assert actual is not ks + + def test_includes(self) -> None: + ks = KeySetNone() + assert not ks.includes('a') diff --git a/tests/test_some.py b/tests/test_some.py index 33ec2f9..bb99b8e 100644 --- a/tests/test_some.py +++ b/tests/test_some.py @@ -114,3 +114,11 @@ def test_intersect_all_except_some_without_common_keys(self) -> None: actual = ks.intersect(other) assert actual.represents_some() assert actual.elements() == {'a', 'b'} + + def test_includes_included(self) -> None: + ks = KeySetSome({'a', 'b'}) + assert ks.includes('a') + + def test_includes_missing(self) -> None: + ks = KeySetSome({'a', 'b'}) + assert not ks.includes('c')