Skip to content

Variables And Secrets

Chris Michael edited this page Oct 7, 2026 · 1 revision

Pudu

Variables And Secrets

Loader.load answers Variables.Variables: the process environment, read once, with the loaded values settled over it. Loading never writes the process environment; the values live in this value for as long as the program keeps it, and two loads with different options can coexist. Variables.process() is the same view with no file.

A key is present when its value is set and not empty.

Read Answers
find, has the value, or None / false
text the value, or Missing([key])
int, float, decimal, bool the converted value, Missing, or Malformed(key, kind)
findInt, findFloat, findDecimal, findBool the converted value, or None
secret the value as a Std.App.Secret, or Missing
require(&keys) Ok(()), or Missing with every absent key in the order asked

Whole numbers admit a sign, numbers ignore surrounding space, and a truth value is true or false in any letter case — never yes, 1, or on.

module Ex06Variables

import Std.App.Secret as Secret
import Std.Io as Io
import Std.Map as Map
import PuduLangEnvironment as Environment
import PuduLangEnvironment.Loader as Loader
import PuduLangEnvironment.Options as Options
import PuduLangEnvironment.Source as Source
import PuduLangEnvironment.Variables as Variables

fn line(text: Str) -> () { let _shown = Io.writeLine(text) }

export fn main() -> Int {
  let text = "PORT=8080\nRATIO=0.75\nPRICE=19.99\nDEBUG=False\nTOKEN=tok-123\nHOST=from-file\nBLANK=\n"
  let options = Options.defaults().withSources(&[Source.Text("example", text)]).withoutOverwrite()
  match Loader.loadOver(&options, &Map.fromPairs(&[("HOST", "from-shell")])) {
    case Ok(variables) => {
      line("int PORT        " + show(Variables.int(&variables, "PORT")))
      line("float RATIO     " + show(Variables.float(&variables, "RATIO")))
      line("decimal PRICE   " + show(Variables.decimal(&variables, "PRICE")))
      line("bool DEBUG      " + show(Variables.bool(&variables, "DEBUG")))
      line("int HOST        " + show(Variables.int(&variables, "HOST")))
      line("findInt HOST    " + show(Variables.findInt(&variables, "HOST")))
      line("text HOST       " + show(Variables.text(&variables, "HOST")))
      line("has BLANK       " + show(Variables.has(&variables, "BLANK")))
      line("require         " + show(Variables.require(&variables, &["PORT", "BLANK", "MISSING"])))
      match Variables.secret(&variables, "TOKEN") {
        case Ok(token) => line("secret TOKEN    " + Secret.redact(&token))
        case Err(problem) => line(Environment.describe(&problem))
      }
      line("applied         " + show(variables.applied))
      line("rendered        " + show(variables))
      line(Variables.describe(&variables))
      0
    }
    case Err(_) => 1
  }
}

Output:

int PORT        Ok(8080)
float RATIO     Ok(0.75)
decimal PRICE   Ok(19.99)
bool DEBUG      Ok(false)
int HOST        Err(Malformed("HOST", "a whole number"))
findInt HOST    None
text HOST       Ok("from-shell")
has BLANK       false
require         Err(Missing(["BLANK", "MISSING"]))
secret TOKEN    [REDACTED]
applied         ["BLANK", "DEBUG", "PORT", "PRICE", "RATIO", "TOKEN"]
rendered        Variables{lookup: <fn <fn>>, applied: ["BLANK", "DEBUG", "PORT", "PRICE", "RATIO", "TOKEN"], sources: ["example"], skipped: []}
6 variables applied from example; values are hidden.

HOST kept the shell's value because the load ran withoutOverwrite(); applied lists only the keys the load set. Rendering the view with show prints <fn> where the values are, because they are held behind a function.

Related

Clone this wiki locally