I am working on the MapDiff library, so it works better when structs are passed to it.
I wrote the following two doctests:
iex> defmodule Foo do
...> defstruct a: 1, b: 2, c: 3
...> end
...> MapDiff.diff(%Foo{}, %Foo{a: 3})
%{changed: :map_change, struct_name: Foo,
value: %{a: %{added: 3, changed: :primitive_change, removed: 1},
b: %{changed: :equal, value: 2}, c: %{changed: :equal, value: 3}}}
and:
iex> defmodule Bar do
...> defstruct a: 1, b: 2, c: 3
...> end
...> defmodule Baz do
...> defstruct a: "foo", b: "bar", z: "baz"
...> end
...> MapDiff.diff(%Bar{}, %Baz{})
%{added: %Baz{a: "foo", b: "bar", z: "baz"}, changed: :primitive_change,
removed: %Bar{a: 1, b: 2, c: 3}}
However, this will not compile. When running mix test
, the following error is thrown:
Compiling 1 file (.ex)
** (CompileError) (for doctest at) lib/map_diff.ex:105: MapDiffTest.Foo.__struct__/1 is undefined, cannot expand struct MapDiffTest.Foo
(stdlib) lists.erl:1354: :lists.mapfoldl/3
test/map_diff_test.exs:3: anonymous fn/3 in :elixir_compiler_1.__MODULE__/1
(elixir) lib/enum.ex:1755: Enum."-reduce/3-lists^foldl/2-0-"/3
test/map_diff_test.exs:3: (module)
I think that this is the case because Elixir tries to evaluate the outcome value decoupled from the example, which means that Foo
, Bar
and Baz
(and their respective __struct__/1
implementations) are not in scope.
Now, how can these doctests be rewritten so:
- they compile.
- it is clear to people that
Foo
,Bar
andBaz
are normal structs they could define themselves?