Skip to content

Commit 003e2a0

Browse files
committed
Add support for multiple cases, single action.
1 parent ab6c643 commit 003e2a0

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,39 @@ def process_with_data(*value):
3737
* Checks for duplicate keys / cases
3838
* Keys can be anything hashable (numbers, strings, objects, etc.)
3939
* Could be extended for "fall-through" cases (doesn't yet)
40+
* Use range and list for multiple cases mapped to a single action
41+
42+
## Multiple cases, one action
43+
44+
You can map ranges and lists of cases to a single action as follows:
45+
46+
```python
47+
# with lists:
48+
value = 4 # matches even number case
49+
50+
with switch(value) as s:
51+
s.case([1, 3, 5, 7], lambda: ...)
52+
s.case([0, 2, 4, 6, 8], lambda: ...)
53+
s.default(lambda: ...)
54+
```
55+
56+
```python
57+
# with ranges:
58+
value = 4 # matches first case
59+
60+
with switch(value) as s:
61+
s.case(range(1, 5), lambda: ...)
62+
s.case(range(6, 7), lambda: ...)
63+
s.default(lambda: ...)
64+
```
65+
66+
**Warning / open for debate**:
67+
68+
I'm a little unsure what is the right way to handle this
69+
On one hand, reading `case(range(1,5))` seems like it should
70+
include `1, 2, 3, 4, 5`. But `list(range(1,5))` is `[1,2,3,4]`.
71+
So that would be inconsistent.
72+
73+
Thoughts? I'm going with `1,2,3,4,5` for `range(1,5)` for now.
4074

4175

switchlang.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ def default(self, func: Callable[[], None]):
1111
self.case('__default__', func)
1212

1313
def case(self, key, func: Callable[[], None]):
14+
if isinstance(key, range):
15+
for n in range(key.start, key.stop + 1, key.step):
16+
self.case(n, func)
17+
return
18+
19+
if isinstance(key, list):
20+
for i in key:
21+
self.case(i, func)
22+
return
23+
1424
if key in self.cases:
1525
raise ValueError("Duplicate case: {}".format(key))
1626
if not func:
@@ -34,4 +44,4 @@ def __exit__(self, exc_type, exc_val, exc_tb):
3444
if not func:
3545
raise Exception("Value does not match any case and there is no default case: value {}".format(self.value))
3646

37-
func()
47+
func()

tests/coretests.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,41 @@ def test_error_duplicate_case(self):
8686
with switch('val') as s:
8787
s.case(1, lambda: None)
8888
s.case(1, lambda: None)
89+
90+
def test_multiple_values_one_case_range(self):
91+
value = 7
92+
93+
executed_case = None
94+
95+
def get_set_case(val):
96+
nonlocal executed_case
97+
executed_case = val
98+
99+
# I'm a little unsure what is the right way to handle this
100+
# On one hand, reading case(range(1,5)) seems like it should
101+
# include 1, 2, 3, 4, 5.
102+
# But list(range(1,5)) is [1,2,3,4]. So that would be inconsistent.
103+
# Thoughts?
104+
# I'm going with 1,2,3,4,5 for range(1,5) for now.
105+
with switch(value) as s:
106+
s.case(range(1, 5), lambda: get_set_case("1-to-5"))
107+
s.case(range(6, 7), lambda: get_set_case("6-to-7"))
108+
s.default(lambda: get_set_case('default'))
109+
110+
self.assertEqual(executed_case, "6-to-7")
111+
112+
def test_multiple_values_one_case_list(self):
113+
value = 6
114+
115+
executed_case = None
116+
117+
def get_set_case(val):
118+
nonlocal executed_case
119+
executed_case = val
120+
121+
with switch(value) as s:
122+
s.case([1, 3, 5, 7], lambda: get_set_case("odd"))
123+
s.case([0, 2, 4, 6, 8], lambda: get_set_case("even"))
124+
s.default(lambda: get_set_case('default'))
125+
126+
self.assertEqual(executed_case, "even")

0 commit comments

Comments
 (0)