arowM / elm-update-builder / Update.Sequence

Run Updates sequentially.

A Quick Sample

import Update exposing (Update)
import Update.Sequence as Sequence exposing (Sequence)

type Value
    = Start
    | ClickNext
    | SubmitText
    | NeverUsed

type Msg
    = SequenceMsg (Sequence.Msg Value)

type alias Model =
    { sequence : Sequence.Model
    , notice : String
    , text : String
    }

update : Msg -> Update Model Msg
update (SequenceMsg msg) =
    Sequence.run
        { get = .sequence
        , set = \seq model -> { model | sequence = seq }
        }
        msg
        [ Sequence.on Start
            [ setNotice "Tutorial has started!"
            ]
        , Sequence.on ClickNext
            [ setNotice "The first next button is clicked."
            ]
        , Sequence.on ClickNext
            [ setNotice "The second next button is clicked."
            ]
        , \v -> Sequence.when (v == SubmitText) <| Sequence.with <| \{ text } ->
            if text == "" then
                Sequence.waitAgain <|
                    setNotice "Invalid text. Retry!"
            else
                Sequence.succeed <|
                    setNotice <| text ++ " is submitted."
        , Sequence.on ClickNext
            [ setNotice "The last next button is clicked."
            ]
        ]



-- Helper functions

setNotice : String -> Update Model msg
setNotice notice = Update.modify <| \model -> { model | notice = notice }


-- Test the update function


model0 : Model
model0 =
    { sequence = Sequence.initModel
    , notice = "initial"
    , text = "initial text"
    }

model1 : Model
model1 =
    Update.run
        (update <| SequenceMsg <| Sequence.resolve Start)
        model0
        |> Tuple.first


model1.notice
--> "Tutorial has started!"

model2 : Model
model2 =
    Update.run
        (update <| SequenceMsg <| Sequence.resolve ClickNext)
        model1
        |> Tuple.first

model2.notice
--> "The first next button is clicked."

-- Notice that here we provide the very same event as previous.
model3 : Model
model3 =
    Update.run
        (update <| SequenceMsg <| Sequence.resolve ClickNext)
        model2
        |> Tuple.first


model3.notice
--> "The second next button is clicked."
-- The result shows that we get the second notice rather than the first one.

model4 : Model
model4 =
    Update.run
        (update <| SequenceMsg <| Sequence.resolve SubmitText)
        { model3 | text = "" }
        |> Tuple.first

model4.notice
--> "Invalid text. Retry!"

-- Notice that here we provides the resulting `model4`, but not the previous `model3` again.
model5 : Model
model5 =
    Update.run
        (update <| SequenceMsg <| Sequence.resolve SubmitText)
        { model4 | text = "valid text" }
        |> Tuple.first

model5.notice
--> "valid text is submitted."
-- The result shows that we can retry the current `Sequence`.

model6 : Model
model6 =
    Update.run
        (update <| SequenceMsg <| Sequence.resolve <| ClickNext)
        model5
        |> Tuple.first


model6.notice
--> "The last next button is clicked."

Core


type Sequence model msg

run : Update.Lifter.Lifter model Model -> Msg value -> List (value -> Sequence model msg) -> Update model msg


type Msg value


type Model

initModel : Model

Msg Constructors

resolve : value -> Msg value

Controllers

call : v -> Update model (Msg v)

Primitive Constructors

succeed : Update model msg -> Sequence model msg

Construct a Sequence always succeeds with given Updates.

waitAgain : Update model msg -> Sequence model msg

Construct a Sequence always wait again after evaluating given Updates.

Handle conditions

with : (model -> Sequence model msg) -> Sequence model msg

when : Basics.Bool -> Sequence model msg -> Sequence model msg

Succeed Sequence only if it meets the condition.

Otherwise, it waitAgain with Update.none.

unless : Basics.Bool -> Sequence model msg -> Sequence model msg

Succeed Sequence unless it meets the condition.

Otherwise, it waitAgain with Update.none.

Handle cases

on : value -> List (Update model msg) -> value -> Sequence model msg

Generate a Sequence that succeeds only under certain value.

It succeeds with Updates only if the fired message value is equals to its first argument, otherwise it waitAgain with Update.none.

onAnyOf : List value -> List (Update model msg) -> value -> Sequence model msg

Generate a Sequence that succeeds only under certain values.

It succeeds with Updates only if the fired message value is one of its first argument, otherwise it waitAgain with Update.none.

anyOf : List (value -> Sequence model msg) -> value -> Sequence model msg

Evaluate Sequences from top to bottom.

Once a Sequence succeeds, it does not evaluate subsequent Sequences.

Sequence.anyOf
    [ Sequence.on ClickOk
        [ setNotice "Ok"
        ]
    , Sequence.on ClickNg
        [ setNotice "Ng"
        ]
    ]

onJust : List (a -> Update model msg) -> Maybe a -> Sequence model msg

Generate a Sequence that succeeds only on Just values.

It succeeds with Updates only if the value is Just, otherwise it waitAgain with Update.none.

onNothing : List (Update model msg) -> Maybe a -> Sequence model msg

Generate a Sequence that succeeds only on Nothing values.

It succeeds with Updates only if the value is Nothing, otherwise it waitAgain with Update.none.

onOk : List (a -> Update model msg) -> Result err a -> Sequence model msg

Generate a Sequence that succeeds only on Ok values.

It succeeds with Updates only if the value is Ok, otherwise it waitAgain with Update.none.

onErr : List (err -> Update model msg) -> Result err a -> Sequence model msg

Generate a Sequence that succeeds only on Err values.

It succeeds with Updates only if the value is Err, otherwise it waitAgain with Update.none.