///|
/// A shopping cart the template can read, loop over and change.
struct Cart {
items : Array[(String, Int32)]
mut coupon : String
}
///|
impl @moonpug.Object for Cart with fn kind(_) {
"the cart"
}
///|
impl @moonpug.Object for Cart with fn attr(self, name) {
match name {
"total" => Some(Int(self.items.fold(init=0, (s, p) => s + p.1).to_int64()))
"coupon" => Some(Text(self.coupon))
_ => None
}
}
///|
impl @moonpug.Object for Cart with fn items(self) {
Some(
self.items.map(p => @moonpug.Value::Tuple([Text(p.0), Int(p.1.to_int64())])),
)
}
///|
impl @moonpug.Object for Cart with fn assign(self, name, value) {
match (name, value) {
("coupon", Text(code)) => self.coupon = code
_ => raise @moonpug.invalid("the cart has no field \{name} to set")
}
}
///|
fn main {
let env = @moonpug.Env::new()
env.add_filter("money", (call, value, _, _) => Text("¥" + call.text(value)))
env.add_global(
"today",
@moonpug.Value::func("today", (_, _, _) => Text("2026-10-25")),
)
let cart = Cart::{ items: [("ink", 12), ("paper", 30)], coupon: "", }
let source =
#|{% for name, price in cart %}{{ name }} {{ price|money }}; {% endfor %}
#|total {{ cart.total|money }} on {{ today() }}
#|{% set cart.coupon = 'AUTUMN' %}coupon {{ cart.coupon }}
println(env.compile(source).render_values({ "cart": Object(cart) })) catch {
e => println("refused: \{e}")
}
}