NimbleOptions (NimbleOptions v0.3.5) View Source

Provides a standard API to handle keyword-list-based options.

NimbleOptions allows developers to create schemas using a pre-defined set of options and types. The main benefits are:

  • A single unified way to define simple static options
  • Config validation against schemas
  • Automatic doc generation

Schema options

These are the options supported in a schema. They are what defines the validation for the items in the given schema.

  • :type - The type of the option item. The default value is :any.

  • :required - Defines if the option item is required. The default value is false.

  • :default - The default value for option item if not specified.

  • :keys - Available for types :keyword_list and :non_empty_keyword_list, it defines which set of keys are accepted for the option item. The value of the :keys option is a schema itself. For example: keys: [foo: [type: :atom]]. Use :* as the key to allow multiple arbitrary keys and specify their schema: keys: [*: [type: :integer]].

  • :deprecated - Defines a message to indicate that the option item is deprecated. The message will be displayed as a warning when passing the item.

  • :rename_to - Renames a option item allowing one to use a normalized name internally, e.g. rename a deprecated item to the currently accepted name.

  • :doc - The documentation for the option item.

  • :subsection - The title of separate subsection of the options' documentation

Types

  • :any - Any type.

  • :keyword_list - A keyword list.

  • :non_empty_keyword_list - A non-empty keyword list.

  • :atom - An atom.

  • :string - A string.

  • :boolean - A boolean.

  • :integer - An integer.

  • :non_neg_integer - A non-negative integer.

  • :pos_integer - A positive integer.

  • :timeout - A non-negative integer or the atom :infinity.

  • :pid - A PID (process identifier).

  • :mfa - A named function in the format {module, function, arity}

  • :mod_arg - A module along with arguments, e.g. {MyModule, [arg1, arg2]}. Usually used for process initialization using start_link and friends.

  • {:fun, arity} - Any function with the specified arity.

  • {:in, choices} - A value that is a member of one of the choices. choices should be a list of terms. The value is an element in said list of terms, that is, value in choices is true. Previously called :one_of.

  • {:custom, mod, fun, args} - A custom type. The related value must be validated by mod.fun(values, ...args). The function should return {:ok, value} or {:error, message}.

  • {:or, subtypes} - A value that matches one of the given subtypes. The value is matched against the subtypes in the order specified in the list of subtypes. If one of the subtypes matches and updates (casts) the given value, the updated value is used. For example: {:or, [:string, :boolean, {:fun, 2}]}. If one of the subtypes is a keyword list, you won't be able to pass :keys directly. For this reason, keyword lists (:keyword_list and :non_empty_keyword_list) are special cased and can be used as subtypes with {:keyword_list, keys} or {:non_empty_keyword_list, keys}. For example, a type such as {:or, [:boolean, keyword_list: [enabled: [type: :boolean]]]} would match either a boolean or a keyword list with the :enabled boolean option in it.

  • {:list, subtype} - A list where all elements match subtype. subtype can be any of the accepted types listed here. Empty lists are allowed. The resulting validated list contains the validated (and possibly updated) elements, each as returned after validation through subtype. For example, if subtype is a custom validator function that returns an updated value, then that updated value is used in the resulting list. Validation fails at the first element that is invalid according to subtype.

Example

iex> schema = [
...>   producer: [
...>     type: :non_empty_keyword_list,
...>     required: true,
...>     keys: [
...>       module: [required: true, type: :mod_arg],
...>       concurrency: [
...>         type: :pos_integer,
...>       ]
...>     ]
...>   ]
...> ]
...>
...> config = [
...>   producer: [
...>     concurrency: 1,
...>   ]
...> ]
...>
...> {:error, %NimbleOptions.ValidationError{} = error} = NimbleOptions.validate(config, schema)
...> Exception.message(error)
"required option :module not found, received options: [:concurrency] (in options [:producer])"

Nested option items

NimbleOptions allows option items to be nested so you can recursively validate any item down the options tree.

Example

iex> schema = [
...>   producer: [
...>     required: true,
...>     type: :non_empty_keyword_list,
...>     keys: [
...>       rate_limiting: [
...>         type: :non_empty_keyword_list,
...>         keys: [
...>           interval: [required: true, type: :pos_integer]
...>         ]
...>       ]
...>     ]
...>   ]
...> ]
...>
...> config = [
...>   producer: [
...>     rate_limiting: [
...>       interval: :oops!
...>     ]
...>   ]
...> ]
...>
...> {:error, %NimbleOptions.ValidationError{} = error} = NimbleOptions.validate(config, schema)
...> Exception.message(error)
"expected :interval to be a positive integer, got: :oops! (in options [:producer, :rate_limiting])"

Link to this section Summary

Types

A schema. See the module documentation for more information.

Functions

Returns documentation for the given schema.

Validate the given options with the given schema.

Validates the given options with the given schema and raises if they're not valid.

Link to this section Types

Specs

schema() :: keyword()

A schema. See the module documentation for more information.

Link to this section Functions

Link to this function

docs(schema, options \\ [])

View Source

Specs

docs(schema(), keyword()) :: String.t()

Returns documentation for the given schema.

You can use this to inject documentation in your docstrings. For example, say you have your schema in a module attribute:

@options_schema [...]

With this, you can use docs/1 to inject documentation:

@doc "Supported options:\n#{NimbleOptions.docs(@options_schema)}"

Options

  • :nest_level - an integer deciding the "nest level" of the generated docs. This is useful when, for example, you use docs/2 inside the :doc option of another schema. For example, if you have the following nested schema:

    nested_schema = [
      allowed_messages: [type: :pos_integer, doc: "Allowed messages."],
      interval: [type: :pos_integer, doc: "Interval."]
    ]

    then you can document it inside another schema with its nesting level increased:

    schema = [
      producer: [
        type: {:or, [:string, keyword_list: nested_schema]},
        doc:
          "Either a string or a keyword list with the following keys:\n\n" <>
            NimbleOptions.docs(nested_schema, nest_level: 1)
      ],
      other_key: [type: :string]
    ]
Link to this function

validate(options, schema)

View Source

Specs

validate(keyword(), schema()) ::
  {:ok, validated_options :: keyword()}
  | {:error, NimbleOptions.ValidationError.t()}

Validate the given options with the given schema.

See the module documentation for what a schema is.

If the validation is successful, this function returns {:ok, validated_options} where validated_options is a keyword list. If the validation fails, this function returns {:error, validation_error} where validation_error is a NimbleOptions.ValidationError struct explaining what's wrong with the options. You can use raise/1 with that struct or Exception.message/1 to turn it into a string.

Link to this function

validate!(options, schema)

View Source

Specs

validate!(keyword(), schema()) :: validated_options :: keyword()

Validates the given options with the given schema and raises if they're not valid.

This function behaves exactly like validate/2, but returns the options directly if they're valid or raises a NimbleOptions.ValidationError exception otherwise.