Modules in a Rell app
The Rell app consists of modules. A module is either a single
.rell
file or a directory with one or multiple .rell
files.
A single-file Rell module must have a module header:
module;
// entities, operations, queries, functions and other definitions
If a .rell
file has no module header, it's part of a directory module. All such .rell
files in a directory belong to the same directory module. An exception is a file called module.rell
: it
always belongs to a directory-module, even if it has a module header. A directory-module doesn't need to have module.rell
.
Every file of a directory module sees definitions of all other module files. A file module file sees only its definitions.
Example of a Rell source directory tree:
.
└── app
├── multi
│ ├── functions.rell
│ ├── module.rell
│ ├── operations.rell
│ └── queries.rell
└── single.rell
app/multi/functions.rell:
function g(): integer = 456;
app/multi/module.rell:
module;
enum state { OPEN, CLOSED }
app/single.rell:
module;
function f(): integer = 123;
Every module has a name defined by its source directory path. The sample source directory tree given above defines two modules:
app.multi
- a directory module in the directoryapp/multi
(consisting of four files)app.single
- a file module in the fileapp/single.rell
There may be a root module - a directory module that consists of .rell
files located in the root of the source directory. The root module has an empty name. Web IDE uses the root module as the default main module of a Rell app.
Import
To access the module's definitions, you need to import the module:
import app.single;
function test() {
single.f(); // Calling the function "f" defined in the module "app.single".
}
When importing a module, it's added to the current namespace with some
alias. By default, the alias is the last part of the module name, single
for the module app.single
or multi
for app.multi
. The
definitions of the module can be accessed via the alias.
A custom alias can be specified:
import alias: app.multi;
function test() {
alias.g();
}
It's possible to specify a relative name of a module when importing. In that case, the name of the imported module is derived from the current module's name. For example, if the current module is a.b.c
,
import .d;
importsa.b.c.d
import alias: ^;
importsa.b
import alias: ^^;
importsa
import ^.e;
importsa.b.e
Wildcard imports
Importing all definitions of a module:
import foo.*;
All definitions are added directly to the importing namespace.
It's possible to import definitions of a specific namespace defined within a module:
import foo.{ns.*};
An import alias, if specified, creates a nested namespace and adds imported definitions there:
import sub: foo.{ns.*};
Definitions from the namespace "ns" of module "foo" in this example are added to a new namespace "sub".
Import specific definitions
To import a specific definition (or a set of definitions) from a module, specify their names in braces:
import foo.{f};
import foo.{g, h};
The definitions "f", "g", and "h" are added to the importing namespace like they were defined there.
If an import alias is specified, a nested namespace is created:
import ns: foo.{f, g};
This creates a namespace "ns" containing definitions "f" and "g".
One can specify an alias for individual definitions in braces:
import foo.{a: f, b: g};
Imported definitions in this example are added to the namespace under names "a" and "b".
Run-time
At run-time, not all modules defined in a source directory tree are active. Only the main module and all modules it imports (directly or indirectly) are active. There is a main module that is specified when starting a Rell app.
When a module is active, its operations and queries can be invoked, and tables for its entities and objects are added to the database on initialization.