diff options
| author | natsuoto <[email protected]> | 2026-07-01 17:04:28 +0530 |
|---|---|---|
| committer | natsuoto <[email protected]> | 2026-07-01 17:04:28 +0530 |
| commit | dab26fa6193af03b5b132f6d7fe60b60d884ba86 (patch) | |
| tree | ea8b0895b829a13b3ec0fca30509aa4e7a663c16 | |
| parent | 52daac402a6d47253f9e13d5a955c990c4f171a8 (diff) | |
| download | edify-dab26fa6193af03b5b132f6d7fe60b60d884ba86.tar.xz edify-dab26fa6193af03b5b132f6d7fe60b60d884ba86.zip | |
feat: .fork() and .copy() explicit aliases for branch construction
| -rw-r--r-- | edify/builder/core.py | 13 | ||||
| -rw-r--r-- | tests/builder/equality.test.py | 2 | ||||
| -rw-r--r-- | tests/builder/fork.test.py | 47 |
3 files changed, 61 insertions, 1 deletions
diff --git a/edify/builder/core.py b/edify/builder/core.py index 1aa1ca3..333c7ad 100644 --- a/edify/builder/core.py +++ b/edify/builder/core.py @@ -33,6 +33,19 @@ class BuilderCore: new_instance._state = new_state return new_instance + def fork(self) -> Self: + """Return a fresh builder with the same immutable state. + + Chain methods already return new instances so implicit forking works + (``root.digit()`` and ``root.word()`` share nothing after the split); + this method makes the intent explicit and discoverable via autocomplete. + """ + return self._with_state(self._state) + + def copy(self) -> Self: + """Alias for :meth:`fork` — return a fresh builder with the same immutable state.""" + return self._with_state(self._state) + def __repr__(self) -> str: """Return ``<ClassName 'pattern-so-far'>`` for interactive display.""" rendered = _render_or_marker(self) diff --git a/tests/builder/equality.test.py b/tests/builder/equality.test.py index 6c6fce5..717d1ae 100644 --- a/tests/builder/equality.test.py +++ b/tests/builder/equality.test.py @@ -47,4 +47,4 @@ def test_hash_of_two_flags_that_differ_are_distinct(): a = RegexBuilder().ignore_case().digit() b = RegexBuilder().digit() assert a != b - assert hash(a) != hash(b)
\ No newline at end of file + assert hash(a) != hash(b) diff --git a/tests/builder/fork.test.py b/tests/builder/fork.test.py new file mode 100644 index 0000000..bcb8d1b --- /dev/null +++ b/tests/builder/fork.test.py @@ -0,0 +1,47 @@ +"""Tests for the :meth:`BuilderCore.fork` and :meth:`BuilderCore.copy` aliases.""" + +from edify import Pattern, RegexBuilder + + +def test_fork_returns_a_regex_builder_with_the_same_state(): + original = RegexBuilder().digit() + forked = original.fork() + assert forked == original + assert forked is not original + + +def test_fork_returns_a_pattern_with_the_same_state(): + original = Pattern().word() + forked = original.fork() + assert forked == original + assert forked is not original + + +def test_copy_returns_a_regex_builder_with_the_same_state(): + original = RegexBuilder().digit() + copied = original.copy() + assert copied == original + assert copied is not original + + +def test_copy_returns_a_pattern_with_the_same_state(): + original = Pattern().word() + copied = original.copy() + assert copied == original + assert copied is not original + + +def test_fork_and_copy_produce_independent_branches(): + root = RegexBuilder().digit() + branch_a = root.fork().word() + branch_b = root.copy().whitespace_char() + assert root.to_regex_string() == "\\d" + assert branch_a.to_regex_string() == "\\d\\w" + assert branch_b.to_regex_string() == "\\d\\s" + + +def test_fork_and_copy_return_the_concrete_class_type(): + assert isinstance(RegexBuilder().fork(), RegexBuilder) + assert isinstance(RegexBuilder().copy(), RegexBuilder) + assert isinstance(Pattern().fork(), Pattern) + assert isinstance(Pattern().copy(), Pattern) |
