...
This commit is contained in:
		
							
								
								
									
										116
									
								
								rhai_engine/rhaibook/language/modules/export.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								rhai_engine/rhaibook/language/modules/export.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
			
		||||
Export Variables, Functions and Sub-Modules From a Script
 | 
			
		||||
=========================================================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish info.side "See also"
 | 
			
		||||
 | 
			
		||||
See [_Create a Module from AST_]({{rootUrl}}/rust/modules/ast.md) for more details.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The easiest way to expose a collection of [functions] as a self-contained [module] is to do it via a Rhai script itself.
 | 
			
		||||
 | 
			
		||||
The script text is evaluated.
 | 
			
		||||
 | 
			
		||||
[Variables] are then selectively exposed via the `export` statement.
 | 
			
		||||
 | 
			
		||||
[Functions] defined by the script are automatically exported, unless marked as `private`.
 | 
			
		||||
 | 
			
		||||
Modules loaded within this [module] at the global level become _sub-modules_ and are also automatically exported.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Export Global Variables
 | 
			
		||||
-----------------------
 | 
			
		||||
 | 
			
		||||
The `export` statement, which can only be at global level, exposes a selected [variable] as member of a [module].
 | 
			
		||||
 | 
			
		||||
[Variables] not exported are _private_ and hidden. They are merely used to initialize the [module],
 | 
			
		||||
but cannot be accessed from outside.
 | 
			
		||||
 | 
			
		||||
Everything exported from a [module] is **[constant]** (i.e. read-only).
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// This is a module script.
 | 
			
		||||
 | 
			
		||||
let hidden = 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 const x = 42;    // convenient short-hand to declare a constant and export it
 | 
			
		||||
                        // under its own name
 | 
			
		||||
 | 
			
		||||
export let x = 123;     // variables can be exported as well, though it'll still be constant
 | 
			
		||||
 | 
			
		||||
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 statements block ends,
 | 
			
		||||
                        //                  therefore it is not 'global' and cannot be exported
 | 
			
		||||
 | 
			
		||||
    export inner;       // <- syntax error: cannot export a local variable
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Multiple exports"
 | 
			
		||||
 | 
			
		||||
[Variables] can be exported under multiple names.
 | 
			
		||||
For example, the following exports three [variables]:
 | 
			
		||||
* `x` as `x` and `hello`
 | 
			
		||||
* `y` as `foo` and `bar`
 | 
			
		||||
* `z` as `z`
 | 
			
		||||
 | 
			
		||||
~~~js
 | 
			
		||||
export x;
 | 
			
		||||
export x as hello;
 | 
			
		||||
export y as foo;
 | 
			
		||||
export x as world;
 | 
			
		||||
export y as bar;
 | 
			
		||||
export z;
 | 
			
		||||
~~~
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Export Functions
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
```admonish info.side "Private functions"
 | 
			
		||||
 | 
			
		||||
`private` [functions] are commonly called within the [module] only.
 | 
			
		||||
They cannot be accessed otherwise.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
All [functions] are automatically exported, _unless_ it is explicitly opt-out with the `private` prefix.
 | 
			
		||||
 | 
			
		||||
[Functions] declared `private` are hidden to the outside.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// This is a module script.
 | 
			
		||||
 | 
			
		||||
fn inc(x) { x + 1 }     // script-defined function - default public
 | 
			
		||||
 | 
			
		||||
private fn foo() {}     // private function - hidden
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Sub-Modules
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
All loaded [modules] are automatically exported as sub-modules.
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: Skip exporting a module"
 | 
			
		||||
 | 
			
		||||
To prevent a [module] from being exported, load it inside a block statement so that it goes away at the
 | 
			
		||||
end of the block.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// This is a module script.
 | 
			
		||||
 | 
			
		||||
import "hello" as foo;      // <- exported
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
    import "world" as bar;  // <- not exported
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										132
									
								
								rhai_engine/rhaibook/language/modules/import.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								rhai_engine/rhaibook/language/modules/import.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
Import a Module
 | 
			
		||||
===============
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish info.side "See also"
 | 
			
		||||
 | 
			
		||||
See [_Module Resolvers_][module resolver] for more details.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Before a [module] can be used (via an `import` statement) in a script, there must be a
 | 
			
		||||
[module resolver] registered into the [`Engine`], the default being the `FileModuleResolver`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`import` Statement
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
```admonish tip.side.wide "Tip"
 | 
			
		||||
 | 
			
		||||
A [module] that is only `import`-ed but not given any name is simply run.
 | 
			
		||||
 | 
			
		||||
This is a very simple way to run another script file from within a script.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A [module] can be _imported_ via the `import` statement, and be given a name.
 | 
			
		||||
 | 
			
		||||
Its members can be accessed via `::` similar to C++.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
import "crypto_banner";         // run the script file 'crypto_banner.rhai' without creating an imported module
 | 
			
		||||
 | 
			
		||||
