From d70ba66fafb485c9d4541a503ff55f96c5c5255e Mon Sep 17 00:00:00 2001 From: Hayleigh Thompson Date: Wed, 19 Jul 2023 11:44:59 +0100 Subject: :truck: Rename 'Cmd' to 'Effect' to better communicate what they're all about. --- src/lustre.gleam | 75 ++++++++++++++++++++++----------------------- src/lustre/cmd.gleam | 64 -------------------------------------- src/lustre/effect.gleam | 67 ++++++++++++++++++++++++++++++++++++++++ test/examples/counter.gleam | 2 +- test/examples/input.gleam | 2 +- test/examples/nested.gleam | 2 +- 6 files changed, 106 insertions(+), 106 deletions(-) delete mode 100644 src/lustre/cmd.gleam create mode 100644 src/lustre/effect.gleam diff --git a/src/lustre.gleam b/src/lustre.gleam index 1628a33..5c36750 100644 --- a/src/lustre.gleam +++ b/src/lustre.gleam @@ -3,7 +3,7 @@ // IMPORTS --------------------------------------------------------------------- import gleam/result -import lustre/cmd.{Cmd} +import lustre/effect.{Effect} import lustre/element.{Element} // TYPES ----------------------------------------------------------------------- @@ -19,36 +19,33 @@ import lustre/element.{Element} /// in time. /// /// ```text -/// +--------+ -/// | | -/// | update | -/// | | -/// +--------+ -/// ^ | -/// | | -/// Msg | | #(Model, Cmd(Msg)) -/// | | -/// | v -/// +------+ +------------------------+ -/// | | #(Model, Cmd(Msg)) | | -/// | init |--------------------->| Lustre Runtime | -/// | | | | -/// +------+ +------------------------+ -/// ^ | -/// | | -/// Msg | | Model -/// | | -/// | v -/// +--------+ -/// | | -/// | render | -/// | | -/// +--------+ +/// +--------+ +/// | | +/// | update | +/// | | +/// +--------+ +/// ^ | +/// | | +/// Msg | | #(Model, Effect(Msg)) +/// | | +/// | v +/// +------+ +------------------------+ +/// | | #(Model, Effect(Msg)) | | +/// | init |------------------------>| Lustre Runtime | +/// | | | | +/// +------+ +------------------------+ +/// ^ | +/// | | +/// Msg | | Model +/// | | +/// | v +/// +--------+ +/// | | +/// | render | +/// | | +/// +--------+ /// ``` /// -/// Someone please PR the Gleam docs generator to fix the monospace font, -/// thanks! 💖 -/// pub type App(model, msg) pub type Error { @@ -62,7 +59,7 @@ pub type Error { // type Update(model, msg) = - fn(model, msg) -> #(model, Cmd(msg)) + fn(model, msg) -> #(model, Effect(msg)) type Render(model, msg) = fn(model) -> Element(msg) @@ -94,8 +91,8 @@ type Render(model, msg) = /// ``` /// pub fn element(element: Element(msg)) -> App(Nil, msg) { - let init = fn() { #(Nil, cmd.none()) } - let update = fn(_, _) { #(Nil, cmd.none()) } + let init = fn() { #(Nil, effect.none()) } + let update = fn(_, _) { #(Nil, effect.none()) } let render = fn(_) { element } application(init, update, render) @@ -155,20 +152,20 @@ pub fn simple( update: fn(model, msg) -> model, render: fn(model) -> Element(msg), ) -> App(model, msg) { - let init = fn() { #(init(), cmd.none()) } - let update = fn(model, msg) { #(update(model, msg), cmd.none()) } + let init = fn() { #(init(), effect.none()) } + let update = fn(model, msg) { #(update(model, msg), effect.none()) } application(init, update, render) } /// An evolution of a [`simple`](#simple) app that allows you to return a -/// [`Cmd`](./lustre/cmd.html#Cmd) from your `init` and `update`s. Commands give +/// [`Effect`](./lustre/effect.html#Effect) from your `init` and `update`s. Commands give /// us a way to perform side effects like sending an HTTP request or running a /// timer and then dispatch actions back to the runtime to trigger an `update`. /// ///``` /// import lustre -/// import lustre/cmd +/// import lustre/effect /// import lustre/element /// /// pub fn main () { @@ -191,8 +188,8 @@ pub fn simple( /// assert Ok(_) = lustre.start(app, "#root") /// } /// -/// fn tick () -> Cmd(Msg) { -/// cmd.from(fn (dispatch) { +/// fn tick () -> Effect(Msg) { +/// effect.from(fn (dispatch) { /// setInterval(fn () { /// dispatch(Tick) /// }, 1000) @@ -203,7 +200,7 @@ pub fn simple( /// = "" "window.setTimeout" ///``` @external(javascript, "./lustre.ffi.mjs", "setup") -pub fn application(init init: fn() -> #(model, Cmd(msg)), update update: Update( +pub fn application(init init: fn() -> #(model, Effect(msg)), update update: Update( model, msg, ), render render: Render(model, msg)) -> App(model, msg) diff --git a/src/lustre/cmd.gleam b/src/lustre/cmd.gleam deleted file mode 100644 index 251908f..0000000 --- a/src/lustre/cmd.gleam +++ /dev/null @@ -1,64 +0,0 @@ -// IMPORTS --------------------------------------------------------------------- - -import gleam/list - -// TYPES ----------------------------------------------------------------------- - -/// A `Cmd` represents some side effect we want the Lustre runtime to perform. -/// It is parameterised by our app's `action` type because some effects need to -/// get information back into your program. -/// -pub opaque type Cmd(action) { - Cmd(List(fn(fn(action) -> Nil) -> Nil)) -} - -// CONSTRUCTORS ---------------------------------------------------------------- - -/// Create a `Cmd` from some custom side effect. This is mostly useful for -/// package authors, or for integrating other libraries into your Lustre app. -/// -/// We pass in a function that recieves a `dispatch` callback that can be used -/// to send messages to the Lustre runtime. We could, for example, create a `tick` -/// command that uses the `setTimeout` JavaScript API to send a message to the -/// runtime every second: -/// -/// ```gleam -/// import lustre/cmd.{Cmd} -/// -/// external fn set_interval(callback: fn() -> any, interval: Int) = -/// "" "window.setInterval" -/// -/// pub fn every_second(msg: msg) -> Cmd(msg) { -/// use dispatch <- cmd.from -/// -/// set_interval(fn() { dispatch(msg) }, 1000) -/// } -/// ``` -/// -pub fn from(cmd: fn(fn(action) -> Nil) -> Nil) -> Cmd(action) { - Cmd([cmd]) -} - -/// Typically our app's `update` function needs to return a tuple of -/// `#(model, Cmd(action))`. When we don't need to perform any side effects we -/// can just return `none()`! -/// -pub fn none() -> Cmd(action) { - Cmd([]) -} - -// MANIPULATIONS --------------------------------------------------------------- - -/// -/// -pub fn batch(cmds: List(Cmd(action))) -> Cmd(action) { - Cmd({ - use b, Cmd(a) <- list.fold(cmds, []) - list.append(b, a) - }) -} - -pub fn map(cmd: Cmd(a), f: fn(a) -> b) -> Cmd(b) { - let Cmd(l) = cmd - Cmd(list.map(l, fn(cmd) { fn(dispatch) { cmd(fn(a) { dispatch(f(a)) }) } })) -} diff --git a/src/lustre/effect.gleam b/src/lustre/effect.gleam new file mode 100644 index 0000000..19f54b0 --- /dev/null +++ b/src/lustre/effect.gleam @@ -0,0 +1,67 @@ +// IMPORTS --------------------------------------------------------------------- + +import gleam/list + +// TYPES ----------------------------------------------------------------------- + +/// A `Effect` represents some side effect we want the Lustre runtime to perform. +/// It is parameterised by our app's `action` type because some effects need to +/// get information back into your program. +/// +pub opaque type Effect(action) { + Effect(List(fn(fn(action) -> Nil) -> Nil)) +} + +// CONSTRUCTORS ---------------------------------------------------------------- + +/// Create a `Effect` from some custom side effect. This is mostly useful for +/// package authors, or for integrating other libraries into your Lustre app. +/// +/// We pass in a function that recieves a `dispatch` callback that can be used +/// to send messages to the Lustre runtime. We could, for example, create a `tick` +/// command that uses the `setTimeout` JavaScript API to send a message to the +/// runtime every second: +/// +/// ```gleam +/// import lustre/effect.{Effect} +/// +/// external fn set_interval(callback: fn() -> any, interval: Int) = +/// "" "window.setInterval" +/// +/// pub fn every_second(msg: msg) -> Effect(msg) { +/// use dispatch <- effect.from +/// +/// set_interval(fn() { dispatch(msg) }, 1000) +/// } +/// ``` +/// +pub fn from(effect: fn(fn(action) -> Nil) -> Nil) -> Effect(action) { + Effect([effect]) +} + +/// Typically our app's `update` function needs to return a tuple of +/// `#(model, Effect(action))`. When we don't need to perform any side effects we +/// can just return `none()`! +/// +pub fn none() -> Effect(action) { + Effect([]) +} + +// MANIPULATIONS --------------------------------------------------------------- + +/// +/// +pub fn batch(cmds: List(Effect(action))) -> Effect(action) { + Effect({ + use b, Effect(a) <- list.fold(cmds, []) + list.append(b, a) + }) +} + +pub fn map(effect: Effect(a), f: fn(a) -> b) -> Effect(b) { + let Effect(l) = effect + Effect(list.map( + l, + fn(effect) { fn(dispatch) { effect(fn(a) { dispatch(f(a)) }) } }, + )) +} diff --git a/test/examples/counter.gleam b/test/examples/counter.gleam index 0bff35b..3858fc6 100644 --- a/test/examples/counter.gleam +++ b/test/examples/counter.gleam @@ -9,7 +9,7 @@ import lustre/event // MAIN ------------------------------------------------------------------------ pub fn main() { - // A `simple` lustre application doesn't produce `Cmd`s. These are best to + // A `simple` lustre application doesn't produce `Effect`s. These are best to // start with if you're just getting started with lustre or you know you don't // need the runtime to manage any side effects. let app = lustre.simple(init, update, render) diff --git a/test/examples/input.gleam b/test/examples/input.gleam index 9916000..352e480 100644 --- a/test/examples/input.gleam +++ b/test/examples/input.gleam @@ -11,7 +11,7 @@ import lustre/html.{div, input, label, pre} // MAIN ------------------------------------------------------------------------ pub fn main() { - // A `simple` lustre application doesn't produce `Cmd`s. These are best to + // A `simple` lustre application doesn't produce `Effect`s. These are best to // start with if you're just getting started with lustre or you know you don't // need the runtime to manage any side effects. let app = lustre.simple(init, update, render) diff --git a/test/examples/nested.gleam b/test/examples/nested.gleam index bd94abe..b16c4ba 100644 --- a/test/examples/nested.gleam +++ b/test/examples/nested.gleam @@ -11,7 +11,7 @@ import lustre/html.{div} // MAIN ------------------------------------------------------------------------ pub fn main() { - // A `simple` lustre application doesn't produce `Cmd`s. These are best to + // A `simple` lustre application doesn't produce `Effect`s. These are best to // start with if you're just getting started with lustre or you know you don't // need the runtime to manage any side effects. let app = lustre.simple(init, update, render) -- cgit v1.2.3