Skip to main content

doge_runtime/stdlib/
env.rs

1//! `env` — command-line arguments and environment variables. The script's
2//! arguments are captured once at startup (`set_script_args`, called from the
3//! generated `main` and the interpreter's CLI path) into a process-global slot;
4//! `env.args()` reads them back and `env.get(name)` reads the OS environment.
5
6use std::sync::OnceLock;
7
8use crate::error::DogeResult;
9use crate::stdlib::str_arg;
10use crate::value::Value;
11
12/// The script's command-line arguments (excluding the program name), set once at
13/// startup. Unset until `set_script_args` runs, which reads back as no arguments.
14static SCRIPT_ARGS: OnceLock<Vec<String>> = OnceLock::new();
15
16/// Record the script's command-line arguments. Called once at program startup
17/// (compiled `main` or the interpreter's file runner); any later call is ignored,
18/// so the arguments a script sees are fixed for its whole run.
19pub fn set_script_args(args: Vec<String>) {
20    let _ = SCRIPT_ARGS.set(args);
21}
22
23/// `env.args()` — the script's command-line arguments as a List of Str, excluding
24/// the program name. Empty when the script was given none.
25pub fn env_args() -> DogeResult {
26    let args = SCRIPT_ARGS
27        .get()
28        .map(|args| args.iter().map(Value::str).collect())
29        .unwrap_or_default();
30    Ok(Value::list(args))
31}
32
33/// `env.get(name)` — the value of environment variable `name` as a Str, or `none`
34/// when it is unset or not valid text.
35pub fn env_get(name: &Value) -> DogeResult {
36    let name = str_arg("env", "get", name)?;
37    match std::env::var(name) {
38        Ok(value) => Ok(Value::str(value)),
39        Err(_) => Ok(Value::None),
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn args_default_to_empty() {
49        // No `set_script_args` runs in this test binary, so the slot is unset.
50        match env_args().unwrap() {
51            Value::List(items) => assert!(items.borrow().is_empty()),
52            _ => panic!("expected a list"),
53        }
54    }
55
56    #[test]
57    fn get_of_an_unset_variable_is_none() {
58        let unset = Value::str("DOGE_SURELY_UNSET_VARIABLE_KABOSU");
59        assert!(matches!(env_get(&unset).unwrap(), Value::None));
60    }
61}