Commits: 11
Setup the project using devenv with flake
new file mode 100644
index 0000000..c5d670d
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+if ! has nix_direnv_version || ! nix_direnv_version 3.1.0; then
+ source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.0/direnvrc" "sha256-yMJ2OVMzrFaDPn7q8nCBZFRYpL/f0RcHzhmw/i6btJM="
+fi
+
+export DEVENV_IN_DIRENV_SHELL=true
+
+watch_file flake.nix
+watch_file flake.lock
+if ! use flake . --no-pure-eval; then
+ echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2
+finew file mode 100644
index 0000000..f7f246e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.devenv
+.direnv/
\ No newline at end of filenew file mode 100644
index 0000000..790b7aa
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,227 @@
+{
+ "nodes": {
+ "cachix": {
+ "inputs": {
+ "devenv": [
+ "devenv"
+ ],
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
+ "git-hooks": [
+ "devenv",
+ "git-hooks"
+ ],
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1760971495,
+ "narHash": "sha256-IwnNtbNVrlZIHh7h4Wz6VP0Furxg9Hh0ycighvL5cZc=",
+ "owner": "cachix",
+ "repo": "cachix",
+ "rev": "c5bfd933d1033672f51a863c47303fc0e093c2d2",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "latest",
+ "repo": "cachix",
+ "type": "github"
+ }
+ },
+ "devenv": {
+ "inputs": {
+ "cachix": "cachix",
+ "flake-compat": "flake-compat",
+ "flake-parts": "flake-parts",
+ "git-hooks": "git-hooks",
+ "nix": "nix",
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1762889687,
+ "narHash": "sha256-oKvHfeYDZ0LfuHSaFLA0w/dfZ9R6C5W8pCGUjUWawGI=",
+ "owner": "cachix",
+ "repo": "devenv",
+ "rev": "3b4fb549962342c928aae1bbea3a13f0eeed2703",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "devenv",
+ "type": "github"
+ }
+ },
+ "flake-compat": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1761588595,
+ "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
+ "type": "github"
+ },
+ "original": {
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1760948891,
+ "narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "git-hooks": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
+ "gitignore": "gitignore",
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1760663237,
+ "narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=",
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "type": "github"
+ }
+ },
+ "gitignore": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "git-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "nix": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
+ "flake-parts": [
+ "devenv",
+ "flake-parts"
+ ],
+ "git-hooks-nix": [
+ "devenv",
+ "git-hooks"
+ ],
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ],
+ "nixpkgs-23-11": [
+ "devenv"
+ ],
+ "nixpkgs-regression": [
+ "devenv"
+ ]
+ },
+ "locked": {
+ "lastModified": 1761648602,
+ "narHash": "sha256-H97KSB/luq/aGobKRuHahOvT1r7C03BgB6D5HBZsbN8=",
+ "owner": "cachix",
+ "repo": "nix",
+ "rev": "3e5644da6830ef65f0a2f7ec22830c46285bfff6",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "devenv-2.30.6",
+ "repo": "nix",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1761313199,
+ "narHash": "sha256-wCIACXbNtXAlwvQUo1Ed++loFALPjYUA3dpcUJiXO44=",
+ "owner": "cachix",
+ "repo": "devenv-nixpkgs",
+ "rev": "d1c30452ebecfc55185ae6d1c983c09da0c274ff",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "rolling",
+ "repo": "devenv-nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "devenv": "devenv",
+ "nixpkgs": "nixpkgs",
+ "systems": "systems"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}new file mode 100644
index 0000000..f90aba3
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,42 @@
+{
+ inputs = {
+ nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling";
+ systems.url = "github:nix-systems/default";
+ devenv.url = "github:cachix/devenv";
+ devenv.inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ nixConfig = {
+ extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=";
+ extra-substituters = "https://devenv.cachix.org";
+ };
+
+ outputs = { self, nixpkgs, devenv, systems, ... } @ inputs:
+ let
+ forEachSystem = nixpkgs.lib.genAttrs (import systems);
+ in
+ {
+ devShells = forEachSystem
+ (system:
+ let
+ pkgs = nixpkgs.legacyPackages.${system};
+ in
+ {
+ default = devenv.lib.mkShell {
+ inherit inputs pkgs;
+ modules = [
+ {
+ # https://devenv.sh/reference/options/
+ packages = [ pkgs.hello ];
+
+ enterShell = ''
+ hello
+ '';
+
+ processes.hello.exec = "hello";
+ }
+ ];
+ };
+ });
+ };
+}Setup Rust development environment
index f7f246e..98507b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,6 @@
=.devenv
-.direnv/
\ No newline at end of file
+.direnv/
+
+# Added by cargo
+
+/targetnew file mode 100644
index 0000000..ee2c2d5
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "tad-better-behavior"
+version = "0.1.0"new file mode 100644
index 0000000..048938e
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "tad-better-behavior"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]index f90aba3..0560c1e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -27,13 +27,9 @@
= modules = [
= {
= # https://devenv.sh/reference/options/
- packages = [ pkgs.hello ];
=
- enterShell = ''
- hello
- '';
-
- processes.hello.exec = "hello";
+ languages.rust.enable = true;
+ packages = [];
= }
= ];
= };new file mode 100644
index 0000000..e7a11a9
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}Setup CLI parsing with Clap
index ee2c2d5..488461d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,185 @@
=# It is not intended for manual editing.
=version = 4
=
+[[package]]
+name = "anstream"
+version = "0.6.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.110"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
=[[package]]
=name = "tad-better-behavior"
=version = "0.1.0"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]index 048938e..ead47b9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,3 +4,4 @@ version = "0.1.0"
=edition = "2024"
=
=[dependencies]
+clap = { version = "4.5.51", features = ["derive"] }index e7a11a9..414bc9c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,15 @@
+use clap::Parser;
+use std::path::PathBuf;
+
+#[derive(Parser)]
+#[command(version, about, long_about=None)]
+struct Cli {
+ #[arg(value_name = "SPEC PATH", default_value = "./spec/")]
+ input: PathBuf,
+}
+
=fn main() {
- println!("Hello, world!");
+ let cli = Cli::parse();
+
+ println!("Reading specifications from {}", cli.input.display());
=}Set the name of main binary to tbb
Short for Tad Better Behavior!
index ead47b9..3386de1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,3 +5,7 @@ edition = "2024"
=
=[dependencies]
=clap = { version = "4.5.51", features = ["derive"] }
+
+[[bin]]
+name = "tbb"
+path = "src/main.rs"Describe the input option
index 414bc9c..a606887 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,6 +4,7 @@ use std::path::PathBuf;
=#[derive(Parser)]
=#[command(version, about, long_about=None)]
=struct Cli {
+ /// A directory or a markdown file with specs to evaluate
= #[arg(value_name = "SPEC PATH", default_value = "./spec/")]
= input: PathBuf,
=}Write a basic sample specification
new file mode 100644
index 0000000..163ee32
--- /dev/null
+++ b/samples/basic.md
@@ -0,0 +1,29 @@
+---
+interpretter: "python samples/basic.py"
+---
+
+# Basic BDD suite
+
+This suite contains several simple **scenarios**. Use it as a reference to get started with Tad Better Behavior.
+
+Scenarios are delimited by 2nd level heading (`## Heading` in markdown). Each bullet point inside a scenario defines a **step**.
+
+
+For each scenario the **interpreter** program (see the front-matter above) will be started. For every step this program will be passed a JSON object via `stdin`. The object will contain the description of the step. An interpretter is expected to print a JSON object with the result of evaluation on it's `stdout`.
+
+
+## Arithmetic
+
+Content outside of bullet points (like this) won't have any effect on the program. You can user it as a humane description of the scenario, or for any other purpose.
+
+ * Add `7` and `5` to get `12`.
+ * Divide `8` by `4` to get `2`
+ * Subtract `7` from `5` to get `-2`
+
+
+## Text
+
+ * The word `blocks` has `6` characters
+ * There are `3` `r`s in the word `strawberry`
+ * The reverse of `abc` is `cba`
+ * There are `2` `o`s in the word `boost`Distinguish between file and directory inputs
Handle errors.
index a606887..c6a8eae 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,8 +9,19 @@ struct Cli {
= input: PathBuf,
=}
=
-fn main() {
+fn main() -> Result<(), Box<dyn std::error::Error>> {
= let cli = Cli::parse();
=
= println!("Reading specifications from {}", cli.input.display());
+
+ let input = cli.input.canonicalize()?;
+ if input.is_dir() {
+ println!("Input is a directory. Looking for markdown files...");
+ Ok(())
+ } else if input.is_file() {
+ println!("Input is a file. Reading...");
+ Ok(())
+ } else {
+ Err(format!("The {} is neither a file nor directory", input.display()).into())
+ }
=}Read the spec input and print it back
index 488461d..ed46f99 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -98,6 +98,12 @@ version = "1.0.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
=
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
=[[package]]
=name = "heck"
=version = "0.5.0"
@@ -156,6 +162,7 @@ name = "tad-better-behavior"
=version = "0.1.0"
=dependencies = [
= "clap",
+ "glob",
=]
=
=[[package]]index 3386de1..3e2476d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2024"
=
=[dependencies]
=clap = { version = "4.5.51", features = ["derive"] }
+glob = "0.3.3"
=
=[[bin]]
=name = "tbb"index c6a8eae..66b20da 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,6 @@
=use clap::Parser;
+use glob::glob;
+use std::error::Error;
=use std::path::PathBuf;
=
=#[derive(Parser)]
@@ -9,19 +11,33 @@ struct Cli {
= input: PathBuf,
=}
=
-fn main() -> Result<(), Box<dyn std::error::Error>> {
+fn main() -> Result<(), Box<dyn Error>> {
= let cli = Cli::parse();
=
= println!("Reading specifications from {}", cli.input.display());
=
= let input = cli.input.canonicalize()?;
= if input.is_dir() {
- println!("Input is a directory. Looking for markdown files...");
+ println!(
+ "The {} is a directory. Looking for markdown files...",
+ input.display()
+ );
+ let pattern = format!("{}/**/*.md", input.display());
+ for path in glob(&pattern)? {
+ process_spec(path?)?;
+ }
= Ok(())
= } else if input.is_file() {
- println!("Input is a file. Reading...");
- Ok(())
+ println!("The {} is a file. Reading...", input.display());
+ process_spec(input)
= } else {
= Err(format!("The {} is neither a file nor directory", input.display()).into())
= }
=}
+
+fn process_spec(input: PathBuf) -> Result<(), Box<dyn Error>> {
+ println!("Reading {}", input.display());
+ let markdown = std::fs::read_to_string(input)?;
+ println!("Content:\n\n{}", markdown);
+ Ok(())
+}Parse input to mdast
index ed46f99..d270297 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -116,6 +116,15 @@ version = "1.70.2"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
=
+[[package]]
+name = "markdown"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5cab8f2cadc416a82d2e783a1946388b31654d391d1c7d92cc1f03e295b1deb"
+dependencies = [
+ "unicode-id",
+]
+
=[[package]]
=name = "once_cell_polyfill"
=version = "1.70.2"
@@ -163,8 +172,15 @@ version = "0.1.0"
=dependencies = [
= "clap",
= "glob",
+ "markdown",
=]
=
+[[package]]
+name = "unicode-id"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ba288e709927c043cbe476718d37be306be53fb1fafecd0dbe36d072be2580"
+
=[[package]]
=name = "unicode-ident"
=version = "1.0.22"index 3e2476d..0ee1226 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2024"
=[dependencies]
=clap = { version = "4.5.51", features = ["derive"] }
=glob = "0.3.3"
+markdown = "1.0.0"
=
=[[bin]]
=name = "tbb"index 163ee32..134df0d 100644
--- a/samples/basic.md
+++ b/samples/basic.md
@@ -8,7 +8,6 @@ This suite contains several simple **scenarios**. Use it as a reference to get s
=
=Scenarios are delimited by 2nd level heading (`## Heading` in markdown). Each bullet point inside a scenario defines a **step**.
=
-
=For each scenario the **interpreter** program (see the front-matter above) will be started. For every step this program will be passed a JSON object via `stdin`. The object will contain the description of the step. An interpretter is expected to print a JSON object with the result of evaluation on it's `stdout`.
=
=index 66b20da..b884fb4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
=use clap::Parser;
=use glob::glob;
+use markdown;
=use std::error::Error;
=use std::path::PathBuf;
=
@@ -37,7 +38,18 @@ fn main() -> Result<(), Box<dyn Error>> {
=
=fn process_spec(input: PathBuf) -> Result<(), Box<dyn Error>> {
= println!("Reading {}", input.display());
- let markdown = std::fs::read_to_string(input)?;
- println!("Content:\n\n{}", markdown);
+ let md = std::fs::read_to_string(input)?;
+ let mdast = markdown::to_mdast(
+ &md,
+ &markdown::ParseOptions {
+ constructs: markdown::Constructs {
+ frontmatter: true,
+ ..Default::default()
+ },
+ ..Default::default()
+ },
+ )
+ .map_err(|message| message.to_string())?;
+ println!("Content:\n\n{:#?}", mdast);
= Ok(())
=}Define structs (Spec, Scenario, Step)
Also extract interpretter from a front-matter using serde_yaml.
index d270297..efecadd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -98,24 +98,52 @@ version = "1.0.4"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
=
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
=[[package]]
=name = "glob"
=version = "0.3.3"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
=
+[[package]]
+name = "hashbrown"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
+
=[[package]]
=name = "heck"
=version = "0.5.0"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
=
+[[package]]
+name = "indexmap"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
=[[package]]
=name = "is_terminal_polyfill"
=version = "1.70.2"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
=
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
=[[package]]
=name = "markdown"
=version = "1.0.0"
@@ -149,6 +177,55 @@ dependencies = [
= "proc-macro2",
=]
=
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.9.34+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde",
+ "unsafe-libyaml",
+]
+
=[[package]]
=name = "strsim"
=version = "0.11.1"
@@ -173,6 +250,8 @@ dependencies = [
= "clap",
= "glob",
= "markdown",
+ "serde",
+ "serde_yaml",
=]
=
=[[package]]
@@ -187,6 +266,12 @@ version = "1.0.22"
=source = "registry+https://github.com/rust-lang/crates.io-index"
=checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
=
+[[package]]
+name = "unsafe-libyaml"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
+
=[[package]]
=name = "utf8parse"
=version = "0.2.2"index 0ee1226..0511019 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,8 @@ edition = "2024"
=clap = { version = "4.5.51", features = ["derive"] }
=glob = "0.3.3"
=markdown = "1.0.0"
+serde = { version = "1.0.228", features = ["serde_derive"] }
+serde_yaml = "0.9.34"
=
=[[bin]]
=name = "tbb"index b884fb4..0e98912 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
=use clap::Parser;
=use glob::glob;
=use markdown;
+use serde::Deserialize;
=use std::error::Error;
=use std::path::PathBuf;
=
@@ -36,6 +37,58 @@ fn main() -> Result<(), Box<dyn Error>> {
= }
=}
=
+#[derive(Debug)]
+struct Spec {
+ title: String,
+ interpretter: String,
+ scenarios: Vec<Scenario>,
+}
+
+#[derive(Debug)]
+struct Scenario {
+ title: String,
+ steps: Vec<Step>,
+}
+
+#[derive(Debug)]
+struct Step {
+ variant: String,
+ arguments: Vec<String>,
+}
+
+#[derive(Deserialize)]
+struct FrontMatter {
+ interpretter: String,
+}
+
+impl TryFrom<markdown::mdast::Node> for Spec {
+ type Error = Box<dyn Error>;
+
+ fn try_from(mdast: markdown::mdast::Node) -> Result<Self, Self::Error> {
+ // Find the YAML frontmatter and extract interpretter field
+ let children = mdast.children().ok_or("The given node has no children.")?;
+ let first = children
+ .first()
+ .ok_or("There is no first child in the given node.")?;
+
+ let markdown::mdast::Node::Yaml(markdown::mdast::Yaml { value: yaml, .. }) = first else {
+ return Err("First child is not a YAML front matter.".into());
+ };
+ let frontmatter: FrontMatter = serde_yaml::from_str(yaml)?;
+
+ // TODO: Find h1 and use it as title (make sure there's only one)
+
+ // TODO: Split into sections, each starting at h2
+ // TODO: Convert each section into a scenario (section::try_into())
+
+ Ok(Self {
+ title: "Spec title".into(),
+ interpretter: frontmatter.interpretter,
+ scenarios: [].into(),
+ })
+ }
+}
+
=fn process_spec(input: PathBuf) -> Result<(), Box<dyn Error>> {
= println!("Reading {}", input.display());
= let md = std::fs::read_to_string(input)?;
@@ -51,5 +104,8 @@ fn process_spec(input: PathBuf) -> Result<(), Box<dyn Error>> {
= )
= .map_err(|message| message.to_string())?;
= println!("Content:\n\n{:#?}", mdast);
+
+ let spec = Spec::try_from(mdast)?;
+ println!("Spec:\n\n{:#?}", spec);
= Ok(())
=}Fix a typo
Spelling hard
index 134df0d..95a7704 100644
--- a/samples/basic.md
+++ b/samples/basic.md
@@ -1,5 +1,5 @@
=---
-interpretter: "python samples/basic.py"
+interpreter: "python samples/basic.py"
=---
=
=# Basic BDD suite
@@ -8,7 +8,7 @@ This suite contains several simple **scenarios**. Use it as a reference to get s
=
=Scenarios are delimited by 2nd level heading (`## Heading` in markdown). Each bullet point inside a scenario defines a **step**.
=
-For each scenario the **interpreter** program (see the front-matter above) will be started. For every step this program will be passed a JSON object via `stdin`. The object will contain the description of the step. An interpretter is expected to print a JSON object with the result of evaluation on it's `stdout`.
+For each scenario the **interpreter** program (see the front-matter above) will be started. For every step this program will be passed a JSON object via `stdin`. The object will contain the description of the step. An interpreter is expected to print a JSON object with the result of evaluation on it's `stdout`.
=
=
=## Arithmeticindex 0e98912..151721e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -40,7 +40,7 @@ fn main() -> Result<(), Box<dyn Error>> {
=#[derive(Debug)]
=struct Spec {
= title: String,
- interpretter: String,
+ interpreter: String,
= scenarios: Vec<Scenario>,
=}
=
@@ -58,14 +58,14 @@ struct Step {
=
=#[derive(Deserialize)]
=struct FrontMatter {
- interpretter: String,
+ interpreter: String,
=}
=
=impl TryFrom<markdown::mdast::Node> for Spec {
= type Error = Box<dyn Error>;
=
= fn try_from(mdast: markdown::mdast::Node) -> Result<Self, Self::Error> {
- // Find the YAML frontmatter and extract interpretter field
+ // Find the YAML front-matter and extract the interpreter field
= let children = mdast.children().ok_or("The given node has no children.")?;
= let first = children
= .first()
@@ -83,7 +83,7 @@ impl TryFrom<markdown::mdast::Node> for Spec {
=
= Ok(Self {
= title: "Spec title".into(),
- interpretter: frontmatter.interpretter,
+ interpreter: frontmatter.interpreter,
= scenarios: [].into(),
= })
= }