Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/language-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,27 @@ Exact lowering still depends on your embedder; `example.wit` is the reference. A

---

## 1.1 Environment variables (`env.<name>`)

Rib supports host input only via **environment variables** with the `env` namespace.

- Use exactly one segment: `env.<name>` (for example `env.TOKEN_ID`).
- Nested paths are rejected: `env.a.b` is invalid.
- The value is always inferred as `string`.
- Name matching is **exact and 1:1** with the environment key.
- If the key is `TOKEN_ID`, use `env.TOKEN_ID`.
- If the key is `TOKEN-ID`, use `env.TOKEN-ID`.
- If the key is `token`, use `env.token`.
- There is no normalization or aliasing (`TOKEN_ID` is not auto-mapped from `token-id`, etc.).

```rust
let token: string = env.TOKEN_ID;
let region: string = env.DEPLOY_REGION;
"token=${token}, region=${region}"
```

---

## 2. Programs, blocks, and semicolons

A Rib **program** is a sequence of expressions separated by **`;`**. The value of the whole program is the **last** expression (REPLs usually print that).
Expand Down
18 changes: 18 additions & 0 deletions rib-lang/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ The **`rib-repl`** crate in this repository consumes the same pipeline for inter

---

## Environment input model

Rib reads host-provided input only via `env.<name>`.

- **Single segment only**: `env.a` is valid; `env.a.b` is rejected.
- **Exact key mapping**: `<name>` is used as-is for lookup in `RibInput` and process environment variables.
- **String-only**: values from `env.<name>` are always typed as `string`.

Examples:

- env key `TOKEN_ID` -> `env.TOKEN_ID`
- env key `TOKEN-ID` -> `env.TOKEN-ID`
- env key `token` -> `env.token`

No key normalization or alternate spellings are applied.

---

## Advanced usage (beyond the REPL)

Most people meet Rib in a **REPL**; **`rib-lang`** is also for **embedding** in your own Rust binary. There, Rib helps when components grow **many exports**, when you **revise WIT or ship new component versions often**, or when you want **short, typed programs** plugged into the **output** of component calls—post-process, reshape, validate—without hand-writing and re-hand-writing the same glue in Rust (or JSON shims) for every export and every shape change. You wire **analysed exports** into the registry once; Rib text is **checked against that surface** on each compile, so updating the component tends to surface mistakes in the script **before** a bad call reaches Wasm.
Expand Down
34 changes: 16 additions & 18 deletions rib-lang/regression_tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use rib::{
async fn rib_compiler_interpreter_end_to_end_worker_metadata_matrix() {
let expr = r#"
let worker = instance();
let str1: string = request.body.name;
let str2: string = request.headers.name;
let str3: string = request.path.name;
let str1: string = env.API_TOKEN;
let str2: string = env.CLIENT_NAME;
let str3: string = env.DEPLOY_REGION;

let unused = worker.function-unit-response(str1);

Expand Down Expand Up @@ -474,7 +474,6 @@ async fn rib_compiler_interpreter_end_to_end_worker_metadata_matrix() {
let compiler = RibCompiler::new(RibCompilerConfig::new(
component_metadata::component_metadata(),
vec![],
vec![],
));

use std::time::Instant;
Expand Down Expand Up @@ -1709,15 +1708,14 @@ mod mock_data {
}

mod mock_interpreter {
use crate::{mock_data, test_utils, Interpreter};
use crate::{mock_data, Interpreter};
use crate::{
EvaluatedFnArgs, EvaluatedFqFn, EvaluatedWorkerName, RibComponentFunctionInvoke,
RibFunctionInvokeResult, RibInput,
};
use async_trait::async_trait;

use rib::wit_type::WitType;
use rib::wit_type::{field, record, str};
use rib::ValueAndType;
use rib::{ComponentDependencyKey, DefaultWorkerNameGenerator, InstructionId};
use std::collections::HashMap;
Expand Down Expand Up @@ -1876,19 +1874,19 @@ mod mock_interpreter {
.map(|(name, result)| (FunctionName(name.to_string()), result))
.collect();

let record_input_type = record(vec![
field("headers", record(vec![field("name", str())])),
field("body", record(vec![field("name", str())])),
field("path", record(vec![field("name", str())])),
]);

let record_input_value = test_utils::get_value_and_type(
&record_input_type,
r#" { headers : { name : "foo" }, body : { name : "bar" }, path : { name : "baz" } }"#,
);

let mut interpreter_env_input: HashMap<String, ValueAndType> = HashMap::new();
interpreter_env_input.insert("request".to_string(), record_input_value);
interpreter_env_input.insert(
"API_TOKEN".to_string(),
ValueAndType::new(rib::Value::String("bar".to_string()), rib::wit_type::str()),
);
interpreter_env_input.insert(
"CLIENT_NAME".to_string(),
ValueAndType::new(rib::Value::String("foo".to_string()), rib::wit_type::str()),
);
interpreter_env_input.insert(
"DEPLOY_REGION".to_string(),
ValueAndType::new(rib::Value::String("baz".to_string()), rib::wit_type::str()),
);

dynamic_test_interpreter(functions_and_result, interpreter_env_input)
}
Expand Down
Loading
Loading