Generate helpers for variant values
Configure
how to generate a variant helper declaration
plus the necessary imports.
Out of the box, there are
Customize with
Create a custom helper generator (or just parts for replacement) with
You can use the source code of accessors & co. as a starting point.
Build
of named erlandsona/elm-accessors
which with
{ build =
VariantHelper.GenerateUsed.accessors
{ valuesCombined = VariantHelper.GenerateUsed.valuesTupleNest }
, nameInModuleInternal = VariantHelper.GenerateUsed.variantAfter "on"
, nameInModuleExternal = VariantHelper.GenerateUsed.variant
, generationModuleIsVariantModuleDotSuffix = "On"
}and
module Data exposing (Data(..))
type Data a b c d
= Some a b c d
| Nonegenerates
module Data.On exposing (some)
import Accessors exposing (makeOneToN_)
import Data exposing (Data(..))
{-| Accessor prism for the variant `Data.Some` of the `type Data`.
-}
some :
Relation ( a, ( b, ( c, d ) ) ) reachable wrap
-> Relation (Data a b c d) reachable (Maybe wrap)
some =
makeOneToN_
"Data.Some"
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter |> Just
_ ->
Nothing
)
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
let
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3
other ->
other
)Build
of unnamed bChiquet/elm-accessors
which with
{ build =
VariantHelper.GenerateUsed.accessorsBChiquet
{ valuesCombined = VariantHelper.GenerateUsed.valuesTupleNest }
, nameInModuleInternal = VariantHelper.GenerateUsed.variant
, nameInModuleExternal = VariantHelper.GenerateUsed.variantAfter "on"
, generationModuleIsVariantModuleDotSuffix = "On"
}and
module Data exposing (Data(..))
type Data a b c d
= Some a b c d
| Nonegenerates
module Data.On exposing (some)
import Accessors exposing (Lens, Relation, makeOneToN_)
import Data exposing (Data(..))
{-| Accessor prism for the variant `Data.Some` of the `type Data`.
-}
some :
Relation ( a, ( b, ( c, d ) ) ) reachable wrap
-> Relation (Data a b c d) reachable (Maybe wrap)
some =
makeOneToN
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter |> Just
_ ->
Nothing
)
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
let
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3
other ->
other
)Build a different documentation:
accessorsDocumentedCustom info =
accessors
{ valuesCombined = valuesRecord }
info
|> documented
(emptyDocComment
|> markdown
("variant `" ++ info.variantName ++ "`: Accessor for the values.")
)Build a different type annotation:
import Hand exposing (Hand(..))
import Stack
accessorsAnnotatedOption : Build
accessorsAnnotatedOption info =
accessors
{ valuesCombined = valuesRecord }
info
|> annotated
(typed "Option"
[ CodeGen.typed info.typeName
(info.typeParameters |> List.map CodeGen.typeVar)
, case variantValues |> Stack.fromList of
Empty _ ->
CodeGen.unitAnn
Filled stacked ->
Filled stacked
|> Stack.reverse
|> Stack.fold (\value soFar -> CodeGen.tupleAnn [ value, soFar ])
, CodeGen.typeVar "reachable"
, CodeGen.typeVar "wrap"
]
)
|> importsAdd
[ impostStmt [ "Accessors" ]
Nothing
([ "Option" |> typeOrAliasExpose ] |> exposingExplicit |> Just)
]Make sure to importsAdd.
Supply additional imports required for generating the declaration.
accessorsAnnotatedOption : Build
accessorsAnnotatedOption info =
accessors info
|> annotated (typed "Option" [ ... ])
|> importsAdd
[ impostStmt [ "Accessors" ]
Nothing
([ "Option" |> typeOrAliasExpose ] |> exposingExplicit |> Just)
]Helpers for values of a given variant among >= 2.
for
type Data a b c d
= Some a b c d
| Nonewith
variantInMultiple valuesTupleNestaccess\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter |> Just
_ ->
Nothingalter\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
let
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3
other ->
otherHelpers for values of a given only variant.
for
type Id attachment
= Id (List Int) attachmentaccess\(Id value0 value1) -> ( value0, value1 )alter\valuesAlter (Id value0 value1) ->
let
( alteredValue0, alteredValue1 ) =
( value0, value1 ) |> valuesAlter
in
Id alteredValue0 alteredValue1Representation of values as one whole, for example
valuesRecord: { value0 = ..., value1 = ..., value2 = ... }valuesTupleNest: ( ..., ( ..., ... ) )Toop.T3 ... ... ...Helpers for a given variant to use with a custom implementation or variantOnly/variantInMultiple.
for
type Data a b c d
= Some a b c d
| NonetypeInOne( a, ( b, ( c, d ) ) )inOne "value"( value0, ( value1, ( value2, value3 ) ) )patternInOne "value"( value0, ( value1, ( value2, value3 ) ) )alterlet
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3Helpers for a given variant to use with a custom implementation or variantOnly/variantInMultiple.
for
type Data a b c d
= Some a b c d
| Noneaccess{ value0 = value0, value1 = value1, value2 = value2, value3 = value3 }alterlet
altered =
{ value0 = value0, value1 = value1, value2 = value2, value3 = value3 }
|> valuesAlter
in
Some altered.value0 altered.value1 altered.value2 altered.value3typeValues{ value0 = a, value1 = b, value2 = c, value3 = d }Pattern on a given variant to use with a custom implementation.
for
type Data a b c d
= Some a b c d
| Nonegenerates
Some value0 value1 value2 value3How to derive helper name ↔ variant name.
Out of the box, there are
You can also create a custom VariantHelperNameConfig:
import Parser
{ build = \{ variantName } -> variantName ++ "Variant"
, parser =
Parser.map (\variantName -> { variantName = variantName })
(Parser.loop ""
(\beforeSuffixFoFar ->
Parser.oneOf
[ Parser.token "Variant"
|. Parser.end
|> Parser.map (\() -> Parser.Done beforeSuffixFoFar)
, Parser.chompIf (\_ -> True)
|> Parser.getChompedString
|> Parser.map
(\stillNotSuffix ->
Parser.Loop (beforeSuffixFoFar ++ stillNotSuffix)
)
]
)
)
}It's not half as daunting as it looks. If you feel motivated 👀 ↓
elm/parser packageMini tip: testing is always a good idea for Parsers
Don't worry about the casing of the results.
They will be automatically be corrected when passed to rule.
In the future,
elm-morph
will allow creating builders and parsers in one go,
making this easier.
Handle helper names in the format prefix<Variant>.
Check out VariantHelperNameConfig for all naming options.
import Parser
import VariantHelper.GenerateUsed
"toSuccess"
|> Parser.run
(VariantHelper.GenerateUsed.variantAfter "to"
|> .parser
)
--> { variantName = "Success" }
{ variantName = "Success" }
|> (VariantHelper.GenerateUsed.variantAfter "map"
|> .build
)
--> "mapSuccess"Handle helper names in the format <variant>.
Check out VariantHelperNameConfig for all naming options.
import Parser
import VariantHelper.GenerateUsed
"success"
|> Parser.run VariantHelper.GenerateUsed.helperNameAsVariant.parser
--> { variantName = "Success" }
{ variantName = "Success" }
|> VariantHelper.GenerateUsed.helperNameAsVariant.build
--> "success"@deprecated in favor of
variantAfter "on"
Handle helper names in the format on<Variant>.
Check out VariantHelperNameConfig for all naming options
Generate each helper for a variant of a
typethat is called from your code but isn't already defined...config.. How to generate, where to generate:
build :aBuildfunction likeaccessorsaccessorsBChiquetname :a way to handle variant helper names likevariantAfter "on"variantgenerationModuleIsVariantModuleDotSuffix :a.Suffixto derive generationmodulenames from variantmodulenamesThere's no configuration to automatically
import Variant.Module.Generation as Variant.Modulebecauseimportaliases can't contain.example
module Variant.Module.On exposing (some)example:
module Variant.Module.X exposing (onSome)Variant helpers will be generated below the
typedeclaration. ConsiderSiriusStarr/elm-review-no-unsortedfor more fine-grained and consistent positioning controluse it
... when you're using
elm-accessorsto mitigate boilerplate related to updating potentially deeply nested data.don't use it
... when you consider accessors the less readable/intuitive/simple/explicit alternative.