defmodule MixTaskGen.Options do use Private def from_args(args, option_specs) do option_specs |> normalize_aliases |> get_defaults |> add_options_from(args, option_specs) |> verify_required_options_are_present(option_specs) end private do ##################### # normalize_aliases # ##################### defp normalize_aliases(specs) do for {name, spec} <- specs, into: %{} do if alias_name = spec[:same_as] do { name, specs[alias_name] } else { name, spec } end end end ##################### # get_defaults_from # ##################### defp get_defaults(option_specs) do option_specs |> Enum.reduce(%{}, &maybe_add_default/2) end defp maybe_add_default(spec = {_name, details}, options) do case Keyword.fetch(details, :default) do :error -> options { :ok, value } -> create_option(spec, value, options) end end #################### # add_options_from # #################### defp add_options_from(options, args, option_specs) do args |> Enum.reduce(options, fn arg, options -> option_from(options, arg, option_specs) end) end defp option_from(options, {name, value}, specs) do case Keyword.fetch(specs, name) do :error -> Mix.raise "Unknown option “--#{name}”" { :ok, spec } -> create_option({name, spec}, value, options) end end defp option_from(options, x, specs) do raise inspect [options, x, specs] end ####################################### # verify_required_options_are_present # ####################################### defp verify_required_options_are_present(options, specs) do for { name, details } <- specs, details[:required] do if !options[name] do Mix.raise("required parameter “--#{name}” is missing") end end options end ########### # Utility # ########### defp create_option(spec, value, options) do Map.put(options, name_of(spec), value) end defp name_of({ name, details }) do details[:to] || name end end end