testmark-go

add comprehensive v2 examples and documentation

commit 402420e892dea1268b690a3c2a4dadca11932183 · parent 13b63c6f85 · browse this tree
Ximainth, 2025-10-19 10:20:48 UTC

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: sb34fb4d228c4a67fk
diff --git a/v2/EXAMPLE.md b/v2/EXAMPLE.md
new file mode 100644
index 0000000..a3b76cb
--- /dev/null
+++ b/v2/EXAMPLE.md
@@ -0,0 +1,143 @@
+# Testmark v2 Examples
+
+This document demonstrates the key improvements in testmark v2.
+
+## Before: v1 Pain Points
+
+```go
+// v1 required lots of boilerplate
+func oldWay() {
+    doc, err := testmark.ReadFile("data.md")
+    if err != nil {
+        panic(err)
+    }
+    
+    // Required manual step!
+    doc.BuildDirIndex()
+    
+    // Manual patch accumulator setup
+    patches := &testmark.PatchAccumulator{}
+    
+    // Direct field access (error-prone)
+    for _, hunk := range doc.DataHunks {
+        fmt.Println(hunk.Name) // Accessing fields directly
+        if shouldUpdate {
+            patches.AppendPatch(testmark.Hunk{
+                Name: hunk.Name,
+                Body: []byte("new content"),
+            })
+        }
+    }
+    
+    // Complex patching
+    newDoc := testmark.Patch(doc, patches.Patches...)
+    
+    // Manual directory navigation
+    if doc.DirEnt != nil {
+        child := doc.DirEnt.Children["config"]
+        // null checks, manual iteration...
+    }
+}
+```
+
+## After: v2 Clean API
+
+```go
+// v2 is much cleaner and safer
+func newWay() {
+    // Auto-indexing, no BuildDirIndex needed!
+    doc := testmark.MustReadFile("data.md")
+    
+    fmt.Printf("Loaded %d hunks\n", doc.Count())
+    
+    // Safe iteration with clean accessors
+    for iter := doc.Hunks(); iter.Next(); {
+        hunk := iter.Hunk()
+        fmt.Printf("%s: %s\n", hunk.Name(), hunk.String())
+    }
+    
+    // Clean patching
+    newHunk := testmark.NewHunkString("config/db", "json", `{"host": "new-host"}`)
+    updated := doc.Patch(newHunk)
+    
+    // Safe directory navigation
+    config := doc.Root().Child("config")
+    if config != nil {
+        for iter := config.Children(); iter.Next(); {
+            entry := iter.Entry()
+            fmt.Printf("Config %s: %s\n", entry.Name(), entry.Hunk().String())
+        }
+    }
+    
+    // Easy serialization
+    fmt.Println(updated.String())
+}
+```
+
+## Key Improvements Summary
+
+### ✅ **Eliminated Boilerplate**
+- No more `doc.BuildDirIndex()` - happens automatically
+- No more `&testmark.PatchAccumulator{}` setup
+- No more manual null checks and field access
+
+### ✅ **Private Fields = Safer Code**
+```go
+// v1: Error-prone direct access
+doc.DataHunks[0].Name = "oops" // Could break things!
+
+// v2: Clean accessors only
+hunk := doc.HunkByName("name")
+name := hunk.Name() // Read-only, safe
+```
+
+### ✅ **Immutable Operations**
+```go
+// v2: Original documents never change
+original := testmark.MustReadFile("data.md")
+modified := original.Patch(newHunk)
+// 'original' is unchanged, 'modified' is new
+```
+
+### ✅ **Safe Iterators**
+```go
+// v2: No direct slice access
+for iter := doc.Hunks(); iter.Next(); {
+    hunk := iter.Hunk() // Safe, controlled access
+    // No risk of modifying internal state
+}
+```
+
+### ✅ **Method Chaining**
+```go
+// v2: Fluent API
+doc := testmark.MustReadFile("data.md")
+    .EnablePatching()
+    .Patches()
+    .Add(newHunk)
+```
+
+### ✅ **Contemporary Patterns**
+```go
+// v2: Modern flag handling
+var regenFlag = flag.Bool("testmark.regen", false, "regen fixtures")
+
+if testmark.ShouldRegen() {
+    // Handle regeneration
+}
+```
+
+## Migration Guide
+
+| v1 Pattern | v2 Replacement |
+|------------|----------------|
+| `doc.BuildDirIndex()` | *automatic* |
+| `doc.DataHunks` | `doc.Hunks()` iterator |
+| `doc.HunksByName[name]` | `doc.HunkByName(name)` |
+| `doc.DirEnt.Children[name]` | `doc.Root().Child(name)` |
+| `&testmark.PatchAccumulator{}` | `doc.EnablePatching().Patches()` |
+| Multiple package imports | Single `v2` import |
+| Direct field access | Private fields + accessors |
+| Mutable operations | Immutable (returns new docs) |
+
+The v2 API is designed to make the "right thing" easy and the "wrong thing" impossible through good API design.