kudzu-forest/elm-initialization/2.0.0

Initialization.Debuggable

This module enables you to prepare more precise debugging information than the Initialization module.

The information provided by this module is available only when you compile your application with elm make --debug.

When you use the Initialization module, the information shown in the Elm Debugger during the initializing phase is often surprisingly poor. This is because all Msg values in that phase are model-transforming functions, which the debugger can only display as <internals>.

By using this module, you can:

  • add String descriptions to each model-transforming function returned by commands
  • inspect additional information when a transformation is executed, based on the initializingModel values before and after the transformation

How to Migrate from the Initialization Module

  1. Change import Initialization as Init to import Initialization.Debuggable as Init. Using the same alias saves time and effort.

  2. Add two type parameters, initUpdateInfo and blockingReason, to type annotation of main function, just after initializingModel parameter in this order.

  3. Add Init.toDebuggableCmd "" (always Nothing) before each Cmd value passed to Cmd.batch in your init function.

  4. Add Init.toDebuggable "" (always Nothing) before each model-transforming function in the Html value returned from the initView function.

  5. Fill in the empty string arguments ("") with descriptions as needed.

  6. Replace any of the (always Nothing) functions with ({ old : initializingModel, new : initializingModel } -> updateInfo), where updateInfo is any type you define. Wrapping the value in Just is usually sufficient.

Example Code

The code below demonstrates how to debug Posix time initialization.

import Html
import Initialization.Debuggable as Init
import Task
import Time


type InitUpdateInfo
    = PosixTimeUpdated { old : Maybe Time.Posix, new : Maybe Time.Posix }


type Msg
    = Tick Time.Posix


main : Init.Program () { mTimezone : Maybe Time.Zone, mPosixTime : Maybe Time.Posix } (Maybe InitUpdateInfo) String { timezone : Time.Zone, posixTime : Time.Posix } Msg
main =
    Init.element
        { init =
            \() ->
                ( { mTimezone = Nothing
                  , mPosixTime = Nothing
                  }
                , Cmd.batch
                    [ Init.toDebuggableCmd ""
                        (always Nothing)
                        (Task.perform (\tz im -> { im | mTimezone = Just tz }) Time.here)
                    , Init.toDebuggableCmd "updating posix time"
                        (\{ old, new } -> Just (PosixTimeUpdated { old = old.mPosixTime, new = new.mPosixTime }))
                        (Task.perform (\pt im -> { im | mPosixTime = Just pt }) Time.now)
                    ]
                )
        , initView =
            \blockingReasons iModel -> Html.div [] (List.map Html.text blockingReasons |> List.intersperse (Html.br [] []))
        , toRunning =
            \{ mTimezone, mPosixTime } ->
                Ok (\tz pt -> ( { timezone = tz, posixTime = pt }, Cmd.none ))
                    |> Init.accumulate
                        (Result.fromMaybe "No timezone" mTimezone)
                    |> Init.accumulate
                        (Result.fromMaybe "No posixTime" mPosixTime)
        }
        { subscriptions =
            \_ -> Time.every 1000 Tick
        , update =
            \msg model ->
                case msg of
                    Tick pt ->
                        ( { model | posixTime = pt }, Cmd.none )
        , view =
            \{ timezone, posixTime } ->
                Html.text <|
                    String.fromInt (Time.toHour timezone posixTime)
                        ++ " : "
                        ++ String.fromInt (Time.toMinute timezone posixTime)
                        ++ " : "
                        ++ String.fromInt (Time.toSecond timezone posixTime)
        }

Types

type alias Program flag initializingModel initUpdateInfo blockingReason runningModel runningMsg =
Program
flag
initializingModel
(MsgWithInfo initUpdateInfo blockingReason initializingModel)
runningModel
runningMsg

Type alias for Platform.Program flag <internally defined Model type> <internally defined Msg type>.

type MsgWithInfo initUpdateInfo blockingReason initializingModel

Msg type used internally to represent model-transforming steps during the initializing phase.

Msg Converters

String
-> ( { old : initializingModel
, new : initializingModel
}
-> initUpdateInfo
)
-> Cmd (initializingModel -> initializingModel)
-> Cmd
(MsgWithInfo initUpdateInfo blockingReason initializingModel)

Converts Cmd (initializingModel -> initializingModel) into Cmd (MsgWithInfo updateInfo blockingReason initializingModel).

This function is intended to be used in the init function.

String
-> ( { old : initializingModel
, new : initializingModel
}
-> initUpdateInfo
)
-> (initializingModel -> initializingModel)
-> MsgWithInfo initUpdateInfo blockingReason initializingModel

Converts initializingModel -> initializingModel into MsgWithInfo updateInfo blockingReason initializingModel.

This function is intended to be used in the initView function.

Main Functions

{ init :
flag
-> ( initializingModel
, Cmd
(MsgWithInfo initUpdateInfo blockingReason initializingModel)
)
, initView :
List blockingReason
-> initializingModel
-> Html
(MsgWithInfo initUpdateInfo blockingReason initializingModel)
, toRunning :
initializingModel
-> Result (List blockingReason) ( runningModel, Cmd runningMsg )
}
-> { subscriptions : runningModel -> Sub runningMsg
, update :
runningMsg -> runningModel -> ( runningModel, Cmd runningMsg )
, view : runningModel -> Html runningMsg
}
-> Program
flag
initializingModel
initUpdateInfo
blockingReason
runningModel
runningMsg

Similar to Initialization.element, but requires that all Msg values are converted from initializingModel -> initializingModel into MsgWithInfo initUpdateInfo blockingReason initializingModel using toDebuggableCmd and toDebuggable.

{ init :
flag
-> ( initializingModel
, Cmd
(MsgWithInfo initUpdateInfo blockingReason initializingModel)
)
, initView :
List blockingReason
-> initializingModel
-> Document
(MsgWithInfo initUpdateInfo blockingReason initializingModel)
, toRunning :
initializingModel
-> Result (List blockingReason) ( runningModel, Cmd runningMsg )
}
-> { subscriptions : runningModel -> Sub runningMsg
, update :
runningMsg -> runningModel -> ( runningModel, Cmd runningMsg )
, view : runningModel -> Document runningMsg
}
-> Program
flag
initializingModel
initUpdateInfo
blockingReason
runningModel
runningMsg

Similar to Initialization.document, but requires that all Msg values are converted from initializingModel -> initializingModel into MsgWithInfo initUpdateInfo blockingReason initializingModel using toDebuggableCmd and toDebuggable.

Helper

Result blockingReason a
-> Result (List blockingReason) (a -> b)
-> Result (List blockingReason) b

The same as Initialization.accumulate.