exconstructor icon indicating copy to clipboard operation
exconstructor copied to clipboard

(option to) Use Kernel.struct!/2 to be stricter about making structs

Open dylan-chong opened this issue 8 years ago • 1 comments

Kernel.struct!/2 is stricter (see docs), which will prevent the ignorance of @enforce_keys and prevent invalid struct keys being passed.

If you want some code to do the two checks independently, you could add something like this:


  use ExConstructor, check_enforce_keys: true, check_no_invalid_args: true

  ...

  # pass @enforce_keys as 2nd param
  def check_enforce_keys(args, enforce_keys) do
    arg_keys =
      args
      |> Map.new
      |> Map.keys
      |> MapSet.new
    required_keys = enforce_keys |> MapSet.new

    if not MapSet.subset?(required_keys, arg_keys) do
      raise(
        ArgumentError,
        "Requires keys #{required_keys |> Enum.to_list |> inspect} "
        <> "but only #{arg_keys |> Enum.to_list |> inspect} "
        <> "were given"
      )
    end
  end

  def check_no_invalid_args(args, module) do
    arg_keys =
      args
      |> Map.new
      |> Map.keys
      |> MapSet.new
    valid_keys =
      module
      |> struct([])
      |> Map.from_struct
      |> Map.keys
      |> MapSet.new

    if not MapSet.subset?(arg_keys, valid_keys) do
      raise(
        KeyError,
        "Allowed keys are #{valid_keys |> Enum.to_list |> inspect} "
        <> "but #{arg_keys |> Enum.to_list |> inspect} "
        <> "were given"
      )
    end
  end

dylan-chong avatar Dec 27 '17 05:12 dylan-chong

I would probably prefer the code above over struct!/2, because some external data is bound to have various other bits of data not to be used by the struct - data that hopefully can be harmlessly ignored. struct!/2 would fail with KeyError if passed a map/kwlist of keys not belonging to the struct.

I still would like @enforce_keys to actually do something though. If devs dont want the check to enforce keys they can just not put @enforce_keys in.

dylan-chong avatar Dec 31 '17 09:12 dylan-chong