← Volver al listado de tecnologías

Capítulo 3: Gestor de Tareas CLI

Por: SiempreListo
pythonzigcliintermedio

Gestor de Tareas

Un sistema CRUD completo para gestionar tareas con persistencia en JSON.

Conceptos que Aprenderás

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

AspectoPythonZig
MemoriaAutomáticaManual con allocator
JSONBuilt-instd.json
Listaslist[]ArrayList

Ejercicios

  1. Agrega fechas de vencimiento
  2. Implementa prioridades (alta/media/baja)
  3. Agrega filtros por estado

← Anterior | Siguiente →