api-surface #1
4 changed files with 27 additions and 4 deletions
fix(struct): address code review feedback
- Formatting: add field/hydrate/discord_struct to locals_without_parens in .formatter.exs so the no-paren data-DSL style is the formatted form; mix format then wrapped the long codec encode_value/2 clause. Both previously-unformatted files now satisfy mix format --check-formatted. - Empty-struct guard: __before_compile__ now raises ArgumentError when a module does 'use Dexcord.Struct' with no field/hydrate declarations, instead of silently generating a bare defstruct []. Added a compile-time test mirroring the existing Code.compile_string validation tests.
commit
a00e455c58
|
|
@ -1,4 +1,5 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
|
||||
locals_without_parens: [field: 2, field: 3, hydrate: 2, discord_struct: 1]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -66,13 +66,22 @@ defmodule Dexcord.Struct do
|
|||
defmacro __before_compile__(env) do
|
||||
module = env.module
|
||||
|
||||
raw_fields = Module.get_attribute(module, :dexcord_fields) || []
|
||||
raw_hydrates = Module.get_attribute(module, :dexcord_hydrates) || []
|
||||
|
||||
if raw_fields == [] and raw_hydrates == [] do
|
||||
raise ArgumentError,
|
||||
"#{inspect(module)}: `use Dexcord.Struct` requires a `discord_struct do ... end` " <>
|
||||
"block declaring at least one `field` or `hydrate`"
|
||||
end
|
||||
|
||||
fields =
|
||||
(Module.get_attribute(module, :dexcord_fields) || [])
|
||||
raw_fields
|
||||
|> Enum.reverse()
|
||||
|> Enum.map(fn {name, type_ast, opts} -> build_field(name, type_ast, opts, env) end)
|
||||
|
||||
hydrates =
|
||||
(Module.get_attribute(module, :dexcord_hydrates) || [])
|
||||
raw_hydrates
|
||||
|> Enum.reverse()
|
||||
|> Enum.map(fn {name, opts} -> build_hydrate(name, opts, env) end)
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,10 @@ defmodule Dexcord.Struct.Codec do
|
|||
# structs delegate straight back here, while hand-written fallback structs
|
||||
# (UnknownChannel, Component.Unknown — no __fields__/0) provide their own.
|
||||
defp encode_value({:struct, _mod}, %_{} = v), do: v.__struct__.to_map(v)
|
||||
defp encode_value({:list, inner}, v) when is_list(v), do: Enum.map(v, &encode_element(inner, &1))
|
||||
|
||||
defp encode_value({:list, inner}, v) when is_list(v),
|
||||
do: Enum.map(v, &encode_element(inner, &1))
|
||||
|
||||
defp encode_value({:enum, mod}, v) when is_atom(v) and not is_nil(v), do: mod.encode(v)
|
||||
defp encode_value({:enum, _mod}, {:unknown, n}) when is_integer(n), do: n
|
||||
# raw passthrough: junk scalars that decode kept raw re-encode raw; a raw
|
||||
|
|
|
|||
|
|
@ -126,6 +126,16 @@ defmodule Dexcord.StructTest do
|
|||
""")
|
||||
end
|
||||
end
|
||||
|
||||
test "use Dexcord.Struct without any field/hydrate raises at compile time" do
|
||||
assert_raise ArgumentError, ~r/requires a `discord_struct`? do/, fn ->
|
||||
Code.compile_string("""
|
||||
defmodule Dexcord.Test.EmptyStruct do
|
||||
use Dexcord.Struct
|
||||
end
|
||||
""")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "from_map decode (Task 5)" do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue