Update docs regarding modules.

This commit is contained in:
Stephen Chung
2020-07-08 09:48:25 +08:00
parent 236ba40784
commit 150f02d8b7
15 changed files with 134 additions and 59 deletions

View File

@@ -19,14 +19,14 @@ script += "x + y";
let result = eval(script); // <- look, JavaScript, we can also do this!
print("Answer: " + result); // prints 42
result == 42;
print("x = " + x); // prints 10: functions call arguments are passed by value
print("y = " + y); // prints 32: variables defined in 'eval' persist!
x == 10; // prints 10: functions call arguments are passed by value
y == 32; // prints 32: variables defined in 'eval' persist!
eval("{ let z = y }"); // to keep a variable local, use a statement block
print("z = " + z); // <- error: variable 'z' not found
print(z); // <- error: variable 'z' not found
"print(42)".eval(); // <- nope... method-call style doesn't work with 'eval'
```

View File

@@ -14,8 +14,9 @@ fn sub(x, y,) { // trailing comma in parameters list is OK
return x - y;
}
print(add(2, 3)); // prints 5
print(sub(2, 3,)); // prints -1 - trailing comma in arguments list is OK
add(2, 3) == 5;
sub(2, 3,) == -1; // trailing comma in arguments list is OK
```
@@ -35,8 +36,9 @@ fn add2(x) {
return x + 2; // explicit return
}
print(add(2, 3)); // prints 5
print(add2(42)); // prints 44
add(2, 3) == 5;
add2(42) == 44;
```

View File

@@ -22,6 +22,8 @@ The `export` statement, which can only be at global level, exposes selected vari
Variables not exported are _private_ and hidden to the outside.
Everything exported from a module is **constant** (**read-only**).
```rust
// This is a module script.
@@ -49,8 +51,6 @@ All functions are automatically exported, _unless_ it is explicitly opt-out with
Functions declared [`private`] are hidden to the outside.
Everything exported from a module is **constant** (**read-only**).
```rust
// This is a module script.

View File

@@ -1,56 +0,0 @@
Implement a Custom Module Resolver
=================================
{{#include ../../links.md}}
For many applications in which Rhai is embedded, it is necessary to customize the way that modules
are resolved. For instance, modules may need to be loaded from script texts stored in a database,
not in the file system.
A module resolver must implement the trait [`rhai::ModuleResolver`][traits],
which contains only one function: `resolve`.
When Rhai prepares to load a module, `ModuleResolver::resolve` is called with the name
of the _module path_ (i.e. the path specified in the [`import`] statement). Upon success, it should
return a [`Module`]; if the module cannot be load, return `EvalAltResult::ErrorModuleNotFound`.
Example
-------
```rust
use rhai::{ModuleResolver, Module, Engine, EvalAltResult};
// Define a custom module resolver.
struct MyModuleResolver {}
// Implement the 'ModuleResolver' trait.
impl ModuleResolver for MyModuleResolver {
// Only required function.
fn resolve(
&self,
engine: &Engine, // reference to the current 'Engine'
path: &str, // the module path
pos: Position, // location of the 'import' statement
) -> Result<Module, Box<EvalAltResult>> {
// Check module path.
if is_valid_module_path(path) {
// Load the custom module.
let module: Module = load_secret_module(path);
Ok(module)
} else {
Err(Box::new(EvalAltResult::ErrorModuleNotFound(path.into(), pos)))
}
}
}
let mut engine = Engine::new();
// Set the custom module resolver into the 'Engine'.
engine.set_module_resolver(Some(MyModuleResolver {}));
engine.consume(r#"
import "hello" as foo; // this 'import' statement will call
// 'MyModuleResolver::resolve' with "hello" as path
foo:bar();
"#)?;
```

View File

@@ -3,6 +3,7 @@ Import a Module
{{#include ../../links.md}}
`import` Statement
-----------------

View File

@@ -1,29 +0,0 @@
Module Resolvers
================
{{#include ../../links.md}}
When encountering an [`import`] statement, Rhai attempts to _resolve_ the module based on the path string.
_Module Resolvers_ are service types that implement the [`ModuleResolver`][traits] trait.
There are a number of standard resolvers built into Rhai, the default being the `FileModuleResolver`
which simply loads a script file based on the path (with `.rhai` extension attached) and execute it to form a module.
Built-in module resolvers are grouped under the `rhai::module_resolvers` module namespace.
| Module Resolver | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FileModuleResolver` | The default module resolution service, not available under [`no_std`] or [WASM] builds. Loads a script file (based off the current directory) with `.rhai` extension.<br/>The base directory can be changed via the `FileModuleResolver::new_with_path()` constructor function.<br/>`FileModuleResolver::create_module()` loads a script file and returns a module. |
| `StaticModuleResolver` | Loads modules that are statically added. This can be used under [`no_std`]. |
An [`Engine`]'s module resolver is set via a call to `Engine::set_module_resolver`:
```rust
// Use the 'StaticModuleResolver'
let resolver = rhai::module_resolvers::StaticModuleResolver::new();
engine.set_module_resolver(Some(resolver));
// Effectively disable 'import' statements by setting module resolver to 'None'
engine.set_module_resolver(None);
```

View File

@@ -1,30 +0,0 @@
Create a Module from Rust
========================
{{#include ../../links.md}}
To load a custom module (written in Rust) into an [`Engine`], first create a [`Module`] type,
add variables/functions into it, then finally push it into a custom [`Scope`].
This has the equivalent effect of putting an [`import`] statement at the beginning of any script run.
```rust
use rhai::{Engine, Scope, Module, i64};
let mut engine = Engine::new();
let mut scope = Scope::new();
let mut module = Module::new(); // new module
module.set_var("answer", 41_i64); // variable 'answer' under module
module.set_fn_1("inc", |x: i64| Ok(x+1)); // use the 'set_fn_XXX' API to add functions
// Push the module into the custom scope under the name 'question'
// This is equivalent to 'import "..." as question;'
scope.push_module("question", module);
// Use module-qualified variables
engine.eval_expression_with_scope::<i64>(&scope, "question::answer + 1")? == 42;
// Call module-qualified functions
engine.eval_expression_with_scope::<i64>(&scope, "question::inc(question::answer)")? == 42;
```

View File

@@ -15,7 +15,7 @@ The following primitive types are supported natively:
| **[`Array`]** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` |
| **[Object map]** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `"#{ "a": 1, "b": 2 }"` |
| **[Timestamp]** (implemented in the [`BasicTimePackage`][packages], disabled with [`no_std`]) | `std::time::Instant` ([`instant::Instant`] if not [WASM] build) | `"timestamp"` | _not supported_ |
| **[Function pointer]** | _None_ | `Fn` | `"Fn(foo)"` |
| **[Function pointer]** | `rhai::FnPtr` | `Fn` | `"Fn(foo)"` |
| **[`Dynamic`] value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ |
| **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. |
| **System floating-point** (current configuration, disabled with [`no_float`]) | `rhai::FLOAT` (`f32` or `f64`) | `"f32"` or `"f64"` | `"123.456"` etc. |