experimenting with this, i threw this contrived but i think relevant example together:
// src/Deps.res
module Clock = SystemClock
module BaseLog = TimestampedLog.Make(Clock, ConsoleLog, SecsSinceStartTimestampedLogFmt)
let mkLog = (name): module(Log.T) =>
module(
NamedLog.Make(
BaseLog,
BracketedNamedLogFmt,
{
let name = name
},
)
)
module FileRepo = InMemoryFileRepo.Make(Clock, unpack(mkLog("bosse")))
// src/DoSomething.res
module Make = (Clock: Clock.T, Log: Log.T) => {
let foo = () => {
let now = Clock.now()->Float.toString
Log.info(`now is ${now}`)
}
}
// src/Main.res
let main = () => {
module DS = DoSomething.Make(Deps.Clock, unpack(Deps.mkLog("DoSomething")))
DS.foo()
}
main()
// src/_Adapters/BracketedNamedLogFmt.res
let fmt = (~name, ~text) => {
`[${name}] ${text}`
}
// src/_Adapters/ConsoleLog.res
let info = Console.log
// src/_Adapters/InMemoryFileRepo.res
module Make = (Clock: Clock.T, Log: Log.T) => {
let store = dict{}
let getById = async id => {
let now = Clock.now()->Float.toString
Log.info(`looking for file: ${id->Id.toString} now is ${now}`)
store->Dict.get(id->Id.toString)
}
let save = async (file: File.t) => {
store->Dict.set(file.id->Id.toString, file)
}
}
// src/_Adapters/NamedLog.res
module Fmt = {
module type T = {
let fmt: (~name: string, ~text: string) => string
}
}
module Make = (
Log: Log.T,
Fmt: Fmt.T,
Conf: {
let name: string
},
) => {
let info = s => {
Log.info(Fmt.fmt(~name=Conf.name, ~text=s))
}
}
// src/_Adapters/SecsSinceStartTimestampedLogFmt.res
let start = Date.now()
let fmt = (~ts, ~text) => {
let s = (ts - start) / 1000.0
`(${s->Float.toString}s) ${text}`
}
// src/_Adapters/SystemClock.res
let now = () => {
Date.now()
}
// src/_Adapters/TimestampedLog.res
module Fmt = {
module type T = {
let fmt: (~ts: float, ~text: string) => string
}
}
module Make = (Clock: Clock.T, Log: Log.T, Fmt: Fmt.T) => {
let info = text => {
let ts = Clock.now()
Log.info(Fmt.fmt(~ts, ~text))
}
}
// src/_Domain/File.res
type t = {
id: Id.t,
name: string,
}
let make = (~id, ~name) => {
id,
name,
}
// src/_Domain/Id.res
type t = string
let fromString = s => s
let toString = s => s
// src/_Ports/Clock.res
module type T = {
let now: unit => float
}
// src/_Ports/FileRepo.res
module type T = {
let getById: Id.t => promise<option<File.t>>
let save: File.t => promise<unit>
}
// src/_Ports/Log.res
module type T = {
let info: string => unit
}
it does get sort of verbose and i could inline a few things here and there. i dont like using unpack however (it seems to be entirely undocumented)
also @tsnobip your input welcome if i’m doing something crazy here