Skip to content

Commit 9dc04e3

Browse files
authored
Merge pull request #478 from JnyJny/features/improve-manager-usability
feat: replace LightManager with simplified fluent LightController
2 parents 7767ffb + d2c64dc commit 9dc04e3

29 files changed

+2430
-1239
lines changed

CLI_MIGRATION_EXAMPLE.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# CLI Migration to New LightController
2+
3+
This document shows how to migrate CLI commands from the old LightManager to the new LightController.
4+
5+
## Before (Old LightManager)
6+
7+
```python
8+
# src/busylight/subcommands/on.py
9+
@on_cli.command(name="on")
10+
def activate_lights(
11+
ctx: typer.Context,
12+
color: Optional[str] = typer.Argument("green", callback=string_to_scaled_color),
13+
) -> None:
14+
"""Activate lights with a color."""
15+
logger.info("Activating lights with color: {}", color)
16+
17+
try:
18+
ctx.obj.manager.on(color, ctx.obj.lights, timeout=ctx.obj.timeout)
19+
except (KeyboardInterrupt, TimeoutError):
20+
ctx.obj.manager.off(ctx.obj.lights)
21+
except NoLightsFoundError:
22+
typer.secho("No lights found.", fg="red")
23+
raise typer.Exit(code=1)
24+
except Exception as e:
25+
typer.secho(f"Error activating lights: {e}", fg="red")
26+
raise typer.Exit(code=1)
27+
```
28+
29+
## After (New LightController)
30+
31+
```python
32+
# src/busylight/subcommands/on.py
33+
@on_cli.command(name="on")
34+
def activate_lights(
35+
ctx: typer.Context,
36+
color: Optional[str] = typer.Argument("green"),
37+
) -> None:
38+
"""Activate lights with a color."""
39+
logger.info("Activating lights with color: {}", color)
40+
41+
try:
42+
with ctx.obj.controller as controller:
43+
# Convert light indices to selection
44+
if ctx.obj.lights:
45+
selection = controller.by_index(*ctx.obj.lights)
46+
else:
47+
selection = controller.all()
48+
49+
# Turn on lights - much cleaner!
50+
selection.turn_on(color, timeout=ctx.obj.timeout)
51+
52+
except (KeyboardInterrupt, TimeoutError):
53+
# Automatic cleanup happens in context manager
54+
pass
55+
except NoLightsFoundError:
56+
typer.secho("No lights found.", fg="red")
57+
raise typer.Exit(code=1)
58+
except Exception as e:
59+
typer.secho(f"Error activating lights: {e}", fg="red")
60+
raise typer.Exit(code=1)
61+
```
62+
63+
## Key Improvements
64+
65+
1. **Cleaner selection**: `controller.by_index(*indices)` instead of complex light ID management
66+
2. **Fluent interface**: `selection.turn_on(color, timeout=timeout)` is much more readable
67+
3. **Automatic cleanup**: Context manager handles resource cleanup automatically
68+
4. **Better error handling**: LightController has better built-in error messages
69+
5. **Color parsing**: Handled automatically in the controller, no need for callback
70+
71+
## Other Command Examples
72+
73+
### Blink Command
74+
```python
75+
# Old way:
76+
effect = Effects.for_name("blink")(color, count=count)
77+
ctx.obj.manager.apply_effect(effect, duty_cycle=speed.duty_cycle, light_ids=ctx.obj.lights, timeout=ctx.obj.timeout)
78+
79+
# New way:
80+
controller.all().blink(color, count=count, speed="slow")
81+
```
82+
83+
### Display Command
84+
```python
85+
# Old way:
86+
lights = ctx.obj.manager.selected_lights(ctx.obj.lights)
87+
for index, light in enumerate(lights):
88+
typer.secho(f"{index:3d} ", nl=False, fg="red")
89+
typer.secho(light.name, fg="green")
90+
91+
# New way:
92+
selection = controller.by_index(*ctx.obj.lights) if ctx.obj.lights else controller.all()
93+
for index, name in enumerate(selection.names()):
94+
typer.secho(f"{index:3d} ", nl=False, fg="red")
95+
typer.secho(name, fg="green")
96+
```
97+
98+
## Global Options Update
99+
100+
```python
101+
# OLD: src/busylight/global_options.py
102+
@dataclass
103+
class GlobalOptions:
104+
timeout: float = None
105+
dim: float = 0
106+
lights: list[int] = field(default_factory=list)
107+
debug: bool = False
108+
manager: LightManager = field(default_factory=LightManager)
109+
110+
# NEW: src/busylight/global_options.py
111+
@dataclass
112+
class GlobalOptions:
113+
timeout: float = None
114+
dim: float = 0
115+
lights: list[int] = field(default_factory=list)
116+
debug: bool = False
117+
controller: LightController = field(default_factory=LightController)
118+
```
119+
120+
## Migration Benefits
121+
122+
1. **Readability**: Code reads like natural language
123+
2. **Maintainability**: Easier to understand and modify
124+
3. **Testing**: Much easier to test individual components
125+
4. **Error handling**: Better built-in error messages and handling
126+
5. **Resource management**: Automatic cleanup prevents resource leaks
127+
6. **Flexibility**: Easy to add new selection methods and operations

0 commit comments

Comments
 (0)