Usage#
Welcome to the RaESL usage documentation! This page covers the rudiments of
how to compile an ESL specification and convert it into an ragraph.graph.Graph
object for further processing.
Usage of the raesl.plot
module for generating graphical views from ESL
specifications and the raesl.doc
module for converting ESL specifications into
PDF documents is discussed in the following documentation sections:
Command-Line Interface#
Most RaESL functionality is included in it’s command line interface (CLI), which is
available in your terminal after installation. Suppose you have an ESL specification in
a file named specification.esl
. You would then be able to compile it using:
raesl compile specification.esl
Simple as that! If the compiler doesn’t find any errors, it will stay silent. For usage from a Python script, please refer to the sections below.
For more info on the (sub-)commands supplied by RaESL, you can type raesl --help
in
your terminal. You can use it for any of the following:
raesl compile
: Compiling ESL specification files or directories (optionally generating Graph output).raesl doc
: Converting ESL specification files or directories into a PDF or formatted document.raesl excel
: Converting ESL specification files or directories into an Excel workbook.raesl jupyter
: Managing the RaESL Jupyter kernel.raesl serve
: Starting the RaESL language server to support editors.raesl version
: Display the installed RaESL version.
Command specific help is also available, which results in:
raesl compile --help
Compiling ESL specifications#
Compiling an ESL specification from a Python script can be done in one of two ways.
If it is the dependency Graph
you’re after, the best way to obtain
it is using RaGraph’s I/O module:
>>> from ragraph.io.esl import from_esl
>>> graph = from_esl(path_to_esl_file) # (e.g. "specification.esl")
which used the from_esl
method.
The second method is a little more elaborate and provides you with additional objects to explore from the RaESL compile module itself:
>>> from raesl.compile.cli import run
>>> diag_store, spec, graph = run(path_to_esl_file) # (e.g. "specification.esl")
which returns three variables: diag_store
which is an
DiagnosticStore
object that contains all diagnostics
information such as warnings and errors; spec
which is an
Specification
object that contains the specified
type, verb, relation and component definitions; and graph
which is an
Graph
object that contains all nodes and edges that have been
derived from the compiled specification.
Multi-file input#
As your specification grows, it might be beneficial to split it into multiple files. The
compiler can handle this without any problem! The ESL compiler will walk through the
(component) instantiation tree starting at the world
definition and collect and
instantiate the required definitions from your provided ESL files. Hence, the
list of provided ESL files should only contain a single world
definition.
Suppose your ESL files are all in one directory, you would then be able to obtain the
Graph
like so:
>>> from ragraph.io.esl import from_esl
>>> graph = from_esl(path_to_esl_dir) # (e.g. "./specification")
You can also supply any number of file and directory path arguments to the
from_esl
and run
methods and they
will be used to discover all available ESL files:
>>> from ragraph.io.esl import from_esl
>>> graph = from_esl(path_to_esl_dir, path_to_esl_file) # (e.g. "specification/", "extra-file.esl")
Note
As a rule of thumb we advice to create a separate ESL file for each component definition. This limits the size of individual ESL files which benefits clarity.
Multiple use-cases / scenarios#
At some point, you might want to investigate multiple use-cases or scenarios that have quite some definitions in common. As an example, you could organize your files like this:
project
├── scenarios
│ ├── scenario1.esl
│ └── scenario2.esl
└── definitions
├── types.esl
├── user.esl
├── component1.esl
├── component2.esl
└── component3.esl
Where you organize your scenarios
(i.e. world definitions) into a separate folder.
You can then compile this specification by specifying the scenario file and
definitions directory. Lets assume that in scenario1
, we supply something to a
user
component using a system comprised of component1
and in scenario2
we do
this using component2
and component3
. If we didn’t make any syntax errors, the
compiler will then be able to compile both scenarios without any problems using:
raesl compile ./definitions ./scenarios/scenario1.esl
or from Python:
from ragraph.io.esl import from_esl
graph = from_esl("./definitions", "./scenarios/scenario1.esl")
This way, you don’t need to duplicate anything that is present in both scenarios! Types, relations, common components: they are all (re-)used automatically.