TypedStructLens is a TypedStruct plugin for defining a Lens on each field without writing boilerplate code.
If you define your structs with TypedStruct and use Lens alongside, you may end up defining lenses for your fields:
defmodule Person do
use TypedStruct
import Lens.Macros
typedstruct do
field :name, String.t(), enforce: true
field :age, non_neg_integer()
field :happy?, boolean(), default: true
field :phone, String.t()
end
deflens name, do: Lens.key(:name)
deflens age, do: Lens.key(:age)
deflens happy?, do: Lens.key(:happy?)
deflens phone, do: Lens.key(:phone)
end
But if you are using TypedStruct, it is also highly probable that you do not
like to write boilerplate code. TypedStructLens is here to write the deflens
for you:
defmodule Person do
use TypedStruct
typedstruct do
plugin TypedStructLens
field :name, String.t(), enforce: true
field :age, non_neg_integer()
field :happy?, boolean(), default: true
field :phone, String.t()
end
end
To use this plugin in your project, add this to your Mix dependencies:
{:typed_struct_lens, "~> 0.1.1"}
If you do not plan to compile modules using this TypedStruct plugin at
runtime, you can add runtime: false
to the dependency tuple as it is only
used during compilation.
To use this plugin in a typed struct, simply register it in the typedstruct
block:
defmodule MyStruct do
use TypedStruct
typedstruct do
# Just add this line to your struct.
plugin TypedStructLens
field :a_field, String.t()
field :other_field, atom()
end
@spec change(t()) :: t()
def change(data) do
# a_field/0 is generated by TypedStructLens.
lens = a_field()
put_in(data, [lens], "Changed")
end
end
You can generate private lenses:
defmodule MyStruct do
use TypedStruct
typedstruct do
# Define private lenses instead.
plugin TypedStructLens, lens: :private
field :a_field, String.t()
# You can still make it public for a given field.
field :other_field, atom(), lens: :public
end
end
Conversely, you can make only a given lens private:
defmodule MyStruct do
use TypedStruct
typedstruct do
# By default lenses are public.
plugin TypedStructLens
field :a_field, String.t()
# You can still make it private for a given field.
field :other_field, atom(), lens: :private
end
end
To avoid naming clashes, you can also prefix or postfix the generated function names:
defmodule MyStruct do
use TypedStruct
typedstruct do
# Configure a prefix and postfix.
plugin TypedStructLens, prefix: :demo_, postfix: :_lens
field :a_field, String.t()
field :other_field, atom()
end
@spec change(t()) :: t()
def change(data) do
# demo_a_field_lens/0 is generated by TypedStructLens instead of
# a_field/0.
lens = demo_a_field_lens()
put_in(data, [lens], "Changed")
end
end
Before contributing to this project, please read the CONTRIBUTING.md.
Copyright © 2020, 2022 Jean-Philippe Cugnet
This project is licensed under the MIT license.