diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index bb65a9c..95196eb 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -24,4 +24,4 @@ jobs: pylint $(git ls-files 'bink/*.py') - name: Run tests run: | - python -m unittest -v tests/story_tests.py + python -m unittest discover diff --git a/README.md b/README.md index b4a290a..624329d 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,10 @@ while not end: # Obtain and print choices choices = story.get_current_choices() - print(f"Num. choices: {choices.len()}\n") + print(f"Num. choices: {len(choices)}\n") - if choices.len() != 0: - for i in range(choices.len()): - text = choices.get_text(i) + if choices: + for i, text in enumerate(choices): print(f"{i + 1}. {text}") # read_input() is a method that you should implement @@ -53,6 +52,6 @@ print("Story ended ok.") We can execute Python tests in the `tests` folder using the next command: ```bash -$ python -m unittest -v tests/story_tests.py +$ python -m unittest discover ``` diff --git a/bink/choices.py b/bink/choices.py index 36d0e5a..2ee6a22 100644 --- a/bink/choices.py +++ b/bink/choices.py @@ -3,16 +3,47 @@ import ctypes from bink import LIB, BINK_OK + +class ChoicesIterator: + def __init__(self, choices): + self._choices = choices + self._index = 0 + + def __next__(self): + if self._index >= len(self._choices): + raise StopIteration + + self._index += 1 + return self._choices[self._index - 1] + + class Choices: """List of story choices.""" def __init__(self, choices, c_len: int): self._choices = choices self._len = c_len - def len(self) -> int: + def __len__(self) -> int: """Returns the number of choices.""" return self._len + def __bool__(self) -> bool: + return self._len != 0 + + def __iter__(self): + return ChoicesIterator(self) + + def __getitem__(self, idx: int) -> str: + """Returns the choice text""" + + if not isinstance(idx, int): + raise TypeError + + if idx < 0 or idx > self._len: + raise IndexError + + return self.get_text(idx) + def get_text(self, idx) -> str: """Returns the choice text.""" text = ctypes.c_char_p() diff --git a/bink/story.py b/bink/story.py index d08062f..434e374 100644 --- a/bink/story.py +++ b/bink/story.py @@ -6,6 +6,7 @@ from bink.tags import Tags from bink import LIB, BINK_OK + class Story: """Story is the entry point of the Blade Ink lib.""" def __init__(self, story_string: str): @@ -22,6 +23,23 @@ def __init__(self, story_string: str): self._story = story + def __next__(self): + if not self.can_continue(): + raise StopIteration + + return self.cont() + + def __iter__(self): + return self + + @property + def choices(self): + return self.get_current_choices() + + @property + def tags(self): + return self.get_current_tags() + def can_continue(self): can_continue = ctypes.c_bool() ret = LIB.bink_story_can_continue( diff --git a/bink/tags.py b/bink/tags.py index b0f0723..a305dff 100644 --- a/bink/tags.py +++ b/bink/tags.py @@ -4,16 +4,47 @@ import ctypes from bink import LIB, BINK_OK + +class TagsIterator: + def __init__(self, tags): + self._tags = tags + self._index = 0 + + def __next__(self): + if self._index >= len(self._tags): + raise StopIteration + + self._index += 1 + return self._tags[self._index - 1] + + class Tags: """Contains a list of tags.""" def __init__(self, tags, c_len): self._tags = tags self._len = c_len - def len(self) -> int: - """Returns the number of choices.""" + def __len__(self) -> int: + """Returns the number of tags.""" return self._len + def __bool__(self) -> bool: + return self._len != 0 + + def __iter__(self): + return TagsIterator(self) + + def __getitem__(self, idx: int) -> str: + """Returns the tag text""" + + if not isinstance(idx, int): + raise TypeError + + if idx < 0 or idx > self._len: + raise IndexError + + return self.get(idx) + def get(self, idx) -> str: """Returns the tag text.""" tag = ctypes.c_char_p() diff --git a/tests/story_tests.py b/tests/test_story.py similarity index 73% rename from tests/story_tests.py rename to tests/test_story.py index 5cc18b1..cedc4e6 100644 --- a/tests/story_tests.py +++ b/tests/test_story.py @@ -15,18 +15,15 @@ def test_the_intercept(self): end = False while not end: - while story.can_continue(): - line = story.cont() + for line in story: print(line) # Assuming 'line' is a byte-like object # Obtain and print choices - choices = story.get_current_choices() + choices = story.choices + print(f"Num. choices: {len(choices)}\n") - print(f"Num. choices: {choices.len()}\n") - - if choices.len() != 0: - for i in range(choices.len()): - text = choices.get_text(i) + if choices: + for i, text in enumerate(choices): print(f"{i + 1}. {text}") # Always choose the first option