docs: explain what distinguishes validate (+ comment audit) #11

Merged
aneurin merged 4 commits from docs-positioning into main 2026-09-07 16:35:55 +00:00
Member

Closes #3.

Per the note on the issue, this starts with a comment audit, then does the docs.

Commit 1 — fix incorrect and vague doc comments

Comments only, no behaviour change.

  • number.goMin, MinFloat32, MinFloat64 all said "less than or equal to a given maximum" (copy-pasted from the Max family). They check the minimum.
  • chars_test.goExampleExceptChars called Chars, not ExceptChars, so it never exercised the function it documents.
  • chars.go — "does not contain disallowed characters" was circular.
  • in.goNotIn's parameter was named allow; renamed to disallow.
  • length.go — noted length is bytes (len), not runes (the %d characters messages imply otherwise).
  • url.go — spelled out that ParseRequestURI wants an absolute URL or path ("example.com" fails).
  • uuid.go — noted lowercase-hex only, version/variant not checked.
  • error.go — documented Err (match-anything sentinel), how Error() formats with Data, and what With does. all.go points at Collect.

Commit 2 — docs: positioning README, package doc, usage examples

  • doc.go — package overview: what a validator is, All vs Collect, errors-as-sentinels, a comparison with validator/v10 (tags + reflection), ozzo-validation (Rule interface) and govalidator (IsX helpers), and a "when to use something else".
  • README.md — rewritten from three lines: positioning intro, "why this and not X" table, building-blocks table, "not a fit if" note.
  • example_test.go — runnable Example (compose built-ins + an inline closure), Example_collectAll (errors.Is over a joined error), Example_errorsIs (sentinel matching).

gofmt / go vet ./... / go test ./... all green; every example has verified output.

🤖 Generated with Claude Code

