← Volver al listado de tecnologías
Capítulo 3: Gestor de Tareas CLI
Gestor de Tareas
Un sistema CRUD completo para gestionar tareas con persistencia en JSON.
Conceptos que Aprenderás
- Lectura/escritura de archivos
- Serialización JSON
- Estructuras de datos complejas
- Patrón Command
Python
import json
from pathlib import Path
from dataclasses import dataclass, asdict
from typing import Optional
from datetime import datetime
ARCHIVO = Path("tareas.json")
@dataclass
class Tarea:
id: int
titulo: str
completada: bool = False
creada: str = ""
def __post_init__(self):
if not self.creada:
self.creada = datetime.now().isoformat()
class GestorTareas:
def __init__(self):
self.tareas: list[Tarea] = []
self.cargar()
def cargar(self):
if ARCHIVO.exists():
data = json.loads(ARCHIVO.read_text())
self.tareas = [Tarea(**t) for t in data]
def guardar(self):
ARCHIVO.write_text(json.dumps([asdict(t) for t in self.tareas], indent=2))
def agregar(self, titulo: str) -> Tarea:
id_nuevo = max((t.id for t in self.tareas), default=0) + 1
tarea = Tarea(id=id_nuevo, titulo=titulo)
self.tareas.append(tarea)
self.guardar()
return tarea
def completar(self, id: int) -> Optional[Tarea]:
for t in self.tareas:
if t.id == id:
t.completada = True
self.guardar()
return t
return None
def eliminar(self, id: int) -> bool:
inicial = len(self.tareas)
self.tareas = [t for t in self.tareas if t.id != id]
if len(self.tareas) < inicial:
self.guardar()
return True
return False
def listar(self):
for t in self.tareas:
estado = "[x]" if t.completada else "[ ]"
print(f"{t.id}. {estado} {t.titulo}")
def main():
gestor = GestorTareas()
comandos = {
'add': lambda: gestor.agregar(input("Título: ")),
'done': lambda: gestor.completar(int(input("ID: "))),
'del': lambda: gestor.eliminar(int(input("ID: "))),
'list': gestor.listar,
}
while True:
cmd = input("\nComando (add/done/del/list/exit): ").lower()
if cmd == 'exit':
break
if cmd in comandos:
comandos[cmd]()
if __name__ == "__main__":
main()
Zig
const std = @import("std");
const json = std.json;
const Tarea = struct {
id: u32,
titulo: []const u8,
completada: bool,
};
const GestorTareas = struct {
tareas: std.ArrayList(Tarea),
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) GestorTareas {
return .{
.tareas = std.ArrayList(Tarea).init(allocator),
.allocator = allocator,
};
}
pub fn agregar(self: *GestorTareas, titulo: []const u8) !void {
const id = if (self.tareas.items.len > 0)
self.tareas.items[self.tareas.items.len - 1].id + 1
else
1;
try self.tareas.append(.{
.id = id,
.titulo = try self.allocator.dupe(u8, titulo),
.completada = false,
});
}
pub fn completar(self: *GestorTareas, id: u32) bool {
for (self.tareas.items) |*t| {
if (t.id == id) {
t.completada = true;
return true;
}
}
return false;
}
pub fn listar(self: *GestorTareas) !void {
const stdout = std.io.getStdOut().writer();
for (self.tareas.items) |t| {
const estado: []const u8 = if (t.completada) "[x]" else "[ ]";
try stdout.print("{d}. {s} {s}\n", .{ t.id, estado, t.titulo });
}
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var gestor = GestorTareas.init(allocator);
const stdin = std.io.getStdIn().reader();
const stdout = std.io.getStdOut().writer();
var buf: [256]u8 = undefined;
while (true) {
try stdout.print("\nComando (add/done/list/exit): ", .{});
const cmd = stdin.readUntilDelimiter(&buf, '\n') catch break;
if (std.mem.eql(u8, cmd, "exit")) break;
if (std.mem.eql(u8, cmd, "add")) {
try stdout.print("Título: ", .{});
const titulo = stdin.readUntilDelimiter(&buf, '\n') catch continue;
try gestor.agregar(titulo);
} else if (std.mem.eql(u8, cmd, "list")) {
try gestor.listar();
}
}
}
Diferencias Clave
| Aspecto | Python | Zig |
|---|---|---|
| Memoria | Automática | Manual con allocator |
| JSON | Built-in | std.json |
| Listas | list[] | ArrayList |
Ejercicios
- Agrega fechas de vencimiento
- Implementa prioridades (alta/media/baja)
- Agrega filtros por estado