Despite what the name suggests,
this package contains multiple elm-review
rules to help with automatic code generation based on use:
When lue-bird/generate-elm
– a framework for making code generation easy and safe –
is finished, every functionality will be ported over.
You find myself writing code like this?
... path newInput =
\state ->
{ state
| projects =
state.projects
|> Scroll.focusMap
(Fillable.map
(\project ->
{ project
| calls =
project.calls
|> List.map
(Tree.elementAlter
( path, Tree.childPrepend newInput )
)
}
)
)
}
Let's define some Field.nameAlter
helpers:
module Field exposing (callsAlter, projectsAlter)
then
import Field
... path newInput =
Field.projectsAlter
(Scroll.focusMap
(Fillable.fillMap
(Field.callsAlter
(List.map
(Tree.elementAlter
( path, Tree.childPrepend newInput )
)
)
)
)
)
We can reduce the number of helpers by combining the possible operations (access, replace, alter, name, ...) into a "lens":
import Field
import Accessors exposing (over)
import Accessors.Library exposing (onEach)
... path newInput =
over Field.projects --← a "lens" for the field .projects
(over Scroll.focus
(over Hand.onFilled
(over Fields.calls --← a "lens" for the field .calls
(over onEach
(over (Tree.elementAt path)
(Tree.childPrepend newInput)
)
)
)
)
)
Seeing a pattern? You can, to put the cherry on the cake, compose those "lenses":
import Field
import Accessors exposing (over)
import Accessors.Library exposing (onEach)
... path newInput =
over
((Field.projects << Scroll.focus << Hand.onFilled)
<< Field.calls
<< onEach
<< Tree.elementAt path
)
(Tree.childPrepend newInput)
Methods like this make your code more readable. Compare with the first example.
→ NoMissingRecordFieldLens
automatically generates record field lenses you use.
No more manual labour.
In the last examples, Field.projects
& Field.calls
will be generated in Field.elm
.
elm-review --template lue-bird/elm-review-missing-record-field-lens/example/field-accessors
module ReviewConfig exposing (config)
import NoMissingRecordFieldLens
import Review.Rule exposing (Rule)
config : List Rule
config =
[ NoMissingRecordFieldLens.rule
{ generator = NoMissingRecordFieldLens.accessors
, generateIn = ( "Field", [] )
}
]
See Config
It's also possible to generate custom lenses or to customize the generation of existing ones.
Don't let this pattern warp you into overusing nesting.
Structuring a model like
{ player : { position : ..., speed : ... }
, scene : { trees : ..., rocks : ... }
}
is a smelly pattern. It makes it unnecessarily hard to update inner fields.
{ playerPosition : ...
, playerSpeed : ...
, sceneTrees : ...
, sceneRocks : ...
}
Doesn't this make ui harder? Yes, but the extra explicitness is worth it.
player
could have things that are irrelevant to the ui like configuredControls
etc.
It's best to keep state structure and ui requirements separate.
Similarly, leaning towards a more limited, domain tailored API of types, packages, ... with strong boundaries
will lead to easier code with stronger guarantees.
↑ example from "Make Data Structures" by Richard Feldman: Doc.id
should be read-only
Don't try to design your API around lenses. Only if the API interaction happens to mirror that behavior, Dōzo!
When parts are logically connected like an Address
or a Camera
.
Make sure to make types, packages, ... out of these.
Don't obsessively employ primitives.
The motivations for using this are similar to NoMissingRecordFieldLens
,
this time trying to cut down on situations where you're only interested in values of one variant.
For any variant type
, you can call YourVariantType.On.oneOfThree
.
If this prism hasn't already been created, it will automatically be generated.
elm-review --template lue-bird/elm-review-missing-record-field-lens/example/variant-accessors
module ReviewConfig exposing (config)
import Review.Rule as Rule exposing (Rule)
import VariantPrism.GenerateUsed
config : List Rule
config =
[ { name = VariantPrism.GenerateUsed.prismNameOnVariant
, build = VariantPrism.GenerateUsed.accessors
}
|> VariantPrism.GenerateUsed.inVariantOriginModuleDotSuffix
"Extra.Local"
|> VariantPrism.GenerateUsed.importGenerationModuleAsOriginModule
|> VariantPrism.GenerateUsed.rule
]
Check out Config
!
It's also possible to generate custom lenses or to customize the generation of existing ones.
→ contributing.