Add usage pattern on multi-layer functions.
This commit is contained in:
parent
ae76d9b8ae
commit
df1dd5190e
@ -118,8 +118,9 @@ The Rhai Scripting Language
|
||||
2. [Loadable Configuration](patterns/config.md)
|
||||
3. [Control Layer](patterns/control.md)
|
||||
4. [Singleton Command](patterns/singleton.md)
|
||||
5. [One Engine Instance Per Call](patterns/parallel.md)
|
||||
6. [Scriptable Event Handler with State](patterns/events.md)
|
||||
5. [Multi-Layer Functions](patterns/multi-layer.md)
|
||||
6. [One Engine Instance Per Call](patterns/parallel.md)
|
||||
7. [Scriptable Event Handler with State](patterns/events.md)
|
||||
9. [Advanced Topics](advanced.md)
|
||||
1. [Capture Scope for Function Call](language/fn-capture.md)
|
||||
2. [Low-Level API](rust/register-raw.md)
|
||||
|
@ -131,7 +131,7 @@ It should simply be passed straight-through the the [`Engine`].
|
||||
### Access Arguments
|
||||
|
||||
The most important argument is `inputs` where the matched identifiers (`$ident$`), expressions/statements (`$expr$`)
|
||||
and statement blocks (`$block$) are provided.
|
||||
and statement blocks (`$block$`) are provided.
|
||||
|
||||
To access a particular argument, use the following patterns:
|
||||
|
||||
|
117
doc/src/patterns/multi-layer.md
Normal file
117
doc/src/patterns/multi-layer.md
Normal file
@ -0,0 +1,117 @@
|
||||
Multi-Layer Functions
|
||||
=====================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
Usage Scenario
|
||||
--------------
|
||||
|
||||
* A system is divided into separate _layers_, each providing logic in terms of scripted [functions].
|
||||
|
||||
* A lower layer provides _default implementations_ of certain functions.
|
||||
|
||||
* Higher layers each provide progressively more specific implementations of the same functions.
|
||||
|
||||
* A more specific function, if defined in a higher layer, always overrides the implementation in a lower layer.
|
||||
|
||||
* This is akin to object-oriented programming but with functions.
|
||||
|
||||
* This type of system is extremely convenient for dynamic business rules configuration, setting corporate-wide
|
||||
policies, granting permissions for specific roles etc. where specific, local rules need to override
|
||||
corporate-wide defaults.
|
||||
|
||||
|
||||
Key Concepts
|
||||
------------
|
||||
|
||||
* Each layer is a separate script.
|
||||
|
||||
* The lowest layer script is compiled into a base [`AST`].
|
||||
|
||||
* Higher layer scripts are also compiled into [`AST`] and _merged_ into the base using `AST::merge`,
|
||||
overriding any existing functions.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Assume the following four scripts:
|
||||
|
||||
```rust
|
||||
----------------
|
||||
| default.rhai |
|
||||
----------------
|
||||
|
||||
// Default implementation of 'foo'.
|
||||
fn foo(x) { x + 1 }
|
||||
|
||||
// Default implementation of 'bar'.
|
||||
fn bar(x, y) { x + y }
|
||||
|
||||
// Default implementation of 'no_touch'.
|
||||
fn no_touch() { throw "do not touch me!"; }
|
||||
|
||||
|
||||
---------------
|
||||
| lowest.rhai |
|
||||
---------------
|
||||
|
||||
// Specific implementation of 'foo'.
|
||||
fn foo(x) { x * 2 }
|
||||
|
||||
// New implementation for this layer.
|
||||
fn baz() { print("hello!"); }
|
||||
|
||||
|
||||
---------------
|
||||
| middle.rhai |
|
||||
---------------
|
||||
|
||||
// Specific implementation of 'bar'.
|
||||
fn bar(x, y) { x - y }
|
||||
|
||||
// Specific implementation of 'baz'.
|
||||
fn baz() { print("hey!"); }
|
||||
|
||||
|
||||
----------------
|
||||
| highest.rhai |
|
||||
----------------
|
||||
|
||||
// Specific implementation of 'foo'.
|
||||
fn foo(x) { x + 42 }
|
||||
```
|
||||
|
||||
Load and merge them sequentially:
|
||||
|
||||
```rust
|
||||
let engine = Engine::new();
|
||||
|
||||
// Compile the baseline default implementations.
|
||||
let mut ast = engine.compile_file("default.rhai".into())?;
|
||||
|
||||
// Merge in the first layer.
|
||||
let lowest = engine.compile_file("lowest.rhai".into())?;
|
||||
ast = ast.merge(&lowest);
|
||||
|
||||
// Merge in the second layer.
|
||||
let middle = engine.compile_file("middle.rhai".into())?;
|
||||
ast = ast.merge(&middle);
|
||||
|
||||
// Merge in the third layer.
|
||||
let highest = engine.compile_file("highest.rhai".into())?;
|
||||
ast = ast.merge(&highest);
|
||||
|
||||
// Now, 'ast' contains the following functions:
|
||||
//
|
||||
// fn no_touch() { // from 'default.rhai'
|
||||
// throw "do not touch me!";
|
||||
// }
|
||||
// fn foo(x) { x + 42 } // from 'highest.rhai'
|
||||
// fn bar(x, y) { x - y } // from 'middle.rhai'
|
||||
// fn baz() { print("hey!"); } // from 'middle.rhai'
|
||||
```
|
||||
|
||||
Unfortunately, there is no `super` call that calls the base implementation
|
||||
(i.e. no way for a higher-layer function to call an equivalent lower-layer function).
|
Loading…
Reference in New Issue
Block a user