Closes #3. Per the note on the issue, this starts with a comment audit, then does the docs. ### Commit 1 — `fix incorrect and vague doc comments` Comments only, no behaviour change. - **`number.go`** — `Min`, `MinFloat32`, `MinFloat64` all said *"less than or equal to a given maximum"* (copy-pasted from the `Max` family). They check the minimum. - **`chars_test.go`** — `ExampleExceptChars` called `Chars`, not `ExceptChars`, so it never exercised the function it documents. - **`chars.go`** — "does not contain disallowed characters" was circular. - **`in.go`** — `NotIn`'s parameter was named `allow`; renamed to `disallow`. - **`length.go`** — noted length is bytes (`len`), not runes (the `%d characters` messages imply otherwise). - **`url.go`** — spelled out that `ParseRequestURI` wants an absolute URL or path (`"example.com"` fails). - **`uuid.go`** — noted lowercase-hex only, version/variant not checked. - **`error.go`** — documented `Err` (match-anything sentinel), how `Error()` formats with `Data`, and what `With` does. **`all.go`** points at `Collect`. ### Commit 2 — `docs: positioning README, package doc, usage examples` - **`doc.go`** — package overview: what a validator is, `All` vs `Collect`, errors-as-sentinels, a comparison with `validator/v10` (tags + reflection), `ozzo-validation` (`Rule` interface) and `govalidator` (`IsX` helpers), and a "when to use something else". - **`README.md`** — rewritten from three lines: positioning intro, "why this and not X" table, building-blocks table, "not a fit if" note. - **`example_test.go`** — runnable `Example` (compose built-ins + an inline closure), `Example_collectAll` (`errors.Is` over a joined error), `Example_errorsIs` (sentinel matching). `gofmt` / `go vet ./...` / `go test ./...` all green; every example has verified output. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude added 2 commits 2026-09-07 13:01:20 +00:00
Audit ahead of the README/doc.go work (issue #3):

- number.go: Min, MinFloat32, MinFloat64 all said "less than or equal to a
  given maximum" -- copy-pasted from the Max family. They check the
  minimum. Fixed.
- chars_test.go: ExampleExceptChars called Chars, not ExceptChars, so it
  never exercised the function it documents.
- chars.go: "does not contain disallowed characters" was circular.
- in.go: NotIn's parameter was named "allow"; renamed to "disallow".
- length.go: note that length is bytes (len), not runes -- the "%d
  characters" messages imply otherwise.
- url.go: spell out that ParseRequestURI wants an absolute URL or path.
- uuid.go: note lowercase-hex only, version/variant not checked.
- error.go: explain Err (the match-anything sentinel), how Error() formats
  with Data, and what With does. all.go: point at Collect.

Comments only; no behaviour change. go vet + go test ./... pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs: positioning README, package doc, usage examples
CI / test (pull_request) Successful in 43s
4483105a78
Closes #3.

- doc.go: package overview -- what a validator is, All vs Collect, errors
  are sentinels, how this compares to validator/v10 (tags+reflection),
  ozzo-validation (Rule interface) and govalidator (IsX helpers), and when
  to pick something else.
- README.md: rewritten from three lines to a positioning intro, a
  "why this and not X" table, a building-blocks table, and a
  "not a fit if" note.
- example_test.go: runnable Example (compose built-ins + a closure),
  Example_collectAll (errors.Is over a joined error), Example_errorsIs
  (sentinel matching, Err as match-anything).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
length.go Outdated
@@ -7,2 +7,3 @@
// MaxLength validates the length of a string as being less than or equal to a given maximum.
// MaxLength validates that a string is no longer than a given maximum.
// Length is measured in bytes (len), not runes.
Owner

The original intention was to measure text length. Does this make it more correct to measure runes rather than bytes?

The original intention was to measure text length. Does this make it more correct to measure runes rather than bytes?
claude added 1 commit 2026-09-07 15:27:31 +00:00
length: count runes, not bytes
CI / test (pull_request) Successful in 34s
4e2e05c1b9
MinLength/MaxLength measured len(value), so a string of 8 accented
characters (9+ bytes) failed MaxLength(8) despite the error message
promising "characters". Count with utf8.RuneCountInString so the check
matches the wording and the common-sense intent.

Still not grapheme-cluster aware (combining marks, emoji ZWJ sequences
count as several runes), which is out of scope for a stdlib-only helper.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Author
Member

Good call — switched MinLength/MaxLength to count runes via utf8.RuneCountInString in 4e2e05c, so the check now matches the "characters" wording. Added test cases with accented input that is within the rune limit but over the byte limit. Still stdlib-only; grapheme clusters (combining marks, emoji ZWJ sequences) still count as multiple runes, which I noted in the commit message as out of scope.

Good call — switched `MinLength`/`MaxLength` to count runes via `utf8.RuneCountInString` in 4e2e05c, so the check now matches the "characters" wording. Added test cases with accented input that is within the rune limit but over the byte limit. Still stdlib-only; grapheme clusters (combining marks, emoji ZWJ sequences) still count as multiple runes, which I noted in the commit message as out of scope.
aneurin requested changes 2026-09-07 15:32:45 +00:00
Dismissed
aneurin left a comment
Owner

Now that Min/MaxLength count runes, we are lacking a byte length validator, which may still be useful.

Add MaxLengthBytes and MinLengthBytes to fill the gap.

Now that Min/MaxLength count runes, we are lacking a byte length validator, which may still be useful. Add MaxLengthBytes and MinLengthBytes to fill the gap.
claude added 1 commit 2026-09-07 15:48:31 +00:00
length: add MinLengthBytes / MaxLengthBytes
CI / test (push) Successful in 37s
CI / test (pull_request) Successful in 34s
164dcbf367
MinLength/MaxLength now count runes, leaving no way to bound a string by
its byte size -- still wanted for fixed-width columns and wire-format
fields. Add the byte-counting pair alongside them, with their own "%d
bytes" sentinels (ErrMustHaveMoreBytes / ErrMustHaveFewerBytes).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Author
Member

Added MinLengthBytes / MaxLengthBytes in 164dcbf, with their own ErrMustHaveMoreBytes / ErrMustHaveFewerBytes sentinels (%d bytes wording) and tests using multibyte input where the byte and rune counts diverge. Doc comments cross-reference the rune-counting pair and vice versa; README building-blocks row updated.

Added `MinLengthBytes` / `MaxLengthBytes` in 164dcbf, with their own `ErrMustHaveMoreBytes` / `ErrMustHaveFewerBytes` sentinels (`%d bytes` wording) and tests using multibyte input where the byte and rune counts diverge. Doc comments cross-reference the rune-counting pair and vice versa; README building-blocks row updated.
claude requested review from aneurin 2026-09-07 15:48:48 +00:00
aneurin approved these changes 2026-09-07 16:20:49 +00:00
aneurin merged commit 164dcbf367 into main 2026-09-07 16:35:55 +00:00
aneurin deleted branch docs-positioning 2026-09-07 16:35:55 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: go/validate#11