import "crypto" as lock;        // run the script file 'crypto.rhai' and import it as a module named 'lock'
 | 
			
		||||
 | 
			
		||||
const SECRET_NUMBER = 42;
 | 
			
		||||
 | 
			
		||||
let mod_file = `crypto_${SECRET_NUMBER}`;
 | 
			
		||||
 | 
			
		||||
import mod_file as my_mod;      // load the script file "crypto_42.rhai" and import it as a module named 'my_mod'
 | 
			
		||||
                                // notice that module path names can be dynamically constructed!
 | 
			
		||||
                                // any expression that evaluates to a string is acceptable after the 'import' keyword
 | 
			
		||||
 | 
			
		||||
lock::encrypt(secret);          // use functions defined under the module via '::'
 | 
			
		||||
 | 
			
		||||
lock::hash::sha256(key);        // sub-modules are also supported
 | 
			
		||||
 | 
			
		||||
print(lock::status);            // module variables are constants
 | 
			
		||||
 | 
			
		||||
lock::status = "off";           // <- runtime error: cannot modify a constant
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```admonish info "Imports are _scoped_"
 | 
			
		||||
 | 
			
		||||
[Modules] imported via `import` statements are only accessible inside the relevant block scope.
 | 
			
		||||
 | 
			
		||||
~~~js
 | 
			
		||||
import "hacker" as h;           // import module - visible globally
 | 
			
		||||
 | 
			
		||||
if secured {                    // <- new block scope
 | 
			
		||||
    let mod = "crypt";
 | 
			
		||||
 | 
			
		||||
    import mod + "o" as c;      // import module (the path needs not be a constant string)
 | 
			
		||||
 | 
			
		||||
    let x = c::encrypt(key);    // use a function in the module
 | 
			
		||||
 | 
			
		||||
    h::hack(x);                 // global module 'h' is visible here
 | 
			
		||||
}                               // <- module 'c' disappears at the end of the block scope
 | 
			
		||||
 | 
			
		||||
h::hack(something);             // this works as 'h' is visible
 | 
			
		||||
 | 
			
		||||
c::encrypt(something);          // <- this causes a run-time error because
 | 
			
		||||
                                //    module 'c' is no longer available!
 | 
			
		||||
 | 
			
		||||
fn foo(something) {
 | 
			
		||||
    h::hack(something);         // <- this also works as 'h' is visible
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
for x in 0..1000 {
 | 
			
		||||
    import "crypto" as c;       // <- importing a module inside a loop is a Very Bad Idea™
 | 
			
		||||
 | 
			
		||||
    c.encrypt(something);
 | 
			
		||||
}
 | 
			
		||||
~~~
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish note "Place `import` statements at the top"
 | 
			
		||||
 | 
			
		||||
`import` statements can appear anywhere a normal statement can be, but in the vast majority of cases they are
 | 
			
		||||
usually grouped at the top (beginning) of a script for manageability and visibility.
 | 
			
		||||
 | 
			
		||||
It is 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!
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
~~~admonish danger "Recursive imports"
 | 
			
		||||
 | 
			
		||||
Beware of _import cycles_ – i.e. recursively loading the same [module]. This is a sure-fire way to
 | 
			
		||||
cause a stack overflow in the [`Engine`], unless stopped by setting a limit for [maximum number of modules].
 | 
			
		||||
 | 
			
		||||
For instance, importing itself always causes an infinite recursion:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
┌────────────┐
 | 
			
		||||
│ hello.rhai │
 | 
			
		||||
└────────────┘
 | 
			
		||||
 | 
			
		||||
import "hello" as foo;          // import itself - infinite recursion!
 | 
			
		||||
 | 
			
		||||
foo::do_something();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[Modules] cross-referencing also cause infinite recursion:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
┌────────────┐
 | 
			
		||||
│ hello.rhai │
 | 
			
		||||
└────────────┘
 | 
			
		||||
 | 
			
		||||
import "world" as foo;
 | 
			
		||||
foo::do_something();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
┌────────────┐
 | 
			
		||||
│ world.rhai │
 | 
			
		||||
└────────────┘
 | 
			
		||||
 | 
			
		||||
import "hello" as bar;
 | 
			
		||||
bar::do_something_else();
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										14
									
								
								rhai_engine/rhaibook/language/modules/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								rhai_engine/rhaibook/language/modules/index.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
Modules
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_.
 | 
			
		||||
Modules can be disabled via the [`no_module`] feature.
 | 
			
		||||
 | 
			
		||||
A module has the type `Module` and holds a collection of functions, variables, [type iterators] and sub-modules.
 | 
			
		||||
It may be created entirely from Rust functions, or it may encapsulate a Rhai script together with the functions
 | 
			
		||||
and variables defined by that script.
 | 
			
		||||
 | 
			
		||||
Other scripts can then load this module and use the functions and variables exported as if they were
 | 
			
		||||
defined inside the same script.
 | 
			
		||||
		Reference in New Issue
	
	Block a user