summaryrefslogtreecommitdiff
path: root/2025/ocaml
diff options
context:
space:
mode:
Diffstat (limited to '2025/ocaml')
-rw-r--r--2025/ocaml/.env.template1
-rw-r--r--2025/ocaml/.envrc2
-rwxr-xr-x2025/ocaml/.githooks/commit-msg15
-rwxr-xr-x2025/ocaml/.githooks/pre-push18
-rw-r--r--2025/ocaml/.gitignore3
-rw-r--r--2025/ocaml/.ocamlformat2
-rw-r--r--2025/ocaml/README.md15
-rw-r--r--2025/ocaml/Taskfile.yaml (renamed from 2025/ocaml/Taskfile.yml)44
-rw-r--r--2025/ocaml/advent_of_code.opam (renamed from 2025/ocaml/advent_of_code_2025.opam)20
-rw-r--r--2025/ocaml/bin/dune8
-rw-r--r--2025/ocaml/bin/main.ml4
-rw-r--r--2025/ocaml/dune-project26
-rw-r--r--2025/ocaml/flake.nix10
-rw-r--r--2025/ocaml/lib/application/dune14
-rw-r--r--2025/ocaml/lib/application/logger_sig.mli11
-rw-r--r--2025/ocaml/lib/domain/dune9
-rw-r--r--2025/ocaml/lib/dune3
-rw-r--r--2025/ocaml/lib/infrastructure/dune18
-rw-r--r--2025/ocaml/lib/infrastructure/logger.ml31
-rw-r--r--2025/ocaml/lib/presentation/cli.ml15
-rw-r--r--2025/ocaml/lib/presentation/dune15
-rw-r--r--2025/ocaml/test/application/dune7
-rw-r--r--2025/ocaml/test/application/test_example.ml (renamed from 2025/ocaml/test/test_advent_of_code_2025.ml)0
-rw-r--r--2025/ocaml/test/domain/dune6
-rw-r--r--2025/ocaml/test/domain/test_example.ml0
-rw-r--r--2025/ocaml/test/dune3
-rw-r--r--2025/ocaml/test/infrastructure/dune8
-rw-r--r--2025/ocaml/test/infrastructure/test_example.ml0
-rw-r--r--2025/ocaml/test/presentation/dune11
-rw-r--r--2025/ocaml/test/presentation/test_example.ml0
30 files changed, 282 insertions, 37 deletions
diff --git a/2025/ocaml/.env.template b/2025/ocaml/.env.template
new file mode 100644
index 0000000..3adee3e
--- /dev/null
+++ b/2025/ocaml/.env.template
@@ -0,0 +1 @@
+LOG_LEVEL=debug
diff --git a/2025/ocaml/.envrc b/2025/ocaml/.envrc
index 3550a30..cf8df4b 100644
--- a/2025/ocaml/.envrc
+++ b/2025/ocaml/.envrc
@@ -1 +1,3 @@
+dotenv
+
use flake
diff --git a/2025/ocaml/.githooks/commit-msg b/2025/ocaml/.githooks/commit-msg
new file mode 100755
index 0000000..1c1c287
--- /dev/null
+++ b/2025/ocaml/.githooks/commit-msg
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+# Commit message hook - enforce conventional commit format
+
+commit_regex='^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}|^fixup!'
+
+if ! grep -qE "$commit_regex" "$1"; then
+ echo "โŒ Invalid commit message format!"
+ echo ""
+ echo "Format: type(scope): description"
+ echo "Types: feat, fix, docs, style, refactor, test, chore"
+ echo "Example: feat(auth): add user login functionality"
+ echo ""
+ echo "Your message: $(cat $1)"
+ exit 1
+fi
diff --git a/2025/ocaml/.githooks/pre-push b/2025/ocaml/.githooks/pre-push
new file mode 100755
index 0000000..51a8761
--- /dev/null
+++ b/2025/ocaml/.githooks/pre-push
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Pre-push hook - run tests before pushing
+
+set -e
+
+echo "๐Ÿงช Running tests before push..."
+
+# Run the full test suite
+task test
+
+if [ $? -eq 0 ]; then
+ echo "โœ… All tests passed! Push allowed."
+ exit 0
+else
+ echo "โŒ Tests failed! Push blocked."
+ echo "Fix the failing tests before pushing."
+ exit 1
+fi
diff --git a/2025/ocaml/.gitignore b/2025/ocaml/.gitignore
index cb02e52..5456007 100644
--- a/2025/ocaml/.gitignore
+++ b/2025/ocaml/.gitignore
@@ -38,5 +38,8 @@ _opam/
# DirEnv cache
.direnv/
+# Environment variables
+*.env
+
# Taskfile cache
.task/
diff --git a/2025/ocaml/.ocamlformat b/2025/ocaml/.ocamlformat
index d22b51c..6fdcd22 100644
--- a/2025/ocaml/.ocamlformat
+++ b/2025/ocaml/.ocamlformat
@@ -1,3 +1,3 @@
-profile = default
+profile = ocamlformat
version = 0.28.1
diff --git a/2025/ocaml/README.md b/2025/ocaml/README.md
index ef9bc42..772c76b 100644
--- a/2025/ocaml/README.md
+++ b/2025/ocaml/README.md
@@ -1,4 +1,12 @@
-# Advent of Code 2025
+# OCaml Template
+
+This is a template for OCaml projects.
+
+## Quick Start
+
+1. Fork this repository
+2. Rename the repository to your project name
+3. Replace all instances of `advent_of_code` with your project name, both in files and filenames themselves.
## Project Structure
@@ -21,8 +29,8 @@
โ”œโ”€โ”€ dune-project # dune project configuration
โ”œโ”€โ”€ flake.lock
โ”œโ”€โ”€ flake.nix # nix flake configuration
-โ”œโ”€โ”€ advent_of_code_2025.install # autogenerated install script
-โ””โ”€โ”€ advent_of_code_2025.opam # autogenerated project description
+โ”œโ”€โ”€ advent_of_code.install # autogenerated install script
+โ””โ”€โ”€ advent_of_code.opam # autogenerated project description
```
## Tools
@@ -37,7 +45,6 @@
- [ocaml-lsp](https://github.com/ocaml/ocaml-lsp)
- [earlybird](https://github.com/ocaml-lsp/earlybird)
- [findlib](https://github.com/ocaml/ocamlfind)
-- [menhir](https://github.com/ocaml-menhir/menhir)
- [re2](https://github.com/janestreet/re2)
- [fmt](https://erratique.ch/software/fmt)
- [cmdliner](https://erratique.ch/software/cmdliner)
diff --git a/2025/ocaml/Taskfile.yml b/2025/ocaml/Taskfile.yaml
index b562b3a..7496067 100644
--- a/2025/ocaml/Taskfile.yml
+++ b/2025/ocaml/Taskfile.yaml
@@ -9,7 +9,7 @@ tasks:
- cmd: task --list-all
docs:
- desc: Builds documentation using ocamldoc
+ desc: Builds documentation
preconditions:
- command -v ocamldoc
cmds:
@@ -17,10 +17,7 @@ tasks:
silent: true
test:
- desc: Runs the tests in the 'tests' directory
- ignore_error: true
- env:
- OUNIT_CI: true
+ desc: Runs the tests
preconditions:
- command -v dune
deps:
@@ -29,13 +26,11 @@ tasks:
- cmd: dune runtest {{.CLI_ARGS}}
test:watch:
- desc: Continuously runs the tests in the 'tests' directory
+ desc: Continuously runs the tests
ignore_error: true
sources:
- lib/**/*.ml
- test/**/*.ml
- env:
- OUNIT_CI: true
preconditions:
- command -v dune
deps:
@@ -43,6 +38,19 @@ tasks:
cmds:
- cmd: dune runtest --watch {{.CLI_ARGS}}
+ test:coverage:
+ desc: Runs the tests and reports coverage
+ preconditions:
+ - command -v dune
+ - command -v bisect-ppx-report
+ deps:
+ - task: build
+ cmds:
+ - cmd: rm --recursive --force _coverage
+ - cmd: rm --force _build/default/test/bisect*.coverage
+ - cmd: dune runtest --instrument-with bisect_ppx --force {{.CLI_ARGS}}
+ - cmd: bisect-ppx-report html
+
build:
desc: Builds the project
preconditions:
@@ -50,6 +58,13 @@ tasks:
cmds:
- cmd: dune build
+ build:watch:
+ desc: Builds the project when files change
+ preconditions:
+ - command -v dune
+ cmds:
+ - cmd: dune build --watch {{.CLI_ARGS}}
+
build:release:
desc: Builds a release version the project
preconditions:
@@ -65,3 +80,16 @@ tasks:
- task: build
cmds:
- cmd: dune exec -- ./bin/main.exe {{.CLI_ARGS}}
+
+ repl:
+ desc: Opens a REPL for the project
+ interactive: true
+ preconditions:
+ - command -v dune
+ - command -v utop
+ cmds:
+ - cmd: dune utop
+
+ git:hooks:
+ desc: sets up the githooks for the project
+ cmd: git config core.hooksPath .githooks
diff --git a/2025/ocaml/advent_of_code_2025.opam b/2025/ocaml/advent_of_code.opam
index 3a50035..a6395c9 100644
--- a/2025/ocaml/advent_of_code_2025.opam
+++ b/2025/ocaml/advent_of_code.opam
@@ -1,20 +1,28 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
-synopsis: "Advent of Code 2025"
-description: "Solutions to the puzzles from Advent of Code 2025"
+synopsis: "advent of code solutions for 2025"
+description:
+ "project aiming to solve the advent of code puzzles released for 2025"
maintainer: ["DJ O'Leary <dijitol@proton.me>"]
authors: ["DJ O'Leary <dijitol@proton.me>"]
license: "Unlicense"
-tags: ["Advent of Code 2025"]
+tags: ["project template"]
homepage: "https://github.com/djoleary/advent_of_code"
-doc:
- "https://github.com/djoleary/advent_of_code/blob/main/2025/ocaml/docs/index.html"
+doc: "https://github.com/djoleary/advent_of_code/2025/ocaml/docs/index.html"
bug-reports: "https://github.com/djoleary/advent_of_code/issues"
depends: [
"dune" {>= "3.20"}
- "ocaml"
+ "ocaml" {>= "5.2"}
+ "ppx_deriving" {build}
"alcotest" {with-test}
+ "qcheck" {with-test}
+ "bisect_ppx" {with-test}
+ "ppx_inline_test" {with-test}
+ "ppx_expect" {with-test}
"odoc" {with-doc}
+ "cmdliner"
+ "fmt"
+ "re2"
]
build: [
["dune" "subst"] {dev}
diff --git a/2025/ocaml/bin/dune b/2025/ocaml/bin/dune
index a912fd0..49a288c 100644
--- a/2025/ocaml/bin/dune
+++ b/2025/ocaml/bin/dune
@@ -1,4 +1,8 @@
(executable
- (public_name advent_of_code_2025)
+ (public_name advent_of_code)
(name main)
- (libraries advent_of_code_2025))
+ (libraries
+ domain
+ application
+ infrastructure
+ presentation))
diff --git a/2025/ocaml/bin/main.ml b/2025/ocaml/bin/main.ml
index 7bf6048..f34d5ef 100644
--- a/2025/ocaml/bin/main.ml
+++ b/2025/ocaml/bin/main.ml
@@ -1 +1,3 @@
-let () = print_endline "Hello, World!"
+let main () = Presentation.Cli.run ()
+
+let () = if !Sys.interactive then () else exit (main ())
diff --git a/2025/ocaml/dune-project b/2025/ocaml/dune-project
index 649d68f..a46e495 100644
--- a/2025/ocaml/dune-project
+++ b/2025/ocaml/dune-project
@@ -1,6 +1,6 @@
(lang dune 3.20)
-(name advent_of_code_2025)
+(name advent_of_code)
(generate_opam_files true)
@@ -13,14 +13,26 @@
(license Unlicense)
-(documentation https://github.com/djoleary/advent_of_code/blob/main/2025/ocaml/docs/index.html)
+(documentation https://github.com/djoleary/advent_of_code/2025/ocaml/docs/index.html)
(package
- (name advent_of_code_2025)
- (synopsis "Advent of Code 2025")
- (description "Solutions to the puzzles from Advent of Code 2025")
- (depends ocaml (alcotest :with-test))
+ (name advent_of_code)
+ (synopsis "advent of code solutions for 2025")
+ (description "project aiming to solve the advent of code puzzles released for 2025")
+ (depends
+ (ocaml (>= 5.2))
+ (ppx_deriving :build)
+ (alcotest :with-test)
+ (qcheck :with-test)
+ (bisect_ppx :with-test)
+ (ppx_inline_test :with-test)
+ (ppx_expect :with-test)
+ (odoc :with-doc)
+ cmdliner
+ fmt
+ re2
+ )
(tags
- ("Advent of Code 2025")))
+ ("project template")))
; See the complete stanza docs at https://dune.readthedocs.io/en/stable/reference/dune-project/index.html
diff --git a/2025/ocaml/flake.nix b/2025/ocaml/flake.nix
index 163e41e..54d7b3f 100644
--- a/2025/ocaml/flake.nix
+++ b/2025/ocaml/flake.nix
@@ -25,14 +25,20 @@
utop # REPL
+ odoc # documentation generator
+
alcotest # unit test framework
bisect_ppx # test coverage
-
- odoc # documentation generator
+ qcheck-core # property-based testing
+ qcheck-alcotest # property-based testing
+ janeStreet.ppx_inline_test # inline test library
+ janeStreet.ppx_expect # inline test library
janeStreet.re2 # regular expression library
fmt # pretty printing library
cmdliner # command line library
+ ppx_deriving # derivers
+ logs # logging library
];
sysTools = with pkgs; [
go-task
diff --git a/2025/ocaml/lib/application/dune b/2025/ocaml/lib/application/dune
new file mode 100644
index 0000000..f73f950
--- /dev/null
+++ b/2025/ocaml/lib/application/dune
@@ -0,0 +1,14 @@
+(library
+ (name application)
+ (libraries
+ domain
+ fmt
+ logs)
+ (inline_tests)
+ (preprocess
+ (pps
+ ppx_deriving.show
+ ppx_deriving.eq
+ ppx_deriving.ord
+ ppx_expect))
+ (modules_without_implementation logger_sig))
diff --git a/2025/ocaml/lib/application/logger_sig.mli b/2025/ocaml/lib/application/logger_sig.mli
new file mode 100644
index 0000000..ac84747
--- /dev/null
+++ b/2025/ocaml/lib/application/logger_sig.mli
@@ -0,0 +1,11 @@
+module type Logger = sig
+ val app : string -> unit
+
+ val err : string -> unit
+
+ val warn : string -> unit
+
+ val info : string -> unit
+
+ val debug : string -> unit
+end
diff --git a/2025/ocaml/lib/domain/dune b/2025/ocaml/lib/domain/dune
new file mode 100644
index 0000000..f23b247
--- /dev/null
+++ b/2025/ocaml/lib/domain/dune
@@ -0,0 +1,9 @@
+(library
+ (name domain)
+ (inline_tests)
+ (preprocess
+ (pps
+ ppx_deriving.show
+ ppx_deriving.eq
+ ppx_deriving.ord
+ ppx_expect)))
diff --git a/2025/ocaml/lib/dune b/2025/ocaml/lib/dune
deleted file mode 100644
index 215ce47..0000000
--- a/2025/ocaml/lib/dune
+++ /dev/null
@@ -1,3 +0,0 @@
-(library
- (name advent_of_code_2025)
- (libraries re2 fmt cmdliner))
diff --git a/2025/ocaml/lib/infrastructure/dune b/2025/ocaml/lib/infrastructure/dune
new file mode 100644
index 0000000..9857fbb
--- /dev/null
+++ b/2025/ocaml/lib/infrastructure/dune
@@ -0,0 +1,18 @@
+(library
+ (name infrastructure)
+ (libraries
+ application
+ domain
+ fmt
+ fmt.cli
+ fmt.tty
+ logs
+ logs.cli
+ logs.fmt)
+ (inline_tests)
+ (preprocess
+ (pps
+ ppx_deriving.show
+ ppx_deriving.eq
+ ppx_deriving.ord
+ ppx_expect)))
diff --git a/2025/ocaml/lib/infrastructure/logger.ml b/2025/ocaml/lib/infrastructure/logger.ml
new file mode 100644
index 0000000..d0d37a3
--- /dev/null
+++ b/2025/ocaml/lib/infrastructure/logger.ml
@@ -0,0 +1,31 @@
+module type Configurable_Logger = sig
+ include Application.Logger_sig.Logger
+
+ val configure_logger : level:Logs.level option -> unit
+
+ val parse_level :
+ env:Cmdliner.Cmd.Env.info -> Logs.level option Cmdliner.Term.t
+
+ val configure_renderer : style_renderer:Fmt.style_renderer option -> unit
+end
+
+module CLI_Logger : Configurable_Logger = struct
+ let configure_logger ~level =
+ Logs.set_level level ;
+ Logs.set_reporter (Logs_fmt.reporter ())
+
+ let parse_level ~env = Logs_cli.level ~env ()
+
+ let configure_renderer ~style_renderer =
+ Fmt_tty.setup_std_outputs ?style_renderer ()
+
+ let app msg = Logs.app (fun m -> m "%s" msg)
+
+ let err msg = Logs.err (fun m -> m "%s" msg)
+
+ let warn msg = Logs.warn (fun m -> m "%s" msg)
+
+ let info msg = Logs.info (fun m -> m "%s" msg)
+
+ let debug msg = Logs.debug (fun m -> m "%s" msg)
+end
diff --git a/2025/ocaml/lib/presentation/cli.ml b/2025/ocaml/lib/presentation/cli.ml
new file mode 100644
index 0000000..c306ad2
--- /dev/null
+++ b/2025/ocaml/lib/presentation/cli.ml
@@ -0,0 +1,15 @@
+open Cmdliner
+open Cmdliner.Term.Syntax
+
+let logger () =
+ let env = Cmd.Env.info "LOG_LEVEL" in
+ let+ level = Infrastructure.Logger.CLI_Logger.parse_level ~env
+ and+ style_renderer = Fmt_cli.style_renderer () in
+ Infrastructure.Logger.CLI_Logger.configure_logger ~level ;
+ Fmt_tty.setup_std_outputs ?style_renderer () ;
+ let result_code = 0 in
+ result_code
+
+let cmd = Cmd.v (Cmd.info "tool") @@ logger ()
+
+let run () = Cmd.eval' cmd
diff --git a/2025/ocaml/lib/presentation/dune b/2025/ocaml/lib/presentation/dune
new file mode 100644
index 0000000..a37ca0c
--- /dev/null
+++ b/2025/ocaml/lib/presentation/dune
@@ -0,0 +1,15 @@
+(library
+ (name presentation)
+ (libraries
+ application
+ domain
+ infrastructure
+ cmdliner
+ fmt.cli)
+ (inline_tests)
+ (preprocess
+ (pps
+ ppx_deriving.show
+ ppx_deriving.eq
+ ppx_deriving.ord
+ ppx_expect)))
diff --git a/2025/ocaml/test/application/dune b/2025/ocaml/test/application/dune
new file mode 100644
index 0000000..785d27e
--- /dev/null
+++ b/2025/ocaml/test/application/dune
@@ -0,0 +1,7 @@
+(tests
+ (names
+ test_example)
+ (libraries
+ application
+ domain
+ alcotest))
diff --git a/2025/ocaml/test/test_advent_of_code_2025.ml b/2025/ocaml/test/application/test_example.ml
index e69de29..e69de29 100644
--- a/2025/ocaml/test/test_advent_of_code_2025.ml
+++ b/2025/ocaml/test/application/test_example.ml
diff --git a/2025/ocaml/test/domain/dune b/2025/ocaml/test/domain/dune
new file mode 100644
index 0000000..8bd0a52
--- /dev/null
+++ b/2025/ocaml/test/domain/dune
@@ -0,0 +1,6 @@
+(tests
+ (names
+ test_example)
+ (libraries
+ domain
+ alcotest))
diff --git a/2025/ocaml/test/domain/test_example.ml b/2025/ocaml/test/domain/test_example.ml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/2025/ocaml/test/domain/test_example.ml
diff --git a/2025/ocaml/test/dune b/2025/ocaml/test/dune
deleted file mode 100644
index c90f542..0000000
--- a/2025/ocaml/test/dune
+++ /dev/null
@@ -1,3 +0,0 @@
-(test
- (libraries alcotest)
- (name test_advent_of_code_2025))
diff --git a/2025/ocaml/test/infrastructure/dune b/2025/ocaml/test/infrastructure/dune
new file mode 100644
index 0000000..5d493d9
--- /dev/null
+++ b/2025/ocaml/test/infrastructure/dune
@@ -0,0 +1,8 @@
+(tests
+ (names
+ test_example)
+ (libraries
+ application
+ domain
+ infrastructure
+ alcotest))
diff --git a/2025/ocaml/test/infrastructure/test_example.ml b/2025/ocaml/test/infrastructure/test_example.ml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/2025/ocaml/test/infrastructure/test_example.ml
diff --git a/2025/ocaml/test/presentation/dune b/2025/ocaml/test/presentation/dune
new file mode 100644
index 0000000..e34e56f
--- /dev/null
+++ b/2025/ocaml/test/presentation/dune
@@ -0,0 +1,11 @@
+(tests
+ (names
+ test_example)
+ (libraries
+ application
+ domain
+ infrastructure
+ presentation
+ alcotest
+ qcheck-core
+ qcheck-alcotest))
diff --git a/2025/ocaml/test/presentation/test_example.ml b/2025/ocaml/test/presentation/test_example.ml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/2025/ocaml/test/presentation/test_example.ml