Repository: dashbitco/nimble_options (elixir)

Issue:
Timeout type
`non_neg_integer | :infinity`

thoughts?

Pull request description:
Add the :timeout type
Closes #16. cc @wojtekmach @josevalim 

Patch:
diff --git a/lib/nimble_options.ex b/lib/nimble_options.ex
index 1fca9bb..a7df6de 100644
--- a/lib/nimble_options.ex
+++ b/lib/nimble_options.ex
@@ -84,6 +84,8 @@ defmodule NimbleOptions do
 
     * `:pos_integer` - A positive integer.
 
+    * `:timeout` - A non-negative integer or the atom `:infinity`.
+
     * `:mfa` - A named function in the format `{module, function, arity}`
 
     * `:mod_arg` - A module along with arguments, e.g. `{MyModule, [arg1, arg2]}`.
@@ -164,7 +166,8 @@ defmodule NimbleOptions do
     :mfa,
     :mod_arg,
     :string,
-    :boolean
+    :boolean,
+    :timeout
   ]
 
   @type schema() :: keyword()
@@ -311,6 +314,12 @@ defmodule NimbleOptions do
     {:error, "expected #{inspect(key)} to be an atom, got: #{inspect(value)}"}
   end
 
+  defp validate_type(:timeout, key, value)
+       when not (value == :infinity or (is_integer(value) and value >= 0)) do
+    {:error,
+     "expected #{inspect(key)} to be non-negative integer or :infinity, got: #{inspect(value)}"}
+  end
+
   defp validate_type(:string, key, value) when not is_binary(value) do
     {:error, "expected #{inspect(key)} to be an string, got: #{inspect(value)}"}
   end


Test patch:
diff --git a/test/nimble_options_test.exs b/test/nimble_options_test.exs
index e81e1f3..41b4785 100644
--- a/test/nimble_options_test.exs
+++ b/test/nimble_options_test.exs
@@ -29,7 +29,7 @@ defmodule NimbleOptionsTest do
       Reason: invalid option type :foo.
 
       Available types: :any, :keyword_list, :non_empty_keyword_list, :atom, \
-      :non_neg_integer, :pos_integer, :mfa, :mod_arg, :string, :boolean, \
+      :non_neg_integer, :pos_integer, :mfa, :mod_arg, :string, :boolean, :timeout, \
       {:fun, arity}, {:custom, mod, fun, args}\
       """
 
@@ -217,6 +217,34 @@ defmodule NimbleOptionsTest do
                {:error, "expected :required to be an boolean, got: :an_atom"}
     end
 
+    test "valid timeout" do
+      schema = [timeout: [type: :timeout]]
+
+      opts = [timeout: 0]
+      assert NimbleOptions.validate(opts, schema) == {:ok, opts}
+
+      opts = [timeout: 1000]
+      assert NimbleOptions.validate(opts, schema) == {:ok, opts}
+
+      opts = [timeout: :infinity]
+      assert NimbleOptions.validate(opts, schema) == {:ok, opts}
+    end
+
+    test "invalid timeout" do
+      schema = [timeout: [type: :timeout]]
+
+      opts = [timeout: -1]
+
+      assert NimbleOptions.validate(opts, schema) ==
+               {:error, "expected :timeout to be non-negative integer or :infinity, got: -1"}
+
+      opts = [timeout: :invalid]
+
+      assert NimbleOptions.validate(opts, schema) ==
+               {:error,
+                "expected :timeout to be non-negative integer or :infinity, got: :invalid"}
+    end
+
     test "valid mfa" do
       schema = [transformer: [type: :mfa]]