wire.values
import wire.values
wirelifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledwire.values.*needsimport wire.values.
How Wire reads the values a template is given: what counts as true, what a value looks like once it reaches the page, and how a string says that it is already markup and must not be escaped again.
Constants
MAX_ARGUMENTS
wire.values.MAX_ARGUMENTS = 8
The most arguments a filter or a template function can be called with.
Zuri has no way to spread a list into a call, so an argument list built at render time has to be handed over one position at a time and the positions have to be written out. Eight is far past what any filter has ever wanted and stops the dispatch below from growing without end.
Functions
safe()
wire.safe(value) -> Safe
Marks value as markup that Wire must not escape.
A Safe passed back in is returned unchanged rather than wrapped twice.
Anything that is not already a string is rendered with stringify()
first, so safe(nil) is an empty string rather than the word “nil”.
Parameters
value(any)
Returns Safe
is_safe()
wire.is_safe(value) -> bool
True when value is a Safe.
Parameters
value(any)
Returns bool
unwrap()
wire.values.unwrap(value) -> any
Strips the Safe wrapper off value, leaving anything else alone.
Filters work on plain values, so this runs on the way into one and the filter decides for itself whether its result is markup.
Parameters
value(any)
Returns any
stringify()
wire.stringify(value) -> string
What value looks like once it reaches the page, before escaping.
nil renders as an empty string rather than as the word “nil”, which is
what lets an optional variable be dropped into a page without a guard
around it. Everything else is rendered by its own to_string().
Parameters
value(any)
Returns string
truthy()
wire.truthy(value) -> bool
Whether value counts as true in an x-if, an x-not, or a boolean
operator inside an expression.
Wire deliberately does not reuse Zuri’s own truthiness here, because one
of Zuri’s answers is wrong for a template: Zuri treats an empty list and
an empty dictionary as true, so x-if="items" would render a section
for a search that found nothing. Wire treats an empty collection as
false.
Everything else agrees with Zuri: nil and false are false, zero and
NaN are false while every other number is true, an empty string is
false, and anything Wire has no special knowledge of (an instance, a
function, a range) is true.
A variable that was never supplied arrives here as nil, which is why
an optional section can be written as x-if="user" with nothing else
around it.
Parameters
value(any)
Returns bool
is_empty()
wire.values.is_empty(value) -> bool
Whether value has nothing in it, for the empty filter and for
anything else that wants the question asked of a collection rather than
of a value in general.
nil is empty. A number is never empty, not even zero; that is a
question about truthiness, not about emptiness.
Parameters
value(any)
Returns bool
is_blank()
wire.values.is_blank(text: string) -> bool
Whether text is empty or is nothing but whitespace.
Parameters
text(string)
Returns bool
compare()
wire.values.compare(a, b) -> number
Orders a before, with or after b, returning -1, 0 or 1.
Zuri’s ordering operators only take numbers, so anything a template sorts or compares that is not one has to be ordered here. Strings are compared a character at a time by code point, which puts them in the order a person expects for one alphabet and in a defined order for everything else. Two values of different kinds are ordered by how they render, which is arbitrary but stable, and stable is what a sort actually needs.
nil sorts before everything, so a record missing the field being
sorted on still appears rather than dropping out of the list.
Parameters
a(any)b(any)
Returns number
invoke()
wire.values.invoke(target, arguments: list) -> any
Calls target with arguments spread into its parameters.
Passing fewer arguments than the function declares leaves the rest
nil, which is how a filter written as def round(value, places) can
be used as a bare |round.
Parameters
target(callable)arguments(list)
Returns any
Raises ArgumentError when there are more than MAX_ARGUMENTS.
type_name()
wire.values.type_name(value) -> string
Wire’s name for value’s type, used in error messages so that a complaint reads “expected a list, got a number” rather than naming an internal class.
Parameters
value(any)
Returns string
Classes
Safe
class wire.Safe
A string that is already markup and must be written out as it is.
Wire escapes everything it interpolates. That is the right default and
it is not negotiable per-variable from the outside, so the only way to
get live markup into a page is to say so explicitly, either with the
raw filter in a template or by handing Wire one of these from Zuri
code.
import wire
var tpl = wire.wire()
# Escaped, because that is the default.
echo tpl.render_string('{{ note }}', { note: '<b>hi</b>' })
# <b>hi</b>
# Not escaped, because the value says it is markup.
echo tpl.render_string('{{ note }}', { note: wire.safe('<b>hi</b>') })
# <b>hi</b>
Wrapping a value is a promise that it is safe in an HTML context. Wrapping something that came from a user is how a template engine becomes a cross-site scripting hole, so wrap the markup you built, never the input you received.
- printable — has a
@to_string(), soechoandprint()show something useful
Fields
| Field | Type | Description |
|---|---|---|
value | The markup this value carries. |
Constructor
wire.Safe(value: string)
Parameters
value(string)
Safe.to_string()
wire.Safe.to_string() -> string
The markup, unchanged.
Returns string
2026, Richard Ore and The Zuri Contributors