Skip to content

Commit 6d0a8f5

Browse files
committed
docs: Add module examples to cookbook (issue #255)
1 parent c6063b7 commit 6d0a8f5

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

doc/src/konfigkoll/cookbook.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,178 @@
33
This contains a bunch of useful patterns and functions you can use in your own
44
configuration.
55

6+
## Multiple files / modules
7+
8+
It will quickly become useful to split your configuration into multiple files.
9+
With the Rune scripting language this is done using [modules](https://rune-rs.github.io/book/items_imports.html#modules),
10+
in a way very similar to how Rust does it (for those who are familiar with Rust).
11+
12+
All modules form a tree, starting at `main.rn`. To specify that a file `foo.rn`
13+
is a submodule of main you use `mod foo;` in `main.rn`. Or `pub mod foo;` if you
14+
want to be able to access it from sibling modules / parent modules (this is not
15+
as useful in main, as it is the top module).
16+
17+
For example, given this directory structure:
18+
19+
```text
20+
myconfig/
21+
- main.rn
22+
- utils.rn
23+
- ignores.rn
24+
```
25+
26+
Your `main.rn` might look like this:
27+
28+
```rune
29+
mod utils;
30+
mod ignores;
31+
32+
pub async fn phase_system_discovery(props, settings) {
33+
// ...
34+
// Call some function from utils. :: is the separator between modules
35+
// and their contents.
36+
let root_fs = utils::figure_out_file_system("/")?;
37+
// ...
38+
Ok(())
39+
}
40+
41+
pub fn phase_ignores(props, cmds) {
42+
// All the ignores are defined in the ignores module!
43+
ignores::apply_ignores(props, cmds)
44+
}
45+
46+
// ...
47+
// phase_script_dependencies, phase_main, etc
48+
```
49+
50+
For functions to be accessible outside their module they need to be declared `pub`.
51+
So in `utils.rn` and `ignores.rn` you would need to add `pub` to the functions you want to expose.
52+
E.g. for `utils.rn`:
53+
54+
```rune
55+
pub fn figure_out_file_system(path) {
56+
// ... do some fancy thing here
57+
}
58+
```
59+
60+
## Nested modules
61+
62+
If you want nested modules, you need to create a directory structure. For example:
63+
64+
```text
65+
myconfig/
66+
- main.rn
67+
- utils.rn
68+
- ignores.rn
69+
- tasks/
70+
- work.rn
71+
- gaming.rn
72+
- mod.rn
73+
```
74+
75+
Note here that we have a `tasks/mod.rn`, which defines the "tasks" module itself.
76+
(`mod.rn` is a special reserved name for this purpose, and you cannot name a module `mod`.)
77+
78+
In your `main.rn` you would have:
79+
80+
```rune
81+
pub mod utils;
82+
pub mod ignores;
83+
pub mod tasks;
84+
85+
// ...
86+
```
87+
88+
In `tasks/mod.rn` you would have:
89+
90+
```rune
91+
pub mod work;
92+
pub mod gaming;
93+
94+
// You could also have normal code directly in here (that is, in the "tasks"
95+
// module itself), but you don't need to
96+
```
97+
98+
The `pub` is needed here, or the sub-modules would not be visible from `main.rn`.
99+
Similarly, functions will need to be `pub` to be visible outside their own modules.
100+
101+
## Importing from other modules
102+
103+
Lets say you have the structure from the previous example:
104+
105+
```text
106+
myconfig/
107+
- main.rn
108+
- utils.rn
109+
- ignores.rn
110+
- tasks/
111+
- work.rn
112+
- gaming.rn
113+
- mod.rn
114+
```
115+
116+
And now you want to use the following function from `utils.rn` in `tasks/work.rn`:
117+
118+
```rune
119+
/// Join strings with separator
120+
///
121+
/// This function ensures that there isn't a leading
122+
/// or trailing separator.
123+
///
124+
/// Arguments:
125+
/// * separator (char or String)
126+
/// * list (Vec<String>)
127+
///
128+
/// Returns a String
129+
pub fn join(separator, list) {
130+
if list.len() == 0 {
131+
return "";
132+
}
133+
let joined = list[0].clone();
134+
for i in 1..list.len() {
135+
joined.push(separator);
136+
joined.push_str(list[i]);
137+
}
138+
joined
139+
}
140+
```
141+
142+
There are two ways of "reaching over" to a sibling/parent module like this:
143+
144+
```rune
145+
pub fn configure_work_stuff(/* ... */) {
146+
let example = Vec::new();
147+
example.push("work");
148+
example.push("stuff");
149+
let example_str = crate::utils::join(", ", example);
150+
// example_str is now "work, stuff"
151+
}
152+
```
153+
154+
The name `crate` (taken from Rust) is a keyword that refers to the root, which
155+
is `main.rn` in this case. You can also `use` a function from a module. This
156+
avoids having to write out the full path every time:
157+
158+
```rune
159+
use crate::utils::join;
160+
161+
pub fn configure_work_stuff(/* ... */) {
162+
let example = Vec::new();
163+
example.push("work");
164+
example.push("stuff");
165+
let example_str = join(", ", example);
166+
// example_str is now "work, stuff"
167+
}
168+
```
169+
170+
You can also import everything public from another module using `*`:
171+
172+
```rune
173+
use crate::utils::*;
174+
175+
// ... use all the functions from utils directly here as needed
176+
```
177+
6178
## Using strong types
7179

8180
While `props` is a generic key value store for passing info between the phases,

0 commit comments

Comments
 (0)