Other languages
The same two evaluations from Python, Node.js, Ruby, PHP, Java, shell, Rust, C# and PowerShell through the command, and from Node.js and Python through the WebAssembly module.
Code: examples/engine-clients
(README). Every client starts the engine once, sends
version, loads the payments bundle, evaluates two requests and prints exactly
expected-output.txt:
engine: Rule Cascade 1.0.0, bundle format 1.0.0
loaded: acme.payments.transfer 1.0.0
domestic transfer: allow
warning ORG-TRF-003 Adding a memo makes this transfer easier to reconcile.
blocked country: deny
error ORG-TRF-001 Transfers to KP are not permitted.The core of each client is one function: write a request line, read a response line, check it.
From process/client.py:
def call(self, command, **members):
self.sent += 1
line = json.dumps({"id": self.sent, "command": command, **members}, ensure_ascii=False)
try:
self.process.stdin.write(line.encode("utf-8") + b"\n")
self.process.stdin.flush()
except OSError:
fail("the engine closed its input")
answer = self.process.stdout.readline() # a whole line, however long
if not answer:
fail("the engine closed its output")
response = json.loads(answer)
if response.get("id") != self.sent:
fail("expected the response to request %d, got %r" % (self.sent, response.get("id")))
if response.get("ok") is not True:
error = response.get("error") or {}
fail("%s: %s" % (error.get("code"), error.get("message")))
return response["result"]PHP, Java, shell, Rust, C# and PowerShell follow the same shape in process/; wasm/client.mjs
and wasm/client.py run the WebAssembly module inside the client's own process.
Run them
Get the command
Download and verify rcas, then point the clients at it:
export RULE_CASCADE_ENGINE=$(command -v rule-cascade)Run one client against the payments bundle
python3 examples/engine-clients/process/client.py conformance/bundles/acme.payments.transfer.bundle.jsonengine: Rule Cascade 1.0.0, bundle format 1.0.0
loaded: acme.payments.transfer 1.0.0
domestic transfer: allow
warning ORG-TRF-003 Adding a memo makes this transfer easier to reconcile.
blocked country: deny
error ORG-TRF-001 Transfers to KP are not permitted.Done when the output is exactly expected-output.txt: ... | diff - examples/engine-clients/expected-output.txt
prints nothing. The Node.js and Ruby clients (node .../client.mjs, ruby .../client.rb) print
the same six lines.
Run every client whose language is installed
sh examples/engine-clients/run-all.shOn a machine with Python, Node.js, Ruby, Java and a shell, but no PHP, Rust, .NET, PowerShell or
the wasmtime Python package:
PASS process/client.py
PASS process/client.mjs
PASS process/client.rb
SKIP process/client.php (PHP is not installed)
PASS process/Client.java
PASS process/client.sh
SKIP process/client.rs (Rust (cargo) is not installed)
SKIP process/Client.cs (the .NET SDK is not installed)
SKIP process/client.ps1 (PowerShell is not installed)
PASS wasm/client.mjs
SKIP wasm/client.py (the wasmtime package is not installed: pip install wasmtime)
6 passed, 0 failed, 5 skippedDone when the last line says 0 failed. Each PASS means that client's output matched
expected-output.txt byte for byte; a client whose language is missing is skipped and named.
CI runs the Python, Node.js, Ruby, PHP, Java, shell and Rust clients and both WebAssembly clients
on Linux. Client.cs and client.ps1 were written against the documented behaviour of .NET and
PowerShell and have not been executed.
Step by step: Run rules from any other language.
Post-save commands
An action rule that asks the host to publish an event after a large transfer is saved - once, keyed by a deterministic idempotency key.
rcas command reference
rcas is the Rule Cascade command: it checks, compiles and evaluates rulesets, serves the engine protocol to other languages, scaffolds projects, derives rules from API schemas, finds rules in existing code, and serves the Model Context ...