Current section
Files
Jump to
Current section
Files
lib/cucumber_messages/writer.ex
defmodule ExCucumberMessages.Writer do
@moduledoc false
# This is a temporary writer up until Protox supports json encoding
alias CucumberMessages.Envelope
alias CucumberMessages.Location
alias CucumberMessages.Pickle.PickleStep
alias CucumberMessages.GherkinDocument.Feature.FeatureChild
alias CucumberMessages.PickleStepArgument.{PickleDocString, PickleTable}
defp unstruct(%Location{column: 0} = map, acc) do
map |> Map.from_struct() |> Map.delete(:column) |> unstruct(acc)
end
defp unstruct(%{__struct__: _} = map, acc) when is_map(map) do
map |> Map.from_struct() |> unstruct(acc)
end
defp unstruct(%{__uf__: _} = map, acc) when is_map(map) do
map |> Map.delete(:__uf__) |> unstruct(acc)
end
defp unstruct(map, acc) when is_map(map) do
Enum.reduce(map, acc, fn
:ignore, acc ->
acc
{_k, nil}, acc ->
acc
{_k, ""}, acc ->
acc
{_k, :ignore}, acc ->
acc
{_k, []}, acc ->
acc
{_k, {new_key, v}}, acc when is_map(v) or is_list(v) ->
Map.put(acc, lower_camelcase(new_key), unstruct(v, %{}))
{k, v}, acc when is_map(v) or is_list(v) ->
Map.put(acc, lower_camelcase(k), unstruct(v, %{}))
{k, data}, acc ->
Map.put(acc, lower_camelcase(k), unstruct(data, %{}))
end)
end
defp unstruct([], %{}) do
:ignore
end
defp unstruct(list, acc) when is_list(list) do
list
|> Enum.map(fn
%FeatureChild{} = el ->
el.value
%PickleStep{argument: %PickleTable{}} = el ->
Map.put(el, :argument, %{dataTable: el.argument}) |> Map.delete(:__struct__)
%PickleStep{argument: %PickleDocString{}} = el ->
Map.put(el, :argument, %{docString: el.argument}) |> Map.delete(:__struct__)
other_el ->
other_el
end)
|> Enum.reduce(acc, fn
{_new_key, nil}, acc ->
acc
{new_key, value}, acc when is_map(acc) ->
# Map.put(acc, lower_camelcase(new_key), unstruct(value, %{}))
[Map.put(acc, lower_camelcase(new_key), unstruct(value, %{}))]
{new_key, value}, acc when is_list(acc) ->
unstructed = unstruct(value, %{})
case unstructed do
:ignore -> acc
_ -> acc ++ [Map.put(%{}, lower_camelcase(new_key), unstructed)]
end
map, acc when is_map(acc) and acc == %{} ->
unstructed = unstruct(map, %{})
case unstructed do
:ignore -> acc
_ -> [unstruct(map, %{})]
end
map, acc ->
unstructed = unstruct(map, %{})
case unstructed do
:ignore -> acc
_ -> acc ++ [unstruct(map, %{})]
end
end)
end
defp unstruct({k, v}, acc) when not is_tuple(v),
do: Map.put(acc, lower_camelcase(k), unstruct(v, %{}))
defp unstruct(just_data, _acc) when not is_tuple(just_data), do: just_data
def envelope_to_ndjson!(%Envelope{} = message) do
# This is sort of a sanity check to see whether the constructed message is
# proto compliant
# As soon as Protox supports json encoding, this is no longer necessary
message |> Protox.Encode.encode!()
unstruct(message, %{})
end
defp lower_camelcase(atom) when is_atom(atom), do: atom |> Atom.to_string() |> lower_camelcase()
defp lower_camelcase(string) when is_binary(string) do
{to_be_downcased, camelcased} = string |> Macro.camelize() |> String.split_at(1)
String.downcase(to_be_downcased) <> camelcased
end
end