Add linkcheck, fix typos and expand.
This commit is contained in:
@@ -1,17 +1,53 @@
|
||||
Export Variables and Functions from Modules
|
||||
==========================================
|
||||
Export Variables, Functions and Sub-Modules in Module
|
||||
===================================================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
A _module_ is a single script (or pre-compiled `AST`) containing global variables and functions.
|
||||
A _module_ is a single script (or pre-compiled `AST`) containing global variables, functions and sub-modules.
|
||||
|
||||
A module can be created from a script via the `Module::eval_ast_as_new` method. When given an `AST`,
|
||||
it is first evaluated, then the following items are exposed as members of the new module:
|
||||
|
||||
* Global variables - essentially all variables that remain in the [`Scope`] at the end of a script run - that are exported. Variables not exported (via the `export` statement) remain hidden.
|
||||
|
||||
* Functions not specifically marked `private`.
|
||||
|
||||
* Global modules that remain in the [`Scope`] at the end of a script run.
|
||||
|
||||
|
||||
Global Variables
|
||||
----------------
|
||||
|
||||
The `export` statement, which can only be at global level, exposes selected variables as members of a module.
|
||||
|
||||
Variables not exported are _private_ and invisible to the outside.
|
||||
Variables not exported are _private_ and hidden to the outside.
|
||||
|
||||
On the other hand, all functions are automatically exported, _unless_ it is explicitly opt-out with the [`private`] prefix.
|
||||
```rust
|
||||
// This is a module script.
|
||||
|
||||
Functions declared [`private`] are invisible to the outside.
|
||||
let private = 123; // variable not exported - default hidden
|
||||
let x = 42; // this will be exported below
|
||||
|
||||
export x; // the variable 'x' is exported under its own name
|
||||
|
||||
export x as answer; // the variable 'x' is exported under the alias 'answer'
|
||||
// another script can load this module and access 'x' as 'module::answer'
|
||||
|
||||
{
|
||||
let inner = 0; // local variable - it disappears when the statement block ends,
|
||||
// therefore it is not 'global' and is not exported
|
||||
|
||||
export inner; // exporting an temporary variable has no effect
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
All functions are automatically exported, _unless_ it is explicitly opt-out with the [`private`] prefix.
|
||||
|
||||
Functions declared [`private`] are hidden to the outside.
|
||||
|
||||
Everything exported from a module is **constant** (**read-only**).
|
||||
|
||||
@@ -20,13 +56,25 @@ Everything exported from a module is **constant** (**read-only**).
|
||||
|
||||
fn inc(x) { x + 1 } // script-defined function - default public
|
||||
|
||||
private fn foo() {} // private function - invisible to outside
|
||||
|
||||
let private = 123; // variable not exported - default invisible to outside
|
||||
let x = 42; // this will be exported below
|
||||
|
||||
export x; // the variable 'x' is exported under its own name
|
||||
|
||||
export x as answer; // the variable 'x' is exported under the alias 'answer'
|
||||
// another script can load this module and access 'x' as 'module::answer'
|
||||
private fn foo() {} // private function - hidden
|
||||
```
|
||||
|
||||
|
||||
Sub-Modules
|
||||
-----------
|
||||
|
||||
All loaded modules are automatically exported as sub-modules.
|
||||
|
||||
To prevent a module from being exported, load it inside a block statement so that it goes away at the
|
||||
end of the block.
|
||||
|
||||
```rust
|
||||
// This is a module script.
|
||||
|
||||
import "hello" as foo; // exported as sub-module 'foo'
|
||||
|
||||
{
|
||||
import "world" as bar; // not exported - the module disappears at the end
|
||||
// of the statement block and is not 'global'
|
||||
}
|
||||
```
|
||||
|
60
doc/src/language/modules/imp-resolver.md
Normal file
60
doc/src/language/modules/imp-resolver.md
Normal file
@@ -0,0 +1,60 @@
|
||||
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`, 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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<EvalAltResult>> {
|
||||
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();
|
||||
"#)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
@@ -18,10 +18,11 @@ lock::status = "off"; // <- runtime error - cannot modify a constant
|
||||
```
|
||||
|
||||
`import` statements are _scoped_, meaning that they are only accessible inside the scope that they're imported.
|
||||
They can appear anywhere a normal statement can be, but in the vast majority of cases `import` statements are
|
||||
group at the beginning of a script.
|
||||
|
||||
It is, however, not advised to deviate from this common practice unless there is a _Very Good Reason™_.
|
||||
They can appear anywhere a normal statement can be, but in the vast majority of cases `import` statements are
|
||||
group at the beginning of a script. It is, however, not advised to deviate from this common practice unless
|
||||
there is a _Very Good Reason™_.
|
||||
|
||||
Especially, do not place an `import` statement within a loop; doing so will repeatedly re-load the same module
|
||||
during every iteration of the loop!
|
||||
|
||||
@@ -34,7 +35,7 @@ if secured { // new block scope
|
||||
c::encrypt(key); // use a function in the module
|
||||
} // the module disappears at the end of the block scope
|
||||
|
||||
crypto::encrypt(others); // <- this causes a run-time error because the 'crypto' module
|
||||
c::encrypt(others); // <- this causes a run-time error because the 'crypto' module
|
||||
// is no longer available!
|
||||
|
||||
for x in range(0, 1000) {
|
||||
|
Reference in New Issue
Block a user