docs: Documentar setSilent() y descripciones extendidas v0.2.4
- setSilent(): carga masiva sin disparar observers - Formato extendido auto_validate: opcion=descripcion - Genera comentarios multilínea en archivo config - 100% compatible hacia atrás 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
3dd835eb51
commit
da50ebfc75
2 changed files with 150 additions and 17 deletions
100
CLAUDE.md
100
CLAUDE.md
|
|
@ -26,7 +26,7 @@ PATH=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2:$PATH zig
|
|||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **Nombre** | zcatconfig |
|
||||
| **Version** | v0.2.3 |
|
||||
| **Version** | v0.2.4 |
|
||||
| **Fecha inicio** | 2025-12-17 |
|
||||
| **Estado** | FUNCIONAL - Integrado en zsimifactu (arquitectura 3 fuentes) |
|
||||
| **Lenguaje** | Zig 0.15.2 |
|
||||
|
|
@ -321,6 +321,103 @@ const separator_pos = blk: {
|
|||
|
||||
---
|
||||
|
||||
## setSilent() - Carga masiva sin observers (v0.2.4)
|
||||
|
||||
### Problema
|
||||
|
||||
Al cargar config desde BD, cada `set()` dispara observers que escriben de vuelta a BD → loop infinito de logs.
|
||||
|
||||
### Solución
|
||||
|
||||
`setSilent()` establece valores SIN notificar observers:
|
||||
|
||||
```zig
|
||||
// Cargar desde BD sin disparar observers
|
||||
var stmt = try db.prepare("SELECT config_key, config_value FROM config_backup");
|
||||
while (try stmt.step()) {
|
||||
const key = stmt.columnText(0) orelse continue;
|
||||
const value = stmt.columnText(1) orelse continue;
|
||||
// Usar setSilent en vez de set
|
||||
manager.setSilent(key, value) catch continue;
|
||||
}
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
```zig
|
||||
/// Establece valor SIN notificar observers
|
||||
/// Útil para carga masiva desde BD
|
||||
pub fn setSilent(self: *Self, key: []const u8, value: []const u8) ConfigError!void
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DESCRIPCIONES EXTENDIDAS EN ARCHIVO CONFIG (v0.2.4)
|
||||
|
||||
### Problema
|
||||
|
||||
El archivo de configuración mostraba opciones pero no explicaba qué hacía cada una:
|
||||
|
||||
```
|
||||
@validacion_nif_modo: Estricto # Modo validación NIF [Estricto,Permisivo,Desactivado]
|
||||
```
|
||||
|
||||
El usuario ve las opciones pero no sabe qué significa cada una.
|
||||
|
||||
### Solución: Formato extendido en auto_validate
|
||||
|
||||
En `config_variables`, usar formato `opcion=descripcion`:
|
||||
|
||||
```zig
|
||||
// Formato simple (sin descripciones):
|
||||
.{ "mi_var", .string, .cat, "Op1,Op2,Op3", "Descripción", ... }
|
||||
|
||||
// Formato extendido (con descripciones):
|
||||
.{ "mi_var", .string, .cat, "Op1=Hace X,Op2=Hace Y,Op3=Hace Z", "Descripción", ... }
|
||||
```
|
||||
|
||||
### Resultado en archivo config
|
||||
|
||||
**Formato simple** (sin `=`):
|
||||
```
|
||||
@mi_var: Op1 # Descripción [Op1,Op2,Op3]
|
||||
```
|
||||
|
||||
**Formato extendido** (con `=`):
|
||||
```
|
||||
# Descripción
|
||||
# Op1: Hace X
|
||||
# Op2: Hace Y
|
||||
# Op3: Hace Z
|
||||
@mi_var: Op1
|
||||
```
|
||||
|
||||
### Ejemplo real
|
||||
|
||||
```zig
|
||||
// En config_unified.zig:
|
||||
.{ "validacion_nif_modo", .string, Cat.validaciones,
|
||||
"Estricto=Bloquea guardar si NIF inválido,Permisivo=Avisa pero permite guardar,Desactivado=Sin validación",
|
||||
"Modo validación NIF", false, "# VALIDACIONES" },
|
||||
```
|
||||
|
||||
Genera:
|
||||
```
|
||||
# Modo validación NIF
|
||||
# Estricto: Bloquea guardar si NIF inválido
|
||||
# Permisivo: Avisa pero permite guardar
|
||||
# Desactivado: Sin validación
|
||||
@validacion_nif_modo: Estricto
|
||||
```
|
||||
|
||||
### Compatibilidad
|
||||
|
||||
- Si `auto_validate` NO contiene `=` → formato simple (actual)
|
||||
- Si `auto_validate` contiene `=` → formato extendido (nuevo)
|
||||
- 100% compatible con archivos existentes
|
||||
|
||||
---
|
||||
|
||||
## EQUIPO
|
||||
|
||||
- **Usuario (R.Eugenio)**: Desarrollador principal
|
||||
|
|
@ -332,6 +429,7 @@ const separator_pos = blk: {
|
|||
|
||||
| Fecha | Version | Commit | Cambios |
|
||||
|-------|---------|--------|---------|
|
||||
| 2025-12-25 | v0.2.4 | `3dd835e` | setSilent() + descripciones extendidas en archivo config |
|
||||
| 2025-12-18 | v0.2.3 | `957767d` | validateIntRange/Float fix: rangos negativos `"-100-100"` |
|
||||
| 2025-12-18 | v0.2.2 | `0ef5efd` | initDeferred(): control manual sin auto-crear archivo |
|
||||
| 2025-12-18 | v0.2.1 | - | FileWatcher, loadFromString, updateMtime |
|
||||
|
|
|
|||
|
|
@ -563,7 +563,41 @@ pub fn save(
|
|||
const value_len = value.len;
|
||||
const total_len = key_len + 2 + value_len;
|
||||
|
||||
// Construir comentario con opciones válidas si existen
|
||||
// Verificar si tiene descripciones extendidas (formato "opcion=desc,opcion2=desc2")
|
||||
const has_descriptions = if (v.auto_validate) |valid|
|
||||
std.mem.indexOf(u8, valid, "=") != null
|
||||
else
|
||||
false;
|
||||
|
||||
if (has_descriptions) {
|
||||
// Formato extendido: comentarios multilínea
|
||||
// # Descripción de la variable
|
||||
// # Opcion1: Descripción 1
|
||||
// # Opcion2: Descripción 2
|
||||
// @variable: valor
|
||||
var desc_line: [256]u8 = undefined;
|
||||
const desc_text = std.fmt.bufPrint(&desc_line, "# {s}\n", .{v.description}) catch "";
|
||||
try file.writeAll(desc_text);
|
||||
|
||||
// Parsear opciones con descripciones
|
||||
var options_iter = std.mem.splitScalar(u8, v.auto_validate.?, ',');
|
||||
while (options_iter.next()) |option_desc| {
|
||||
if (std.mem.indexOf(u8, option_desc, "=")) |eq_pos| {
|
||||
const opt_name = option_desc[0..eq_pos];
|
||||
const opt_desc = option_desc[eq_pos + 1 ..];
|
||||
const opt_line = std.fmt.bufPrint(&desc_line, "# {s}: {s}\n", .{ opt_name, opt_desc }) catch "";
|
||||
try file.writeAll(opt_line);
|
||||
}
|
||||
}
|
||||
|
||||
// Escribir variable sin comentario inline
|
||||
const line = std.fmt.bufPrint(&line_buf, "{s}: {s}\n", .{
|
||||
v.config_key,
|
||||
value,
|
||||
}) catch unreachable;
|
||||
try file.writeAll(line);
|
||||
} else {
|
||||
// Formato simple: comentario inline con opciones entre corchetes
|
||||
var comment_buf: [256]u8 = undefined;
|
||||
const comment: []const u8 = if (v.auto_validate) |valid|
|
||||
std.fmt.bufPrint(&comment_buf, "{s} [{s}]", .{ v.description, valid }) catch v.description
|
||||
|
|
@ -577,16 +611,17 @@ pub fn save(
|
|||
value,
|
||||
spaces(padding),
|
||||
comment,
|
||||
}) catch unreachable; // Buffer 1024 es suficiente
|
||||
}) catch unreachable;
|
||||
try file.writeAll(line);
|
||||
} else {
|
||||
const line = std.fmt.bufPrint(&line_buf, "{s}: {s}\n", .{
|
||||
v.config_key,
|
||||
value,
|
||||
}) catch unreachable; // Buffer 1024 es suficiente
|
||||
}) catch unreachable;
|
||||
try file.writeAll(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try file.writeAll("\n");
|
||||
try file.writeAll("# ============================================================================\n");
|
||||
|
|
|
|||
Loading…
Reference in a new issue