The .to_bytes() method has a default value for length, but apparently Mypy does not know that yet. Maybe it is running for an older Python version. |
||
|---|---|---|
| docs | ||
| etc | ||
| examples | ||
| fuzz | ||
| golden | ||
| ideas | ||
| pyrcl | ||
| src | ||
| tools | ||
| .gitignore | ||
| .gitmodules | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CONTRIBUTING.md | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| mkdocs.yml | ||
| README.md | ||
| rust-toolchain.toml | ||
Ruud’s Configuration Language
Ruud’s Configuration Language, RCL for short, is a domain-specific language optimized for specifying human-written data with just enough abstraction features to avoid repetition. It is a superset of json that extends it into a simple functional programming language that resembles Python and Nix. Use cases include:
- Querying json documents, like
jq, but with a more familiar language. - Generating repetitive configuration files, such as GitHub Actions workflows or Terraform configuration.
- Enabling large repositories to split configuration into small reusable pieces that can be referenced from a single consistent entry point, in the same way that Nix enables this for Nixpkgs.
RCL can be used through the rcl command-line tool that can export documents
to json and other formats. It can also be used through a native Python
module, with an interface similar to the json module.
Warning
While RCL is usable, it is still in an early exploratory stage with frequent breaking changes. This is a hobby project without stability promise.
Getting started
See the manual for more information. The most useful chapters to get started:
You may also find the examples in the examples directory instructive.
Rationale
Why another config language?
-
HCL is too ad-hoc to be suitable for any serious abstraction (
setunionis variadic so it only works with a statically known number of sets;flattenrecursively flattens so it can’t be typed properly and breaks generic code, for comprehensions can’t do nested loops,for_eachsyntax is bolted on, etc.) -
Nix-the-language is great but forces the entire Nix store on you when all I want is to evaluate expressions.
-
Python is great but requires some boilerplate for doing the IO if you want to use it as a configuration language. Also the syntactic order of list comprehensions prevents autocomplete in editors.
-
Dhall has the right ideas but the syntax and heavy use of Unicode symbols make it look ugly.
-
CUE and Nickel were not invented here.
-
For more background, see the blog post: A reasonable configuration language.
Classification
-
Purely functional: RCL documents are expressions that evaluate to values, rather than sequences of statements that have side effects. Values are immutable, there are no mutable objects. Functions are values.
-
Gradually typed: Optional type annotations can be used to prevent bugs and to make code more self-documenting. All type annotations are enforced.
-
Json superset: Vaporware, this is not fully implemented; floats are not yet supported.
Usage
Build:
cargo build --release
Print usage:
target/release/rcl
target/release/rcl eval --help
Evaluate an RCL expression to json:
target/release/rcl eval examples/tags.rcl
Query an RCL or json document:
target/release/rcl query examples/tags.rcl input.tags.ams01
Autoformat an RCL expression (non-destructive, prints to stdout):
target/release/rcl fmt examples/tags.rcl
Highlight an RCL expression in your terminal:
target/release/rcl highlight examples/tags.rcl
Development
Run all tests and checks below in one command:
nix flake check
Run golden tests:
cargo build
golden/run.py
Check the grammar for ambiguities:
bison -Werror=all src/grammar.y
Run unit tests and lints:
cargo test
cargo clippy
Typecheck Python sources
mypy --strict --exclude pyrcl .
mypy --strict pyrcl
Check formatting:
cargo fmt
black .
View coverage of the golden tests:
nix build .#coverage --out-link result
xdg-open result/index.html
Run the fuzzer:
cargo +nightly-2023-06-03 fuzz run main -- -dict=fuzz/dictionary.txt -timout=5
Building the Python module
Build the shared object:
cargo build --manifest-path pyrcl/Cargo.toml
Give the shared object the appropriate name for the Python interpreter to discover it:
mv target/debug/{libpyrcl,rcl}.so
Tell Python where to find the shared object, run the interpreter:
PYTHONPATH=target/debug python3
>>> import rcl
>>> help(rcl.loads)
>>> rcl.load_file("examples/buckets.rcl")
License
RCL is licensed under the Apache 2.0 license. It may be used in free software as well as closed-source applications, both for commercial and non-commercial use under the conditions given in the license. If you want to use RCL in your GPLv2-licensed software, you can add an exception to your copyright notice. Please do not open an issue if you disagree with the choice of license.