diff --git a/.gitignore b/.gitignore index 16818c2..37fe30e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,54 +1,12 @@ -# Prerequisites -*.d +build*/ +.vix/ +.cache/ -# Compiled Object files -*.slo -*.lo *.o *.obj - -# Precompiled Headers -*.gch -*.pch - -# Linker files -*.ilk - -# Debugger Files -*.pdb - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la *.a *.lib - -# Executables +*.so +*.dll +*.dylib *.exe -*.out -*.app - -# debug information files -*.dwo -build-ninja/ -build/ -docker/ -.github/ -infra/ -scripts/ -db.sql -.env -vix.log -configs/ -docs/ -cmd.md -.vscode/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e69de29..30c54c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.20) + +project(rix + VERSION 0.5.0 + DESCRIPTION "Unified Rix facade for Vix C++ projects" + LANGUAGES CXX +) + +option(RIX_BUILD_EXAMPLES "Build Rix examples" ON) +option(RIX_BUILD_TESTS "Build Rix tests" ON) + +include(${CMAKE_CURRENT_SOURCE_DIR}/.vix/vix_deps.cmake OPTIONAL) + +add_library(rix INTERFACE) +add_library(rix::rix ALIAS rix) + +target_compile_features(rix INTERFACE cxx_std_20) + +target_include_directories(rix + INTERFACE + $ + $ +) + +target_link_libraries(rix + INTERFACE + rix::csv + rix::debug +) + +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + if(RIX_BUILD_EXAMPLES) + add_subdirectory(examples) + endif() + + if(RIX_BUILD_TESTS) + enable_testing() + add_subdirectory(tests) + endif() +endif() diff --git a/Makefile b/Makefile deleted file mode 100644 index 2e29289..0000000 --- a/Makefile +++ /dev/null @@ -1,216 +0,0 @@ -# ============================================================= -# Vix App — Cross-platform build helper -# ============================================================= -# Usage: -# make build → configure + build (ALL) -# make run → build + run (target 'run') -# make clean → delete build folders -# make rebuild → full rebuild -# make preset=name run → override configure preset (ex: dev-msvc) -# make BUILD_PRESET=name → override build preset (ex: build-msvc) -# ============================================================= - -# ---------------- Base Shell ---------------- -SHELL := /bin/bash -.ONESHELL: -.SHELLFLAGS := -eu -o pipefail -c - -# ---------------- Variables ---------------- -VERSION ?= v0.1.0 -BRANCH_DEV ?= dev -BRANCH_MAIN ?= main -REMOTE ?= origin - -# CMake presets / build -PRESET ?= dev-ninja -BUILD_PRESET ?= $(PRESET) -ifeq ($(PRESET),dev-ninja) - BUILD_PRESET := build-ninja -endif -ifeq ($(PRESET),dev-msvc) - BUILD_PRESET := build-msvc -endif -RUN_PRESET ?= $(BUILD_PRESET) -ifeq ($(PRESET),dev-ninja) - RUN_PRESET := run-ninja -endif -ifeq ($(PRESET),dev-msvc) - RUN_PRESET := run-msvc -endif - -CMAKE ?= cmake - -# ---------------- PHONY ---------------- -.PHONY: force_ssh_remote preflight ensure-branch ensure-clean commit push merge tag release \ - test changelog help build run clean rebuild preset \ - coverage publish-mods publish-mods-force - -# ---------------- Help ---------------- -help: - @echo "Targets:" - @echo " release VERSION=vX.Y.Z Run full release flow (commit -> sync -> push/merge -> tag)" - @echo " commit Commit all changes on $(BRANCH_DEV)" - @echo " preflight Sync branches with retries (fetch & rebase)" - @echo " push Push $(BRANCH_DEV) with retries" - @echo " merge Merge $(BRANCH_DEV) -> $(BRANCH_MAIN) and push with retries" - @echo " tag VERSION=vX.Y.Z Create and push annotated tag" - @echo " test Run ctest if build/ exists, otherwise composer test" - @echo " changelog Run scripts/update_changelog.sh if present" - @echo " build Configure + build (CMake preset: $(PRESET))" - @echo " run Build + run (uses run preset: $(RUN_PRESET))" - @echo " clean Remove build artifacts" - @echo " rebuild Full rebuild (clean + build)" - @echo " preset Placeholder target to override PRESET variable" - -# ---------------- Git Remote (force SSH) ---------------- -force_ssh_remote: - @echo "🔐 Forcing SSH for GitHub remotes..." - @git config --global url."git@github.com:".insteadOf https://github.com/ - @url="$$(git remote get-url $(REMOTE))"; \ - if [[ "$$url" =~ ^https://github.com/ ]]; then \ - new="$${url/https:\/\/github.com\//git@github.com:}"; \ - echo "🔁 Switching $(REMOTE) to $$new"; \ - git remote set-url $(REMOTE) "$$new"; \ - fi - @echo "Remote $(REMOTE): $$(git remote get-url $(REMOTE))" - @ssh -T git@github.com >/dev/null 2>&1 || true - -# ---------------- Guards ---------------- -ensure-branch: - @if [ "$$(git rev-parse --abbrev-ref HEAD)" != "$(BRANCH_DEV)" ]; then \ - echo "❌ You must be on $(BRANCH_DEV) to run this target."; \ - exit 1; \ - fi - -ensure-clean: - @if [ -n "$$(git status --porcelain)" ]; then \ - echo "❌ Working tree not clean. Commit or stash first."; \ - git status --porcelain; \ - exit 1; \ - fi - -# ---------------- Sync (avec retries) ---------------- -preflight: force_ssh_remote - @echo "🔎 Sync $(BRANCH_DEV) & $(BRANCH_MAIN) ..." - @tries=0; until git fetch $(REMOTE); do \ - tries=$$((tries+1)); \ - if [ $$tries -ge 5 ]; then echo "❌ git fetch failed after $$tries tries"; exit 128; fi; \ - echo "⏳ Retry $$tries (fetch)..."; sleep 3; \ - done - @git show-ref --verify --quiet refs/heads/$(BRANCH_DEV) || git branch $(BRANCH_DEV) $(REMOTE)/$(BRANCH_DEV) || true - @git show-ref --verify --quiet refs/heads/$(BRANCH_MAIN) || git branch $(BRANCH_MAIN) $(REMOTE)/$(BRANCH_MAIN) || true - - @tries=0; until git checkout $(BRANCH_DEV) && git pull --rebase $(REMOTE) $(BRANCH_DEV); do \ - tries=$$((tries+1)); \ - if [ $$tries -ge 5 ]; then echo "❌ rebase $(BRANCH_DEV) failed after $$tries tries"; exit 128; fi; \ - echo "⏳ Retry $$tries (pull --rebase $(BRANCH_DEV))..."; sleep 3; \ - done - - @tries=0; until git checkout $(BRANCH_MAIN) && git pull --rebase $(REMOTE) $(BRANCH_MAIN); do \ - tries=$$((tries+1)); \ - if [ $$tries -ge 5 ]; then echo "❌ rebase $(BRANCH_MAIN) failed after $$tries tries"; exit 128; fi; \ - echo "⏳ Retry $$tries (pull --rebase $(BRANCH_MAIN))..."; sleep 3; \ - done - - @git checkout $(BRANCH_DEV) - @echo "✅ Preflight sync OK" - -# ---------------- Core Flow ---------------- -commit: ensure-branch - @if [ -n "$$(git status --porcelain)" ]; then \ - echo "📝 Committing changes..."; \ - git add -A; \ - git commit -m "chore(release): prepare $(VERSION)"; \ - else \ - echo "✅ Nothing to commit."; \ - fi - -push: force_ssh_remote - @tries=0; until git push $(REMOTE) $(BRANCH_DEV); do \ - tries=$$((tries+1)); \ - if [ $$tries -ge 5 ]; then echo "❌ push $(BRANCH_DEV) failed after $$tries tries"; exit 128; fi; \ - echo "⏳ Retry $$tries..."; sleep 3; \ - done - -merge: force_ssh_remote - git checkout $(BRANCH_MAIN) - git merge --no-ff --no-edit $(BRANCH_DEV) - @tries=0; until git push $(REMOTE) $(BRANCH_MAIN); do \ - tries=$$((tries+1)); \ - if [ $$tries -ge 5 ]; then echo "❌ push $(BRANCH_MAIN) failed after $$tries tries"; exit 128; fi; \ - echo "⏳ Retry $$tries..."; sleep 3; \ - done - git checkout $(BRANCH_DEV) - @echo "✅ Merge & push to $(BRANCH_MAIN) OK" - -tag: force_ssh_remote - @if ! [[ "$(VERSION)" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$$ ]]; then \ - echo "❌ VERSION must look like vX.Y.Z (got '$(VERSION)')"; exit 1; \ - fi - @if git rev-parse -q --verify "refs/tags/$(VERSION)" >/dev/null; then \ - echo "❌ Tag $(VERSION) already exists."; exit 1; \ - fi - @echo "🏷️ Creating annotated tag $(VERSION)..." - git tag -a $(VERSION) -m "chore(release): $(VERSION)" - @tries=0; until git push $(REMOTE) $(VERSION); do \ - tries=$$((tries+1)); \ - if [ $$tries -ge 5 ]; then echo "❌ push tag $(VERSION) failed after $$tries tries"; exit 128; fi; \ - echo "⏳ Retry $$tries..."; sleep 3; \ - done - @echo "✅ Tag $(VERSION) pushed" - -# ---------------- Orchestration ---------------- -# Ordre sûr : commit -> preflight(sync) -> ensure-clean -> push dev -> merge to main -> tag -release: ensure-branch force_ssh_remote commit preflight ensure-clean push merge tag - @echo "🎉 Release $(VERSION) done!" - -# ---------------- Extras / Tests ---------------- -# Try ctest if build dir exists, otherwise fallback to composer test -test: - @if [ -d "./build" ] || ls build-* 1>/dev/null 2>&1; then \ - echo "🔬 Running ctest..."; \ - ctest --test-dir ./build || exit $$?; \ - else \ - echo "🔬 No build folder found — running composer test fallback..."; \ - @composer test || true; \ - fi - -coverage: - @XDEBUG_MODE=coverage vendor/bin/phpunit || true - -publish-mods: - php bin/ivi modules:publish-assets || true - -publish-mods-force: - php bin/ivi modules:publish-assets --force || true - -changelog: - @bash scripts/update_changelog.sh || true - -# ---------------- CMake / Build section ---------------- -# Configure preset (CMake 'configurePresets') -# Build preset (CMake 'buildPresets') is mapped above -all: build - -build: - @echo "⚙️ Configuring with preset '$(PRESET)' and building '$(BUILD_PRESET)'..." - @$(CMAKE) --preset $(PRESET) - @$(CMAKE) --build --preset $(BUILD_PRESET) - -run: - @echo "▶ Building and running (preset: $(RUN_PRESET))..." - @$(CMAKE) --preset $(PRESET) - @$(CMAKE) --build --preset $(RUN_PRESET) --target run - -clean: - @echo "🧹 Cleaning build artifacts..." - @rm -rf build-* CMakeFiles CMakeCache.txt || true - -rebuild: clean build - -preset: - @: - -# ---------------- Misc ---------------- -# Keep this file easy to extend for CI or dev machines. - diff --git a/README.md b/README.md index 504b137..7c65f04 100644 --- a/README.md +++ b/README.md @@ -1 +1,306 @@ # Rix + +Rix is the unified userland library layer for Vix.cpp. + +It gives Vix C++ projects a single optional facade object: + +```cpp +#include + +int main() +{ + rix.debug.print("Hello", "Rix"); + + auto table = rix.csv.parse("name,language\nAda,C++\n"); + + rix.debug.log("loaded {} rows", table.size()); +} +``` + +Rix does not replace Vix. + +Vix provides the runtime, CLI, build workflow, registry integration, and core foundations. + +Rix provides optional userland packages and a unified facade over them. + +## Design + +Rix is built around two levels. + +```txt +@rix/csv +@rix/debug +@rix/config +@rix/table +``` + +These are independent packages. + +```txt +@rix/rix +``` + +This is the unified facade package. + +The facade mounts independent packages into one object-style API: + +```cpp +rix.csv.parse(...) +rix.debug.print(...) +rix.debug.format(...) +rix.debug.log(...) +rix.debug.inspect(...) +``` + +## Install + +```bash +vix add @rix/rix +vix install +``` + +## Use + +```cpp +#include + +int main() +{ + rix.debug.print("Hello", "Rix"); + + const auto message = rix.debug.format("Package: {}", "rix/rix"); + + rix.debug.log("message: {}", message); + + return 0; +} +``` + +## Current modules + +| Package | Facade API | Description | +| ------------ | ----------- | -------------------------------------------------------------- | +| `@rix/csv` | `rix.csv` | Small CSV reader and writer for Vix C++ projects. | +| `@rix/debug` | `rix.debug` | Debug printing, formatting, logging, and inspection utilities. | + +## CSV example + +```cpp +#include +#include + +int main() +{ + const std::string input = + "name,language\n" + "Ada,C++\n" + "Gaspard,Vix\n"; + + const auto table = rix.csv.parse(input); + + rix.debug.log("loaded {} rows", table.size()); + + for (const auto &row : table) + { + for (const auto &field : row) + { + rix.debug.print(field); + } + } + + return 0; +} +``` + +## Debug example + +```cpp +#include + +int main() +{ + rix.debug.print("Hello", "Rix"); + + auto text = rix.debug.format("Package: {}", "rix/rix"); + + rix.debug.log("loaded {} APIs", 4); + rix.debug.log.warn("slow path: {}ms", 120); + + rix.debug.inspect(text); + + return 0; +} +``` + +## Print and format + +`rix.debug.print` does not replace `{}` placeholders. + +It prints values separated by spaces: + +```cpp +rix.debug.print("Hello", "Rix"); +rix.debug.print(1, 2, 3); +``` + +Output: + +```txt +Hello Rix +1 2 3 +``` + +For placeholder formatting, use `rix.debug.format`: + +```cpp +auto text = rix.debug.format("Hello {}", "Rix"); +rix.debug.print(text); +``` + +Or use `rix.debug.log` directly: + +```cpp +rix.debug.log("Hello {}", "Rix"); +``` + +## Independent packages + +Each Rix module can also be used independently. + +For example: + +```bash +vix add @rix/csv +vix install +``` + +```cpp +#include + +int main() +{ + rixlib::csv::Csv csv; + auto table = csv.parse("name,language\nAda,C++\n"); + + return 0; +} +``` + +And: + +```bash +vix add @rix/debug +vix install +``` + +```cpp +#include + +int main() +{ + rixlib::debug::Debug debug; + + debug.print("Hello", "Rix"); + debug.log("loaded {} rows", 3); + + return 0; +} +``` + +## Repository layout + +```txt +rix/ +├── include/ +│ └── rix.hpp +├── examples/ +│ ├── basic.cpp +│ ├── csv.cpp +│ └── debug.cpp +├── tests/ +│ └── rix_tests.cpp +├── packages/ +│ ├── csv/ +│ │ ├── README.md +│ │ └── vix.json +│ └── debug/ +│ ├── README.md +│ └── vix.json +├── CMakeLists.txt +├── vix.json +├── vix.lock +└── README.md +``` + +## Role of this repository + +This repository has two roles. + +First, it is the source package for the unified facade: + +```txt +@rix/rix +``` + +Second, it is the official human-readable index of Rix packages: + +```txt +packages/csv +packages/debug +``` + +The real source code of each independent package lives in its own repository: + +```txt +https://github.com/rixcpp/csv +https://github.com/rixcpp/debug +``` + +## Build + +```bash +vix install +vix build --build-target all -v +``` + +## Run examples + +Because this repository contains multiple examples, run one explicitly: + +```bash +vix run rix_basic +vix run rix_csv_example +vix run rix_debug_example +``` + +## Tests + +```bash +vix tests +``` + +## Package model + +```txt +Vix -> runtime, CLI, build workflow, registry client +Rix -> userland libraries and unified facade +Registry -> package metadata and version resolution +``` + +Rix keeps packages modular while still offering one clean entry point for users who want the full standard userland layer. + +## Current facade API + +```cpp +rix.csv.parse(...) +rix.csv.write(...) + +rix.debug.print(...) +rix.debug.format(...) +rix.debug.log(...) +rix.debug.inspect(...) +``` + +## License + +MIT diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..12ef08f --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,26 @@ +add_executable(rix_basic + basic.cpp +) + +target_link_libraries(rix_basic + PRIVATE + rix::rix +) + +add_executable(rix_csv_example + csv.cpp +) + +target_link_libraries(rix_csv_example + PRIVATE + rix::rix +) + +add_executable(rix_debug_example + debug.cpp +) + +target_link_libraries(rix_debug_example + PRIVATE + rix::rix +) diff --git a/examples/basic.cpp b/examples/basic.cpp new file mode 100644 index 0000000..9f1b8b2 --- /dev/null +++ b/examples/basic.cpp @@ -0,0 +1,14 @@ +/** + * @file basic.cpp + * @brief Basic example for the unified Rix facade. + */ + +#include + +int main() +{ + rix.debug.print("Hello", "Rix"); + rix.debug.log("facade is ready"); + + return 0; +} diff --git a/examples/csv.cpp b/examples/csv.cpp new file mode 100644 index 0000000..853aa20 --- /dev/null +++ b/examples/csv.cpp @@ -0,0 +1,47 @@ +/** + * @file csv.cpp + * @brief CSV example for the unified Rix facade. + */ + +#include + +#include +#include + +namespace +{ + void print_table(const rixlib::csv::Table &table) + { + for (const auto &row : table) + { + std::ostringstream line; + + for (std::size_t i = 0; i < row.size(); ++i) + { + if (i > 0) + { + line << " "; + } + + line << row[i]; + } + + rix.debug.print(line.str()); + } + } +} + +int main() +{ + const std::string input = + "name,language\n" + "Ada,C++\n" + "Gaspard,Vix\n"; + + const auto table = rix.csv.parse(input); + + rix.debug.log("loaded {} rows", table.size()); + print_table(table); + + return 0; +} diff --git a/examples/debug.cpp b/examples/debug.cpp new file mode 100644 index 0000000..37aa164 --- /dev/null +++ b/examples/debug.cpp @@ -0,0 +1,20 @@ +/** + * @file debug.cpp + * @brief Debug example for the unified Rix facade. + */ + +#include + +int main() +{ + rix.debug.print("Hello", "Rix"); + + const std::string package = rix.debug.format("Package: {}", "rix/rix"); + + rix.debug.print(package); + rix.debug.log("loaded {} debug APIs", 4); + rix.debug.log.warn("this is a warning: {}", "slow path"); + rix.debug.inspect(package); + + return 0; +} diff --git a/include/rix.hpp b/include/rix.hpp new file mode 100644 index 0000000..53d0788 --- /dev/null +++ b/include/rix.hpp @@ -0,0 +1,65 @@ +/** + * @file rix.hpp + * @brief Unified Rix facade. + * + * This header exposes the global `rix` object. + * + * The package `@rix/rix` is the optional unified facade for Rix packages. + * Individual packages such as `@rix/csv` and `@rix/debug` stay independent, + * but this facade mounts them into one object-style API. + * + * Example: + * + * @code + * auto table = rix.csv.parse("name,lang\nAda,C++\n"); + * rix.debug.print("loaded rows:", table.size()); + * rix.debug.log("loaded {} rows", table.size()); + * @endcode + * + * @author Gaspard Kirira + */ + +#ifndef RIXCPP_RIX_INCLUDE_RIX_HPP_INCLUDED +#define RIXCPP_RIX_INCLUDE_RIX_HPP_INCLUDED + +#include +#include + +namespace rixlib +{ + /** + * @brief Unified Rix API facade. + * + * This class groups independent Rix components into one object. + */ + class Rix + { + public: + /** + * @brief CSV reader and writer component. + */ + rixlib::csv::Csv csv{}; + + /** + * @brief Debug printing, formatting, logging, and inspection component. + */ + rixlib::debug::Debug debug{}; + }; +} + +/** + * @brief Global Rix facade object. + * + * This object allows API usage such as: + * + * @code + * rix.csv.parse(...) + * rix.debug.print(...) + * rix.debug.format(...) + * rix.debug.log(...) + * rix.debug.inspect(...) + * @endcode + */ +inline constexpr rixlib::Rix rix{}; + +#endif // RIXCPP_RIX_INCLUDE_RIX_HPP_INCLUDED diff --git a/modules/.gitkeep b/modules/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/packages/csv/README.md b/packages/csv/README.md new file mode 100644 index 0000000..e7a9480 --- /dev/null +++ b/packages/csv/README.md @@ -0,0 +1,74 @@ +# rix/csv + +Small CSV reader and writer for Vix C++ projects. + +`rix/csv` is part of Rix, the userland package layer for the Vix.cpp ecosystem. + +The source code lives in its own repository. This folder only keeps the official package entry used by the Rix umbrella repository. + +## Install + +```bash +vix add @rix/csv +vix install +``` + +## Use + +```cpp +#include + +int main() +{ + rixlib::csv::Csv csv; + auto table = csv.parse("name,lang\nAda,C++\n"); +} +``` + +## Run + +```bash +vix run main.cpp +``` + +## Repository + +```txt +https://github.com/rixcpp/csv +``` + +## Package + +```txt +rix/csv +``` + +## Namespace + +```cpp +rix::csv +``` + +## CMake target + +```cmake +rix::csv +``` + +## Manifest + +```txt +packages/csv/vix.json +``` + +## Role in Rix + +Rix does not embed package source code. + +The real library lives in: + +```txt +github.com/rixcpp/csv +``` + +The Rix umbrella keeps only the public package entry, documentation, and metadata. diff --git a/packages/csv/vix.json b/packages/csv/vix.json new file mode 100644 index 0000000..5af5b19 --- /dev/null +++ b/packages/csv/vix.json @@ -0,0 +1,26 @@ +{ + "name": "csv", + "namespace": "rix", + "version": "0.2.0", + "type": "header-only", + "include": "include", + "license": "MIT", + "description": "Small CSV reader and writer for Vix C++ projects.", + "keywords": [ + "cpp", + "csv", + "rix", + "vix" + ], + "repository": "https://github.com/rixcpp/csv", + "authors": [ + { + "name": "Gaspard Kirira", + "github": "rixcpp" + } + ], + "cmake": { + "target": "rix::csv" + }, + "deps": [] +} diff --git a/packages/debug/README.md b/packages/debug/README.md new file mode 100644 index 0000000..8c4199e --- /dev/null +++ b/packages/debug/README.md @@ -0,0 +1,208 @@ +# @rix/debug + +Debug utilities for Rix. + +`@rix/debug` provides a small set of developer-focused tools for C++ projects: + +- formatted strings +- simple logging +- value inspection +- print helpers + +It can be used as an independent Rix package, or through the unified `@rix/rix` facade. + +## Installation + +```bash +vix add @rix/debug +vix install +``` + +## Basic usage + +```cpp +#include + +int main() +{ + rixlib::debug::Debug debug{}; + + debug.print("Hello", "Rix"); + + auto text = debug.format("Package: {}", "rix/debug"); + + debug.log("loaded {} rows", 3); + debug.log.warn("slow request: {}ms", 120); + + debug.inspect(text); + + return 0; +} +``` + +Output: + +```txt +Hello Rix +[debug] loaded 3 rows +[warn] slow request: 120ms +Package: rix/debug +``` + +## Formatting + +`debug.format` supports simple placeholder-based formatting. + +```cpp +auto message = debug.format("Hello {}", "Rix"); +auto result = debug.format("{0} + {0} = {1}", 2, 4); +auto escaped = debug.format("{{ value }} = {}", 42); +``` + +Supported placeholders: + +```txt +{} automatic argument indexing +{0} explicit positional indexing +{{ escaped opening brace +}} escaped closing brace +``` + +Format specifiers such as `{:>10}` or `{:.2f}` are intentionally not supported. + +## Logging + +```cpp +debug.log("loaded {} rows", 3); +debug.log.info("server started"); +debug.log.warn("slow request: {}ms", 120); +debug.log.error("failed: {}", "timeout"); +``` + +Output: + +```txt +[debug] loaded 3 rows +[info] server started +[warn] slow request: 120ms +[error] failed: timeout +``` + +## Printing + +`debug.print` is not a formatter. + +It prints values separated by spaces. + +```cpp +debug.print("Hello", "Rix"); +debug.print(1, 2, 3); +``` + +Output: + +```txt +Hello Rix +1 2 3 +``` + +For formatted strings, use `debug.format` or `debug.log`. + +```cpp +debug.print(debug.format("Hello {}", "Rix")); +``` + +## Inspection + +```cpp +debug.inspect(42); + +auto value = debug.inspect.to_string(true); + +bool ok = debug.inspect.check(42, 42); +``` + +Inspection is useful for debugging values, containers, optional values, variants, and other supported C++ types. + +## Independent API + +You can also use the free functions directly. + +```cpp +#include + +int main() +{ + rixlib::print("Hello", "Rix"); + + auto text = rixlib::format("Package: {}", "rix/debug"); + + rixlib::inspect(text); + + return 0; +} +``` + +## Unified Rix facade + +When used through `@rix/rix`, the debug package is mounted under `rix.debug`. + +```cpp +#include + +int main() +{ + rix.debug.print("Hello", "Rix"); + rix.debug.log("loaded {} rows", 3); + + return 0; +} +``` + +## Design + +`@rix/debug` is intentionally small and focused. + +It does not try to replace full logging frameworks or formatting libraries. Its role is to provide simple debugging primitives that are easy to use in Rix-based C++ projects. + +The package exposes two layers: + +```txt +rixlib::format(...) +rixlib::print(...) +rixlib::inspect(...) +``` + +and the object-style API: + +```txt +rixlib::debug::Debug +``` + +This keeps the package usable on its own while allowing the unified Rix facade to mount it cleanly as: + +```txt +rix.debug +``` + +## Build + +```bash +vix build +``` + +## Run example + +```bash +vix run +``` + +## Tests + +```bash +vix tests +``` + +## License + +MIT diff --git a/packages/debug/vix.json b/packages/debug/vix.json new file mode 100644 index 0000000..d6f2d54 --- /dev/null +++ b/packages/debug/vix.json @@ -0,0 +1,30 @@ +{ + "name": "debug", + "namespace": "rix", + "version": "0.2.0", + "type": "header-only", + "include": "include", + "license": "MIT", + "description": "Debug printing, formatting, logging, and inspection utilities for Rix.", + "keywords": [ + "cpp", + "debug", + "print", + "format", + "log", + "inspect", + "rix", + "vix" + ], + "repository": "https://github.com/rixcpp/debug", + "maintainers": [ + { + "name": "Gaspard kirira", + "github": "Gaspardkirira" + } + ], + "cmake": { + "target": "rix::debug" + }, + "deps": [] +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..bb739d8 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,13 @@ +add_executable(rix_tests + rix_tests.cpp +) + +target_link_libraries(rix_tests + PRIVATE + rix::rix +) + +add_test( + NAME rix_tests + COMMAND rix_tests +) diff --git a/tests/rix_tests.cpp b/tests/rix_tests.cpp new file mode 100644 index 0000000..42a143f --- /dev/null +++ b/tests/rix_tests.cpp @@ -0,0 +1,169 @@ +/** + * @file rix_tests.cpp + * @brief Basic tests for the unified Rix facade. + * + * @author Gaspard Kirira + */ + +#include + +#include +#include +#include +#include + +namespace +{ + void expect_true(bool condition, const std::string &message) + { + if (!condition) + { + std::cerr << "FAILED: " << message << '\n'; + std::exit(1); + } + } + + void test_global_rix_csv_parse() + { + const std::string input = + "name,language\n" + "Ada,C++\n"; + + const auto table = rix.csv.parse(input); + + expect_true(table.size() == 2, "rix.csv.parse should return 2 rows"); + expect_true(table[0][0] == "name", "header first field should be name"); + expect_true(table[0][1] == "language", "header second field should be language"); + expect_true(table[1][0] == "Ada", "data first field should be Ada"); + expect_true(table[1][1] == "C++", "data second field should be C++"); + } + + void test_global_rix_csv_write() + { + const rixlib::csv::Table table = { + {"name", "language"}, + {"Ada", "C++"}, + }; + + const std::string output = rix.csv.write(table); + + const std::string expected = + "name,language\n" + "Ada,C++\n"; + + expect_true(output == expected, "rix.csv.write should serialize CSV data"); + } + + void test_global_rix_debug_format() + { + const std::string output = rix.debug.format("Hello {}", "Rix"); + + expect_true( + output == "Hello Rix", + "rix.debug.format should format automatic placeholders"); + } + + void test_global_rix_debug_format_explicit_indexes() + { + const std::string output = rix.debug.format("{0} + {0} = {1}", 2, 4); + + expect_true( + output == "2 + 2 = 4", + "rix.debug.format should format explicit placeholders"); + } + + void test_global_rix_debug_format_escaped_braces() + { + const std::string output = rix.debug.format("{{ value }} = {}", 42); + + expect_true( + output == "{ value } = 42", + "rix.debug.format should support escaped braces"); + } + + void test_global_rix_debug_format_append() + { + std::string output = "prefix: "; + + rix.debug.format.append(output, "{}", "ready"); + + expect_true( + output == "prefix: ready", + "rix.debug.format.append should append formatted text"); + } + + void test_global_rix_debug_format_to() + { + std::string output = "old"; + + rix.debug.format.to(output, "status: {}", "ok"); + + expect_true( + output == "status: ok", + "rix.debug.format.to should replace destination content"); + } + + void test_global_rix_debug_print_to_stream() + { + std::ostringstream out; + + rixlib::print_to(out, "Hello", "Rix"); + + expect_true( + out.str() == "Hello Rix\n", + "rixlib::print_to should write arguments separated by spaces with newline"); + } + + void test_global_rix_debug_inspect_to_string() + { + expect_true( + rix.debug.inspect.to_string(42) == "42", + "rix.debug.inspect.to_string should inspect integers"); + + expect_true( + rix.debug.inspect.to_string(true) == "true", + "rix.debug.inspect.to_string should inspect booleans"); + } + + void test_global_rix_debug_inspect_check_pass() + { + const bool ok = rix.debug.inspect.check(42, 42); + + expect_true( + ok, + "rix.debug.inspect.check should return true when values are equal"); + } + + void test_global_rix_debug_inspect_check_fail() + { + const bool ok = rix.debug.inspect.check(42, 24); + + expect_true( + !ok, + "rix.debug.inspect.check should return false when values are different"); + } + + void run_tests() + { + test_global_rix_csv_parse(); + test_global_rix_csv_write(); + + test_global_rix_debug_format(); + test_global_rix_debug_format_explicit_indexes(); + test_global_rix_debug_format_escaped_braces(); + test_global_rix_debug_format_append(); + test_global_rix_debug_format_to(); + test_global_rix_debug_print_to_stream(); + test_global_rix_debug_inspect_to_string(); + test_global_rix_debug_inspect_check_pass(); + test_global_rix_debug_inspect_check_fail(); + } +} + +int main() +{ + run_tests(); + + std::cout << "rix facade tests passed\n"; + return 0; +} diff --git a/vix.json b/vix.json new file mode 100644 index 0000000..81bd3e9 --- /dev/null +++ b/vix.json @@ -0,0 +1,36 @@ +{ + "cmake": { + "target": "rix::rix" + }, + "deps": [ + { + "id": "rix/csv", + "version": "0.2.0" + }, + { + "id": "rix/debug", + "version": "0.2.0" + } + ], + "description": "Unified Rix facade for Vix C++ projects.", + "include": "include", + "keywords": [ + "cpp", + "rix", + "vix", + "facade", + "standard-library" + ], + "license": "MIT", + "maintainers": [ + { + "github": "rixcpp", + "name": "Rix maintainers" + } + ], + "name": "rix", + "namespace": "rix", + "repository": "https://github.com/rixcpp/rix", + "type": "header-only", + "version": "0.6.0" +} diff --git a/vix.lock b/vix.lock new file mode 100644 index 0000000..3063844 --- /dev/null +++ b/vix.lock @@ -0,0 +1,23 @@ +{ + "dependencies": [ + { + "commit": "fb876411810310180692666593eecf05a7962128", + "hash": "42e26288f206955e68fbbff1a83ffb8b0b2cb5539a9436dff258959e809a3c80", + "id": "rix/csv", + "repo": "https://github.com/rixcpp/csv", + "requested": "0.2.0", + "tag": "v0.2.0", + "version": "0.2.0" + }, + { + "commit": "7ce988db8e20a1d0bcedda81dcb88e4daf01c8a7", + "hash": "a5fa071b814c6beb90a3ed49091307651f6ce996b2bf041d009400fca7746f42", + "id": "rix/debug", + "repo": "https://github.com/rixcpp/debug", + "requested": "0.2.0", + "tag": "v0.2.0", + "version": "0.2.0" + } + ], + "lockVersion": 1 +}