func Blocks
Blocks renders a block count at a coarse magnitude — deliberately vague, because a block count is not a wall-clock duration.
Package humanize formats numbers for people rather than machines, as a pure, reusable package: byte sizes, thousands ...
gno.land/p/moul/x/daily/humanize/v0Human-facing number formatting — Bytes, Comma, Ordinal, Plural,
Blocks, Truncate.
1import "gno.land/p/moul/x/daily/humanize/v0"
2
3humanize.Bytes(1536) // "1.5 KiB"
4humanize.Comma(1234567) // "1,234,567"
5humanize.Ordinal(12) // "12th" — not "12nd"
6humanize.Plural(2, "mouse", "mice") // "2 mice"
7humanize.Blocks(1234) // "~1,200 blocks"
8humanize.Truncate("ééé", 2) // "é…"
Integer-only, on purpose. No floats anywhere: a rendered value that differed
between nodes would be a consensus bug, so the single decimal place in Bytes
comes from scaling by 10 and taking a remainder.
Durations are in blocks, never seconds. There is no wall clock on chain, so
"about 2 hours" is a lie dressed as precision. Blocks says ~1,200 blocks and
lets the caller decide what that means on their chain — and rounds deliberately,
because false precision is worse than none.
Ordinal handles the teens (11th/12th/13th, not 11st/12nd/13rd) —
the case naive implementations get wrong. Truncate counts runes, so
multi-byte text is never sliced mid-character.
Live demo: r/moul/x/daily/humanizedemo
· render it at /r/moul/x/daily/humanizedemo/v0.
Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.
Package humanize formats numbers for people rather than machines, as a pure, reusable package: byte sizes, thousands separators, ordinals, pluralisation and block-height "durations".
Everything is integer-only. There are no floats here on purpose: gno has no float determinism guarantees worth relying on for consensus output, and a rendered value that differs between nodes would be a consensus bug. One decimal place is produced by scaling by 10 and taking a remainder.
Durations are expressed in BLOCKS, not seconds. There is no wall clock on chain, so "about 2 hours" is a lie dressed as precision; this package says "~1200 blocks" and lets the caller decide what that means on their chain.
A live demo of this package is at r/moul/x/daily/humanizedemo(/r/moul/x/daily/humanizedemo/v0).
Blocks renders a block count at a coarse magnitude — deliberately vague, because a block count is not a wall-clock duration.
Bytes renders n bytes with SI-ish binary units and one decimal place. Negative input is rendered with a leading minus rather than rejected.
Comma inserts thousands separators: 1234567 -> "1,234,567".
Ordinal renders 1 -> "1st", 2 -> "2nd", 11 -> "11th".
The teens are the trap: 11/12/13 take "th" despite ending in 1/2/3, so the 11–13 case must be checked before the last digit.
Plural returns "1 block" / "2 blocks", using plural when given, else word+"s".
Truncate shortens s to at most max runes, appending "…" when it cut. Counts RUNES, not bytes, so a multi-byte string is not sliced mid-character.