Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
dylan-chong opened this issue Dec 27, 2017 · 1 comment
Open

Comments

@dylan-chong
Copy link
Contributor

dylan-chong commented Dec 27, 2017

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
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants