Replace keyword with concrete keyword lists in specs (#14611)

This commit is contained in:
Łukasz Samson
2025-06-30 17:24:37 +02:00
committed by José Valim
parent a0ca37cb8f
commit db203167e2
69 changed files with 1230 additions and 149 deletions
+14 -5
View File
@@ -118,6 +118,15 @@ defmodule EEx do
| {:expr | :start_expr | :middle_expr | :end_expr, marker, charlist, metadata}
| {:eof, metadata}
@type tokenize_opt ::
{:file, binary()}
| {:line, line}
| {:column, column}
| {:indentation, non_neg_integer}
| {:trim, boolean()}
@type compile_opt :: tokenize_opt | {:engine, module()} | {:parser_options, Code.parser_opts()}
@doc """
Generates a function definition from the given string.
@@ -220,7 +229,7 @@ defmodule EEx do
"3"
"""
@spec compile_string(String.t(), keyword) :: Macro.t()
@spec compile_string(String.t(), [compile_opt]) :: Macro.t()
def compile_string(source, options \\ []) when is_binary(source) and is_list(options) do
case tokenize(source, options) do
{:ok, tokens} ->
@@ -259,7 +268,7 @@ defmodule EEx do
#=> "3"
"""
@spec compile_file(Path.t(), keyword) :: Macro.t()
@spec compile_file(Path.t(), [compile_opt]) :: Macro.t()
def compile_file(filename, options \\ []) when is_list(options) do
filename = IO.chardata_to_string(filename)
options = Keyword.merge([file: filename, line: 1], options)
@@ -277,7 +286,7 @@ defmodule EEx do
"foo baz"
"""
@spec eval_string(String.t(), keyword, keyword) :: String.t()
@spec eval_string(String.t(), keyword, [compile_opt]) :: String.t()
def eval_string(source, bindings \\ [], options \\ [])
when is_binary(source) and is_list(bindings) and is_list(options) do
compiled = compile_string(source, options)
@@ -299,7 +308,7 @@ defmodule EEx do
#=> "foo baz"
"""
@spec eval_file(Path.t(), keyword, keyword) :: String.t()
@spec eval_file(Path.t(), keyword, [compile_opt]) :: String.t()
def eval_file(filename, bindings \\ [], options \\ [])
when is_list(bindings) and is_list(options) do
filename = IO.chardata_to_string(filename)
@@ -339,7 +348,7 @@ defmodule EEx do
Note new tokens may be added in the future.
"""
@doc since: "1.14.0"
@spec tokenize([char()] | String.t(), opts :: keyword) ::
@spec tokenize([char()] | String.t(), [tokenize_opt]) ::
{:ok, [token()]} | {:error, String.t(), metadata()}
def tokenize(contents, opts \\ []) do
EEx.Compiler.tokenize(contents, opts)
+17 -1
View File
@@ -10,6 +10,22 @@ defmodule EEx.Compiler do
@h_spaces [?\s, ?\t]
@all_spaces [?\s, ?\t, ?\n, ?\r]
@typedoc """
Options for EEx compilation functions.
These options control various aspects of EEx template compilation including
file information, parsing behavior, and the template engine to use.
"""
@type compile_opts :: [
file: String.t(),
line: pos_integer(),
column: pos_integer(),
indentation: non_neg_integer(),
trim: boolean(),
parser_options: Code.parser_opts(),
engine: module()
]
@doc """
Tokenize EEx contents.
"""
@@ -290,7 +306,7 @@ defmodule EEx.Compiler do
and the engine together by handling the tokens and invoking
the engine every time a full expression or text is received.
"""
@spec compile([EEx.token()], String.t(), keyword) :: Macro.t()
@spec compile([EEx.token()], String.t(), compile_opts) :: Macro.t()
def compile(tokens, source, opts) do
file = opts[:file] || "nofile"
line = opts[:line] || 1
+18 -1
View File
@@ -14,12 +14,29 @@ defmodule EEx.Engine do
@type state :: term
@typedoc """
Options passed to engine initialization.
These are the same options passed to `EEx.Compiler.compile/3`,
allowing engines to access compilation settings and customize
their behavior accordingly.
"""
@type init_opts :: [
file: String.t(),
line: pos_integer(),
column: pos_integer(),
indentation: non_neg_integer(),
trim: boolean(),
parser_options: Code.parser_opts(),
engine: module()
]
@doc """
Called at the beginning of every template.
It must return the initial state.
"""
@callback init(opts :: keyword) :: state
@callback init(opts :: init_opts) :: state
@doc """
Called at the end of every template.
+17 -1
View File
@@ -162,6 +162,22 @@ defmodule Calendar do
"""
@type time_zone_database :: module()
@typedoc """
Options for formatting dates and times with `strftime/3`.
"""
@type strftime_opts :: [
preferred_datetime: String.t(),
preferred_date: String.t(),
preferred_time: String.t(),
am_pm_names: (:am | :pm -> String.t()) | (:am | :pm, map() -> String.t()),
month_names: (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),
abbreviated_month_names:
(pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),
day_of_week_names: (pos_integer() -> String.t()) | (pos_integer(), map() -> String.t()),
abbreviated_day_of_week_names:
(pos_integer() -> String.t()) | (pos_integer(), map() -> String.t())
]
@doc """
Returns how many days there are in the given month of the given year.
"""
@@ -617,7 +633,7 @@ defmodule Calendar do
"""
@doc since: "1.11.0"
@spec strftime(map(), String.t(), keyword()) :: String.t()
@spec strftime(map(), String.t(), strftime_opts()) :: String.t()
def strftime(date_or_time_or_datetime, string_format, user_options \\ [])
when is_map(date_or_time_or_datetime) and is_binary(string_format) do
parse(
+17
View File
@@ -161,6 +161,22 @@ defmodule Duration do
"""
@type duration :: t | [unit_pair]
@typedoc """
Options for `Duration.to_string/2`.
"""
@type to_string_opts :: [
units: [
year: String.t(),
month: String.t(),
week: String.t(),
day: String.t(),
hour: String.t(),
minute: String.t(),
second: String.t()
],
separator: String.t()
]
@microseconds_per_second 1_000_000
@doc """
@@ -436,6 +452,7 @@ defmodule Duration do
"""
@doc since: "1.18.0"
@spec to_string(t, to_string_opts) :: String.t()
def to_string(%Duration{} = duration, opts \\ []) do
units = Keyword.get(opts, :units, [])
separator = Keyword.get(opts, :separator, " ")
+72 -25
View File
@@ -248,6 +248,49 @@ defmodule Code do
"""
@type position() :: line() | {line :: pos_integer(), column :: pos_integer()}
@typedoc """
Options for code formatting functions.
"""
@type format_opts :: [
file: binary(),
line: pos_integer(),
line_length: pos_integer(),
locals_without_parens: keyword(),
force_do_end_blocks: boolean(),
migrate: boolean(),
migrate_bitstring_modifiers: boolean(),
migrate_call_parens_on_pipe: boolean(),
migrate_charlists_as_sigils: boolean(),
migrate_unless: boolean()
]
@typedoc """
Options for parsing functions that convert strings to quoted expressions.
"""
@type parser_opts :: [
file: binary(),
line: pos_integer(),
column: pos_integer(),
indentation: non_neg_integer(),
columns: boolean(),
unescape: boolean(),
existing_atoms_only: boolean(),
token_metadata: boolean(),
literal_encoder: (term(), Macro.metadata() -> term()),
static_atoms_encoder: (atom() -> term()),
emit_warnings: boolean()
]
@typedoc """
Options for environment evaluation functions like eval_string/3 and eval_quoted/3.
"""
@type env_eval_opts :: [
file: binary(),
line: pos_integer(),
module: module(),
prune_binding: boolean()
]
@boolean_compiler_options [
:docs,
:debug_info,
@@ -560,7 +603,7 @@ defmodule Code do
[a: 1, b: 2]
"""
@spec eval_string(List.Chars.t(), binding, Macro.Env.t() | keyword) :: {term, binding}
@spec eval_string(List.Chars.t(), binding, Macro.Env.t() | env_eval_opts) :: {term, binding}
def eval_string(string, binding \\ [], opts \\ [])
def eval_string(string, binding, %Macro.Env{} = env) do
@@ -615,7 +658,8 @@ defmodule Code do
"""
@doc since: "1.15.0"
@spec with_diagnostics(keyword(), (-> result)) :: {result, [diagnostic(:warning | :error)]}
@spec with_diagnostics([log: boolean()], (-> result)) ::
{result, [diagnostic(:warning | :error)]}
when result: term()
def with_diagnostics(opts \\ [], fun) do
value = :erlang.get(:elixir_code_diagnostics)
@@ -648,7 +692,7 @@ defmodule Code do
Defaults to `true`.
"""
@doc since: "1.15.0"
@spec print_diagnostic(diagnostic(:warning | :error), keyword()) :: :ok
@spec print_diagnostic(diagnostic(:warning | :error), snippet: boolean()) :: :ok
def print_diagnostic(diagnostic, opts \\ []) do
read_snippet? = Keyword.get(opts, :snippet, true)
:elixir_errors.print_diagnostic(diagnostic, read_snippet?)
@@ -1035,7 +1079,7 @@ defmodule Code do
address the deprecation warnings.
"""
@doc since: "1.6.0"
@spec format_string!(binary, keyword) :: iodata
@spec format_string!(binary, format_opts) :: iodata
def format_string!(string, opts \\ []) when is_binary(string) and is_list(opts) do
line_length = Keyword.get(opts, :line_length, 98)
@@ -1060,7 +1104,7 @@ defmodule Code do
available options.
"""
@doc since: "1.6.0"
@spec format_file!(binary, keyword) :: iodata
@spec format_file!(binary, format_opts) :: iodata
def format_file!(file, opts \\ []) when is_binary(file) and is_list(opts) do
string = File.read!(file)
formatted = format_string!(string, [file: file, line: 1] ++ opts)
@@ -1098,7 +1142,7 @@ defmodule Code do
[a: 1, b: 2]
"""
@spec eval_quoted(Macro.t(), binding, Macro.Env.t() | keyword) :: {term, binding}
@spec eval_quoted(Macro.t(), binding, Macro.Env.t() | env_eval_opts) :: {term, binding}
def eval_quoted(quoted, binding \\ [], env_or_opts \\ []) do
{value, binding, _env} =
eval_verify(:eval_quoted, [quoted, binding, env_for_eval(env_or_opts)])
@@ -1129,8 +1173,15 @@ defmodule Code do
* `:line` - the line on which the script starts
* `:module` - the module to run the environment on
* `:prune_binding` - (since v1.14.2) prune binding to keep only
variables read or written by the evaluated code. Note that
variables used by modules are always pruned, even if later used
by the modules. You can submit to the `:on_module` tracer event
and access the variables used by the module from its environment.
"""
@doc since: "1.14.0"
@spec env_for_eval(Macro.Env.t() | env_eval_opts) :: Macro.Env.t()
def env_for_eval(env_or_opts), do: :elixir.env_for_eval(env_or_opts)
@doc """
@@ -1144,15 +1195,11 @@ defmodule Code do
## Options
* `:prune_binding` - (since v1.14.2) prune binding to keep only
variables read or written by the evaluated code. Note that
variables used by modules are always pruned, even if later used
by the modules. You can submit to the `:on_module` tracer event
and access the variables used by the module from its environment.
It accepts the same options as `env_for_eval/1`.
"""
@doc since: "1.14.0"
@spec eval_quoted_with_env(Macro.t(), binding, Macro.Env.t(), keyword) ::
@spec eval_quoted_with_env(Macro.t(), binding, Macro.Env.t(), env_eval_opts) ::
{term, binding, Macro.Env.t()}
def eval_quoted_with_env(quoted, binding, %Macro.Env{} = env, opts \\ [])
when is_list(binding) do
@@ -1263,7 +1310,7 @@ defmodule Code do
{:error, {[line: 1, column: 4], "syntax error before: ", "\"3\""}}
"""
@spec string_to_quoted(List.Chars.t(), keyword) ::
@spec string_to_quoted(List.Chars.t(), parser_opts) ::
{:ok, Macro.t()} | {:error, {location :: keyword, binary | {binary, binary}, binary}}
def string_to_quoted(string, opts \\ []) when is_list(opts) do
file = Keyword.get(opts, :file, "nofile")
@@ -1290,7 +1337,7 @@ defmodule Code do
Check `string_to_quoted/2` for options information.
"""
@spec string_to_quoted!(List.Chars.t(), keyword) :: Macro.t()
@spec string_to_quoted!(List.Chars.t(), parser_opts) :: Macro.t()
def string_to_quoted!(string, opts \\ []) when is_list(opts) do
file = Keyword.get(opts, :file, "nofile")
line = Keyword.get(opts, :line, 1)
@@ -1341,7 +1388,7 @@ defmodule Code do
"""
@doc since: "1.13.0"
@spec string_to_quoted_with_comments(List.Chars.t(), keyword) ::
@spec string_to_quoted_with_comments(List.Chars.t(), parser_opts) ::
{:ok, Macro.t(), list(map())} | {:error, {location :: keyword, term, term}}
def string_to_quoted_with_comments(string, opts \\ []) when is_list(opts) do
charlist = to_charlist(string)
@@ -1371,7 +1418,7 @@ defmodule Code do
Check `string_to_quoted/2` for options information.
"""
@doc since: "1.13.0"
@spec string_to_quoted_with_comments!(List.Chars.t(), keyword) :: {Macro.t(), list(map())}
@spec string_to_quoted_with_comments!(List.Chars.t(), parser_opts) :: {Macro.t(), list(map())}
def string_to_quoted_with_comments!(string, opts \\ []) do
charlist = to_charlist(string)
@@ -1456,6 +1503,9 @@ defmodule Code do
## Options
This function accepts all options supported by `format_string!/2` for controlling
code formatting, plus these additional options:
* `:comments` - the list of comments associated with the quoted expression.
Defaults to `[]`. It is recommended that both `:token_metadata` and
`:literal_encoder` options are given to `string_to_quoted_with_comments/2`
@@ -1466,17 +1516,14 @@ defmodule Code do
`string_to_quoted/2`, setting this option to `false` will prevent it from
escaping the sequences twice. Defaults to `true`.
* `:locals_without_parens` - a keyword list of name and arity
pairs that should be kept without parens whenever possible.
The arity may be the atom `:*`, which implies all arities of
that name. The formatter already includes a list of functions
and this option augments this list.
* `:syntax_colors` - a keyword list of colors the output is colorized.
See `Inspect.Opts` for more information.
See `format_string!/2` for the full list of formatting options including
`:file`, `:line`, `:line_length`, `:locals_without_parens`, `:force_do_end_blocks`,
`:syntax_colors`, and all migration options like `:migrate_charlists_as_sigils`.
"""
@doc since: "1.13.0"
@spec quoted_to_algebra(Macro.t(), keyword) :: Inspect.Algebra.t()
@spec quoted_to_algebra(Macro.t(), [
Code.Formatter.to_algebra_opt() | Code.Normalizer.normalize_opt()
]) :: Inspect.Algebra.t()
def quoted_to_algebra(quoted, opts \\ []) do
quoted
|> Code.Normalizer.normalize(opts)
+23
View File
@@ -155,9 +155,32 @@ defmodule Code.Formatter do
@do_end_keywords [:rescue, :catch, :else, :after]
@typedoc """
Options for `to_algebra/2`.
These options include all the standard code formatting options plus
additional context like comments and syntax highlighting colors.
"""
@type to_algebra_opt ::
{:comments, [term()]}
| {:syntax_colors, keyword()}
| {:sigils, keyword()}
| {:file, binary()}
| {:line, pos_integer()}
| {:line_length, pos_integer()}
| {:locals_without_parens, keyword()}
| {:force_do_end_blocks, boolean()}
| {:migrate, boolean()}
| {:migrate_bitstring_modifiers, boolean()}
| {:migrate_call_parens_on_pipe, boolean()}
| {:migrate_charlists_as_sigils, boolean()}
| {:migrate_unless, boolean()}
| {atom(), term()}
@doc """
Converts the quoted expression into an algebra document.
"""
@spec to_algebra(Macro.t(), [to_algebra_opt]) :: Inspect.Algebra.t()
def to_algebra(quoted, opts \\ []) do
comments = Keyword.get(opts, :comments, [])
+23 -3
View File
@@ -11,6 +11,26 @@ defmodule Code.Fragment do
@type position :: {line :: pos_integer(), column :: pos_integer()}
@typedoc """
Options for cursor context functions.
Currently, these options are not used but reserved for future extensibility.
"""
@type cursor_opts :: []
@typedoc """
Options for converting code fragments to quoted expressions.
"""
@type container_cursor_to_quoted_opts :: [
file: String.t(),
line: pos_integer(),
column: pos_integer(),
columns: boolean(),
token_metadata: boolean(),
literal_encoder: (term(), Macro.metadata() -> term()),
trailing_fragment: String.t()
]
@doc ~S"""
Returns the list of lines in the given string, preserving their line endings.
@@ -172,7 +192,7 @@ defmodule Code.Fragment do
references, and more.
"""
@doc since: "1.13.0"
@spec cursor_context(List.Chars.t(), keyword()) ::
@spec cursor_context(List.Chars.t(), cursor_opts()) ::
{:alias, charlist}
| {:alias, inside_alias, charlist}
| {:block_keyword_or_binary_operator, charlist}
@@ -662,7 +682,7 @@ defmodule Code.Fragment do
of examples and their return values.
"""
@doc since: "1.13.0"
@spec surround_context(List.Chars.t(), position(), keyword()) ::
@spec surround_context(List.Chars.t(), position(), cursor_opts()) ::
%{begin: position, end: position, context: context} | :none
when context:
{:alias, charlist}
@@ -1215,7 +1235,7 @@ defmodule Code.Fragment do
"""
@doc since: "1.13.0"
@spec container_cursor_to_quoted(List.Chars.t(), keyword()) ::
@spec container_cursor_to_quoted(List.Chars.t(), container_cursor_to_quoted_opts()) ::
{:ok, Macro.t()} | {:error, {location :: keyword, binary | {binary, binary}, binary}}
def container_cursor_to_quoted(fragment, opts \\ []) do
{trailing_fragment, opts} = Keyword.pop(opts, :trailing_fragment)
+10
View File
@@ -10,10 +10,20 @@ defmodule Code.Normalizer do
is_binary(x) or
is_atom(x)
@typedoc """
Options for `normalize/2`.
"""
@type normalize_opt ::
{:line, pos_integer() | nil}
| {:escape, boolean()}
| {:locals_without_parens, keyword()}
| {atom(), term()}
@doc """
Wraps literals in the quoted expression to conform to the AST format expected
by the formatter.
"""
@spec normalize(Macro.t(), [normalize_opt]) :: Macro.t()
def normalize(quoted, opts \\ []) do
line = Keyword.get(opts, :line, nil)
escape = Keyword.get(opts, :escape, true)
+7 -1
View File
@@ -98,6 +98,12 @@ defmodule Config do
(assembled with `mix release`).
"""
@type config_opts :: [
imports: [Path.t()] | :disabled,
env: atom(),
target: atom()
]
@opts_key {__MODULE__, :opts}
@config_key {__MODULE__, :config}
@imports_key {__MODULE__, :imports}
@@ -306,7 +312,7 @@ defmodule Config do
end
@doc false
@spec __eval__!(Path.t(), binary(), keyword) :: {keyword, [Path.t()] | :disabled}
@spec __eval__!(Path.t(), binary(), config_opts) :: {keyword, [Path.t()] | :disabled}
def __eval__!(file, content, opts \\ []) when is_binary(file) and is_list(opts) do
env = Keyword.get(opts, :env)
target = Keyword.get(opts, :target)
+11
View File
@@ -111,6 +111,16 @@ defmodule Config.Provider do
"""
@type config_path :: {:system, binary(), binary()} | binary()
@typedoc """
Options for `init/3`.
"""
@type init_opts :: [
extra_config: config(),
prune_runtime_sys_config_after_boot: boolean(),
reboot_system_after_config: boolean(),
validate_compile_env: [{atom(), [atom()], term()}]
]
@doc """
Invoked when initializing a config provider.
@@ -196,6 +206,7 @@ defmodule Config.Provider do
@reboot_mode_key :config_provider_reboot_mode
@doc false
@spec init([{module(), term()}], config_path(), init_opts()) :: config()
def init(providers, config_path, opts \\ []) when is_list(providers) and is_list(opts) do
validate_config_path!(config_path)
providers = for {provider, init} <- providers, do: {provider, provider.init(init)}
+9 -3
View File
@@ -46,6 +46,12 @@ defmodule Config.Reader do
@behaviour Config.Provider
@type config_opts :: [
imports: [Path.t()] | :disabled,
env: atom(),
target: atom()
]
@impl true
def init(opts) when is_list(opts) do
{path, opts} = Keyword.pop!(opts, :path)
@@ -68,7 +74,7 @@ defmodule Config.Reader do
Accepts the same options as `read!/2`.
"""
@doc since: "1.11.0"
@spec eval!(Path.t(), binary, keyword) :: keyword
@spec eval!(Path.t(), binary, config_opts) :: keyword
def eval!(file, contents, opts \\ [])
when is_binary(file) and is_binary(contents) and is_list(opts) do
Config.__eval__!(Path.expand(file), contents, opts) |> elem(0)
@@ -90,7 +96,7 @@ defmodule Config.Reader do
"""
@doc since: "1.9.0"
@spec read!(Path.t(), keyword) :: keyword
@spec read!(Path.t(), config_opts) :: keyword
def read!(file, opts \\ []) when is_binary(file) and is_list(opts) do
file = Path.expand(file)
Config.__eval__!(file, File.read!(file), opts) |> elem(0)
@@ -104,7 +110,7 @@ defmodule Config.Reader do
option cannot be disabled in `read_imports!/2`.
"""
@doc since: "1.9.0"
@spec read_imports!(Path.t(), keyword) :: {keyword, [Path.t()]}
@spec read_imports!(Path.t(), config_opts) :: {keyword, [Path.t()]}
def read_imports!(file, opts \\ []) when is_binary(file) and is_list(opts) do
if opts[:imports] == :disabled do
raise ArgumentError, ":imports must be a list of paths"
+35 -3
View File
@@ -115,11 +115,28 @@ defmodule Inspect.Opts do
width: non_neg_integer | :infinity
}
@typedoc """
Options for building an `Inspect.Opts` struct with `new/1`.
"""
@type new_opt ::
{:base, :decimal | :binary | :hex | :octal}
| {:binaries, :infer | :as_binaries | :as_strings}
| {:charlists, :infer | :as_lists | :as_charlists}
| {:custom_options, keyword}
| {:inspect_fun, (any, t -> Inspect.Algebra.t())}
| {:limit, non_neg_integer | :infinity}
| {:pretty, boolean}
| {:printable_limit, non_neg_integer | :infinity}
| {:safe, boolean}
| {:structs, boolean}
| {:syntax_colors, [{color_key, IO.ANSI.ansidata()}]}
| {:width, non_neg_integer | :infinity}
@doc """
Builds an `Inspect.Opts` struct.
"""
@doc since: "1.13.0"
@spec new(keyword()) :: t
@spec new([new_opt()]) :: t
def new(opts) do
struct(%Inspect.Opts{inspect_fun: default_inspect_fun()}, opts)
end
@@ -324,6 +341,14 @@ defmodule Inspect.Algebra do
quote do: {:doc_color, unquote(doc), unquote(color)}
end
@typedoc """
Options for container documents.
"""
@type container_opts :: [
separator: String.t(),
break: :strict | :flex | :maybe
]
@docs [
:doc_break,
:doc_collapse,
@@ -440,7 +465,14 @@ defmodule Inspect.Algebra do
updated options from inspection.
"""
@doc since: "1.6.0"
@spec container_doc(t, [term], t, Inspect.Opts.t(), (term, Inspect.Opts.t() -> t), keyword()) ::
@spec container_doc(
t,
[term],
t,
Inspect.Opts.t(),
(term, Inspect.Opts.t() -> t),
container_opts()
) ::
t
def container_doc(left, collection, right, inspect_opts, fun, opts \\ []) do
container_doc_with_opts(left, collection, right, inspect_opts, fun, opts) |> elem(0)
@@ -496,7 +528,7 @@ defmodule Inspect.Algebra do
t,
Inspect.Opts.t(),
(term, Inspect.Opts.t() -> t),
keyword()
container_opts()
) ::
{t, Inspect.Opts.t()}
def container_doc_with_opts(left, collection, right, inspect_opts, fun, opts \\ [])
+22 -3
View File
@@ -128,6 +128,22 @@ defmodule IO do
@type nodata :: {:error, term} | :eof
@type chardata :: String.t() | maybe_improper_list(char | chardata, String.t() | [])
@type inspect_opts :: [Inspect.Opts.new_opt() | {:label, term}]
@typedoc """
Stacktrace information as keyword options for `warn/2`.
At least `:file` is required. Other options are optional and used
to provide more precise location information.
"""
@type warn_stacktrace_opts :: [
file: String.t(),
line: pos_integer(),
column: pos_integer(),
module: module(),
function: {atom(), arity()}
]
defguardp is_device(term) when is_atom(term) or is_pid(term)
defguardp is_iodata(data) when is_list(data) or is_binary(data)
@@ -346,7 +362,10 @@ defmodule IO do
#=> my_app.ex:4: MyApp.main/1
"""
@spec warn(chardata | String.Chars.t(), Exception.stacktrace() | keyword() | Macro.Env.t()) ::
@spec warn(
chardata | String.Chars.t(),
Exception.stacktrace() | warn_stacktrace_opts() | Macro.Env.t()
) ::
:ok
def warn(message, stacktrace_info)
@@ -476,7 +495,7 @@ defmodule IO do
after: [2, 4, 6]
"""
@spec inspect(item, keyword) :: item when item: var
@spec inspect(item, inspect_opts) :: item when item: var
def inspect(item, opts \\ []) do
inspect(:stdio, item, opts)
end
@@ -486,7 +505,7 @@ defmodule IO do
See `inspect/2` for a full list of options.
"""
@spec inspect(device, item, keyword) :: item when item: var
@spec inspect(device, item, inspect_opts) :: item when item: var
def inspect(device, item, opts) when is_device(device) and is_list(opts) do
label = if label = opts[:label], do: [to_chardata(label), ": "], else: []
opts = Inspect.Opts.new(opts)
+17 -3
View File
@@ -5,6 +5,20 @@
defmodule IO.ANSI.Docs do
@moduledoc false
@type print_opts :: [
enabled: boolean(),
doc_bold: [IO.ANSI.ansicode()],
doc_code: [IO.ANSI.ansicode()],
doc_headings: [IO.ANSI.ansicode()],
doc_metadata: [IO.ANSI.ansicode()],
doc_quote: [IO.ANSI.ansicode()],
doc_inline_code: [IO.ANSI.ansicode()],
doc_table_heading: [IO.ANSI.ansicode()],
doc_title: [IO.ANSI.ansicode()],
doc_underline: [IO.ANSI.ansicode()],
width: pos_integer()
]
@bullet_text_unicode "• "
@bullet_text_ascii "* "
@bullets [?*, ?-, ?+]
@@ -52,7 +66,7 @@ defmodule IO.ANSI.Docs do
See `default_options/0` for docs on the supported options.
"""
@spec print_headings([String.t()], keyword) :: :ok
@spec print_headings([String.t()], print_opts) :: :ok
def print_headings(headings, options \\ []) do
# It's possible for some of the headings to contain newline characters (`\n`), so in order to prevent it from
# breaking the output from `print_headings/2`, as `print_headings/2` tries to pad the whole heading, we first split
@@ -77,7 +91,7 @@ defmodule IO.ANSI.Docs do
See `default_options/0` for docs on the supported options.
"""
@spec print_metadata(map, keyword) :: :ok
@spec print_metadata(map, print_opts) :: :ok
def print_metadata(metadata, options \\ []) when is_map(metadata) do
options = Keyword.merge(default_options(), options)
print_each_metadata(metadata, options) && IO.write("\n")
@@ -115,7 +129,7 @@ defmodule IO.ANSI.Docs do
It takes a set of `options` defined in `default_options/0`.
"""
@spec print(term(), String.t(), keyword) :: :ok
@spec print(term(), String.t(), print_opts) :: :ok
def print(doc, format, options \\ [])
def print(doc, "text/markdown", options) when is_binary(doc) and is_list(options) do
+17 -1
View File
@@ -328,6 +328,22 @@ defmodule JSON do
| {:invalid_byte, non_neg_integer(), byte()}
| {:unexpected_sequence, non_neg_integer(), binary()}
@typedoc """
Decoders for customizing JSON decoding behavior.
"""
@type decoders :: [
array_start: (term() -> term()),
array_push: (term(), term() -> term()),
array_finish: (term(), term() -> {term(), term()}),
object_start: (term() -> term()),
object_push: (term(), term(), term() -> term()),
object_finish: (term(), term() -> {term(), term()}),
float: (String.t() -> term()),
integer: (String.t() -> term()),
string: (String.t() -> term()),
null: term()
]
@doc ~S"""
Decodes the given JSON.
@@ -381,7 +397,7 @@ defmodule JSON do
For streaming decoding, see Erlang's [`:json`](`:json`) module.
"""
@spec decode(binary(), term(), keyword()) ::
@spec decode(binary(), term(), decoders()) ::
{term(), term(), binary()} | {:error, decode_error_reason()}
def decode(binary, acc, decoders) when is_binary(binary) and is_list(decoders) do
decoders = Keyword.put_new(decoders, :null, nil)
+1 -1
View File
@@ -2456,7 +2456,7 @@ defmodule Kernel do
See the "Deriving" section of the documentation of the `Inspect`
protocol for more information.
"""
@spec inspect(Inspect.t(), keyword) :: String.t()
@spec inspect(Inspect.t(), [Inspect.Opts.new_opt()]) :: String.t()
def inspect(term, opts \\ []) when is_list(opts) do
opts = Inspect.Opts.new(opts)
+38 -3
View File
@@ -16,6 +16,38 @@ defmodule Kernel.ParallelCompiler do
@type warning() :: {file :: Path.t(), Code.position(), message :: String.t()}
@type error() :: {file :: Path.t(), Code.position(), message :: String.t()}
@typedoc """
Options for parallel compilation functions.
"""
@type compile_opts :: [
after_compile: (-> term()),
each_file: (Path.t() -> term()),
each_long_compilation: (Path.t() -> term()) | (Path.t(), pid() -> term()),
each_long_verification: (module() -> term()) | (module(), pid() -> term()),
each_module: (Path.t(), module(), binary() -> term()),
each_cycle: ([module()], [Code.diagnostic(:warning)] ->
{:compile, [module()], [Code.diagnostic(:warning)]}
| {:runtime, [module()], [Code.diagnostic(:warning)]}),
long_compilation_threshold: pos_integer(),
long_verification_threshold: pos_integer(),
verification: boolean(),
profile: :time,
dest: Path.t(),
beam_timestamp: term(),
return_diagnostics: boolean(),
max_concurrency: pos_integer()
]
@typedoc """
Options for requiring files in parallel.
"""
@type require_opts :: [
each_file: (Path.t() -> term()),
each_module: (Path.t(), module(), binary() -> term()),
max_concurrency: pos_integer(),
return_diagnostics: boolean()
]
@doc """
Starts a task for parallel compilation.
"""
@@ -185,7 +217,7 @@ defmodule Kernel.ParallelCompiler do
"""
@doc since: "1.6.0"
@spec compile([Path.t()], keyword()) ::
@spec compile([Path.t()], compile_opts()) ::
{:ok, [atom], [warning] | info()}
| {:error, [error] | [Code.diagnostic(:error)], [warning] | info()}
def compile(files, options \\ []) when is_list(options) do
@@ -198,7 +230,7 @@ defmodule Kernel.ParallelCompiler do
See `compile/2` for more information.
"""
@doc since: "1.6.0"
@spec compile_to_path([Path.t()], Path.t(), keyword()) ::
@spec compile_to_path([Path.t()], Path.t(), compile_opts()) ::
{:ok, [atom], [warning] | info()}
| {:error, [error] | [Code.diagnostic(:error)], [warning] | info()}
def compile_to_path(files, path, options \\ []) when is_binary(path) and is_list(options) do
@@ -233,9 +265,12 @@ defmodule Kernel.ParallelCompiler do
Setting this option to 1 will compile files sequentially.
Defaults to the number of schedulers online, or at least 2.
* `:return_diagnostics` - when `true`, returns structured diagnostics
as maps instead of the legacy format. Defaults to `false`.
"""
@doc since: "1.6.0"
@spec require([Path.t()], keyword()) ::
@spec require([Path.t()], require_opts()) ::
{:ok, [atom], [warning] | info()}
| {:error, [error] | [Code.diagnostic(:error)], [warning] | info()}
def require(files, options \\ []) when is_list(options) do
+11 -2
View File
@@ -197,6 +197,15 @@ defmodule Macro do
@typedoc "A captured remote function in the format of &Mod.fun/arity"
@type captured_remote_function :: fun
@type escape_opts :: [
unquote: boolean(),
prune_metadata: boolean()
]
@type inspect_atom_opts :: [
escape: (binary(), char() -> binary())
]
@doc """
Breaks a pipeline expression into a list.
@@ -835,7 +844,7 @@ defmodule Macro do
bound), while `quote/2` produces syntax trees for
expressions.
"""
@spec escape(term, keyword) :: t()
@spec escape(term, escape_opts) :: t()
def escape(expr, opts \\ []) do
unquote = Keyword.get(opts, :unquote, false)
kind = if Keyword.get(opts, :prune_metadata, false), do: :prune_metadata, else: :none
@@ -2399,7 +2408,7 @@ defmodule Macro do
"""
@doc since: "1.14.0"
@spec inspect_atom(:literal | :key | :remote_call, atom, keyword) :: binary
@spec inspect_atom(:literal | :key | :remote_call, atom, inspect_atom_opts) :: binary
def inspect_atom(source_format, atom, opts \\ [])
def inspect_atom(:literal, atom, _opts) when is_nil(atom) or is_boolean(atom) do
+44 -6
View File
@@ -70,6 +70,42 @@ defmodule Macro.Env do
@typep tracers :: [module]
@typep versioned_vars :: %{optional(variable) => var_version :: non_neg_integer}
@type define_import_opts :: [
trace: boolean(),
emit_warnings: boolean(),
info_callback: (atom() -> [{atom(), arity()}]),
only: :functions | :macros | [{atom(), arity()}],
except: [{atom(), arity()}],
warn: boolean()
]
@type define_alias_opts :: [
trace: boolean(),
as: atom(),
warn: boolean()
]
@type define_require_opts :: [
trace: boolean(),
as: atom(),
warn: boolean()
]
@type expand_alias_opts :: [
trace: boolean()
]
@type expand_import_opts :: [
allow_locals: boolean(),
check_deprecations: boolean(),
trace: boolean()
]
@type expand_require_opts :: [
check_deprecations: boolean(),
trace: boolean()
]
@type t :: %{
__struct__: __MODULE__,
aliases: aliases,
@@ -331,7 +367,7 @@ defmodule Macro.Env do
"""
@doc since: "1.17.0"
@spec define_require(t, Macro.metadata(), module) :: {:ok, t}
@spec define_require(t, Macro.metadata(), module, define_require_opts) :: {:ok, t}
def define_require(env, meta, module, opts \\ [])
when is_list(meta) and is_atom(module) and is_list(opts) do
{trace, opts} = Keyword.pop(opts, :trace, true)
@@ -391,7 +427,8 @@ defmodule Macro.Env do
"""
@doc since: "1.17.0"
@spec define_import(t, Macro.metadata(), module, keyword) :: {:ok, t} | {:error, String.t()}
@spec define_import(t, Macro.metadata(), module, define_import_opts) ::
{:ok, t} | {:error, String.t()}
def define_import(env, meta, module, opts \\ [])
when is_list(meta) and is_atom(module) and is_list(opts) do
{trace, opts} = Keyword.pop(opts, :trace, true)
@@ -441,7 +478,8 @@ defmodule Macro.Env do
"""
@doc since: "1.17.0"
@spec define_alias(t, Macro.metadata(), module, keyword) :: {:ok, t} | {:error, String.t()}
@spec define_alias(t, Macro.metadata(), module, define_alias_opts) ::
{:ok, t} | {:error, String.t()}
def define_alias(env, meta, module, opts \\ [])
when is_list(meta) and is_atom(module) and is_list(opts) do
{trace, opts} = Keyword.pop(opts, :trace, true)
@@ -487,7 +525,7 @@ defmodule Macro.Env do
"""
@doc since: "1.17.0"
@spec expand_alias(t, keyword, [atom()], keyword) ::
@spec expand_alias(t, keyword, [atom()], expand_alias_opts) ::
{:alias, atom()} | :error
def expand_alias(env, meta, list, opts \\ [])
when is_list(meta) and is_list(list) and is_list(opts) do
@@ -527,7 +565,7 @@ defmodule Macro.Env do
"""
@doc since: "1.17.0"
@spec expand_import(t, keyword, atom(), arity(), keyword) ::
@spec expand_import(t, keyword, atom(), arity(), expand_import_opts) ::
{:macro, module(), (Macro.metadata(), args :: [Macro.t()] -> Macro.t())}
| {:function, module(), atom()}
| {:error, :not_found | {:conflict, module()} | {:ambiguous, [module()]}}
@@ -583,7 +621,7 @@ defmodule Macro.Env do
"""
@doc since: "1.17.0"
@spec expand_require(t, keyword, module(), atom(), arity(), keyword) ::
@spec expand_require(t, keyword, module(), atom(), arity(), expand_require_opts) ::
{:macro, module(), (Macro.metadata(), args :: [Macro.t()] -> Macro.t())}
| :error
def expand_require(env, meta, module, name, arity, opts \\ [])
+12 -2
View File
@@ -687,6 +687,16 @@ defmodule Module do
@type definition :: {atom, arity}
@type def_kind :: :def | :defp | :defmacro | :defmacrop
@type create_opts :: [
file: binary(),
line: pos_integer(),
generated: boolean()
]
@type get_definition_opts :: [
skip_clauses: boolean()
]
@extra_error_msg_defines? "Use Kernel.function_exported?/3 and Kernel.macro_exported?/3 " <>
"to check for public functions and macros instead"
@@ -918,7 +928,7 @@ defmodule Module do
when defining the module, while `Kernel.defmodule/2`
automatically uses the environment it is invoked at.
"""
@spec create(module, Macro.t(), Macro.Env.t() | keyword) :: {:module, module, binary, term}
@spec create(module, Macro.t(), Macro.Env.t() | create_opts) :: {:module, module, binary, term}
def create(module, quoted, opts)
def create(module, quoted, %Macro.Env{} = env) when is_atom(module) do
@@ -1423,7 +1433,7 @@ defmodule Module do
only an interest in fetching the kind and the metadata
"""
@spec get_definition(module, definition, keyword) ::
@spec get_definition(module, definition, get_definition_opts) ::
{:v1, def_kind, meta :: keyword,
[{meta :: keyword, arguments :: [Macro.t()], guards :: [Macro.t()], Macro.t()}]}
| nil
+11
View File
@@ -11,9 +11,20 @@ defmodule Module.ParallelChecker do
@type warning() :: term()
@type mode() :: :erlang | :elixir | :protocol
@typedoc """
Options for `start_link/1`.
"""
@type start_link_opts :: [
{:max_concurrency, pos_integer()}
| {:long_verification_threshold, pos_integer()}
| {:each_long_verification, (module() -> term()) | (module(), pid() -> term())}
| {atom(), term()}
]
@doc """
Initializes the parallel checker process.
"""
@spec start_link(start_link_opts()) :: {:ok, cache()}
def start_link(opts \\ []) do
:proc_lib.start_link(__MODULE__, :init, [opts])
end
+14
View File
@@ -51,6 +51,13 @@ defmodule Module.Types.Descr do
# Type definitions
@typedoc """
Options for `to_quoted/2`.
"""
@type to_quoted_opts :: [
collapse_structs: boolean()
]
defguard is_descr(descr) when is_map(descr) or descr == :term
defp descr_key?(:term, _key), do: true
@@ -552,6 +559,7 @@ defmodule Module.Types.Descr do
* `:collapse_structs` - do not show struct fields that match
their default type
"""
@spec to_quoted(term(), to_quoted_opts) :: Macro.t()
def to_quoted(descr, opts \\ []) do
if term_type?(descr) do
{:term, [], []}
@@ -620,7 +628,13 @@ defmodule Module.Types.Descr do
@doc """
Converts a descr to its quoted string representation.
## Options
* `:collapse_structs` - do not show struct fields that match
their default type
"""
@spec to_quoted(term(), to_quoted_opts) :: String.t()
def to_quoted_string(descr, opts \\ []) do
descr
|> to_quoted(opts)
+8
View File
@@ -6,6 +6,13 @@ defmodule Module.Types.Helpers do
# AST and enumeration helpers.
@moduledoc false
@typedoc """
Options for `expr_to_string/2`.
"""
@type expr_to_string_opts :: [
collapse_structs: boolean()
]
## AST helpers
@doc """
@@ -272,6 +279,7 @@ defmodule Module.Types.Helpers do
We also undo some macro expressions done by the Kernel module.
"""
@spec expr_to_string(Macro.t(), expr_to_string_opts) :: String.t()
def expr_to_string(expr, opts \\ []) do
string = prewalk_expr_to_string(expr, opts)
+5 -3
View File
@@ -22,6 +22,8 @@ defmodule Path do
"""
@type t :: IO.chardata()
@type relative_to_opts :: [force: boolean()]
@doc """
Converts the given path to an absolute one.
@@ -401,7 +403,7 @@ defmodule Path do
Path.relative_to("../foo", "/usr/local") #=> "../foo"
"""
@spec relative_to(t, t, keyword) :: binary
@spec relative_to(t, t, relative_to_opts) :: binary
def relative_to(path, cwd, opts \\ []) when is_list(opts) do
os_type = major_os_type()
split_path = split(path)
@@ -479,7 +481,7 @@ defmodule Path do
Check `relative_to/3` for the supported options.
"""
@spec relative_to_cwd(t, keyword) :: binary
@spec relative_to_cwd(t, relative_to_opts) :: binary
def relative_to_cwd(path, opts \\ []) when is_list(opts) do
case :file.get_cwd() do
{:ok, base} -> relative_to(path, IO.chardata_to_string(base), opts)
@@ -801,7 +803,7 @@ defmodule Path do
Path.wildcard("projects/*/ebin/**/*.{beam,app}")
"""
@spec wildcard(t, keyword) :: [binary]
@spec wildcard(t, match_dot: boolean()) :: [binary]
def wildcard(glob, opts \\ []) when is_list(opts) do
mod = if Keyword.get(opts, :match_dot), do: :file, else: Path.Wildcard
+9 -2
View File
@@ -45,6 +45,13 @@ defmodule Record do
a module by calling `Code.fetch_docs/1`.
"""
@type extract_opts :: [
from: binary(),
from_lib: binary(),
includes: [binary()],
macros: keyword()
]
@doc """
Extracts record information from an Erlang file.
@@ -102,7 +109,7 @@ defmodule Record do
]
"""
@spec extract(name :: atom, keyword) :: keyword
@spec extract(name :: atom, extract_opts) :: keyword
def extract(name, opts) when is_atom(name) and is_list(opts) do
Record.Extractor.extract(name, opts)
end
@@ -119,7 +126,7 @@ defmodule Record do
Accepts the same options as listed for `Record.extract/2`.
"""
@spec extract_all(keyword) :: [{name :: atom, keyword}]
@spec extract_all(extract_opts) :: [{name :: atom, keyword}]
def extract_all(opts) when is_list(opts) do
Record.Extractor.extract_all(opts)
end
+30 -4
View File
@@ -164,6 +164,11 @@ defmodule Regex do
@type t :: %__MODULE__{re_pattern: term, source: binary, opts: [term]}
@type named_captures_opts :: [
return: :binary | :index,
offset: non_neg_integer()
]
defmodule CompileError do
@moduledoc """
An exception raised when a regular expression could not be compiled.
@@ -321,7 +326,7 @@ defmodule Regex do
["d", ""]
"""
@spec run(t, binary, [term]) :: nil | [binary] | [{integer, integer}]
@spec run(t, binary, capture_opts) :: nil | [binary] | [{integer, integer}]
def run(regex, string, options \\ [])
def run(%Regex{} = regex, string, options) when is_binary(string) do
@@ -343,6 +348,8 @@ defmodule Regex do
* `:return` - when set to `:index`, returns byte index and match length.
Defaults to `:binary`.
* `:offset` - (since v1.12.0) specifies the starting offset to match in the given string.
Defaults to zero.
## Examples
@@ -363,7 +370,7 @@ defmodule Regex do
You can then use `binary_part/3` to fetch the relevant part from the given string.
"""
@spec named_captures(t, String.t(), keyword) :: map | nil
@spec named_captures(t, String.t(), named_captures_opts) :: map | nil
def named_captures(regex, string, options \\ []) when is_binary(string) do
names = names(regex)
options = Keyword.put(options, :capture, names)
@@ -545,7 +552,7 @@ defmodule Regex do
[["cd"], ["ce"]]
"""
@spec scan(t(), String.t(), [term()]) :: [[String.t()]] | [[{integer(), integer()}]]
@spec scan(t(), String.t(), capture_opts) :: [[String.t()]] | [[{integer(), integer()}]]
def scan(regex, string, options \\ [])
def scan(%Regex{} = regex, string, options) when is_binary(string) do
@@ -573,6 +580,25 @@ defmodule Regex do
end
end
@typedoc """
Options for regex functions that capture matches.
"""
@type capture_opts :: [
return: :binary | :index,
capture: :all | :first | :all_but_first | :none | :all_names | [binary() | atom()],
offset: non_neg_integer()
]
@typedoc """
Options for `split/3`.
"""
@type split_opts :: [
parts: pos_integer() | :infinity,
trim: boolean(),
on: :first | :all | :all_but_first | :none | :all_names | [atom() | integer()],
include_captures: boolean()
]
@doc """
Splits the given target based on the given pattern and in the given number of
parts.
@@ -626,7 +652,7 @@ defmodule Regex do
["a", "b", "c"]
"""
@spec split(t, String.t(), [term]) :: [String.t()]
@spec split(t, String.t(), split_opts) :: [String.t()]
def split(regex, string, options \\ [])
def split(%Regex{}, "", opts) do
+12 -1
View File
@@ -242,6 +242,11 @@ defmodule Registry do
{:register, registry, key, registry_partition :: pid, value}
| {:unregister, registry, key, registry_partition :: pid}
@typedoc """
Options used for `dispatch/4`.
"""
@type dispatch_opts :: [parallel: boolean()]
## Via callbacks
@doc false
@@ -483,9 +488,15 @@ defmodule Registry do
See the module documentation for examples of using the `dispatch/3`
function for building custom dispatching or a pubsub system.
## Options
* `:parallel` - if `true`, the dispatching is done in parallel
across all partitions. Defaults to `false`.
"""
@doc since: "1.4.0"
@spec dispatch(registry, key, dispatcher, keyword) :: :ok
@spec dispatch(registry, key, dispatcher, dispatch_opts) :: :ok
when dispatcher: (entries :: [{pid, value}] -> term) | {module(), atom(), [term()]}
def dispatch(registry, key, mfa_or_fun, opts \\ [])
when is_atom(registry) and is_function(mfa_or_fun, 1)
+13 -3
View File
@@ -298,6 +298,15 @@ defmodule String do
| [nonempty_binary]
| (compiled_search_pattern :: :binary.cp())
@type split_opts :: [
parts: pos_integer() | :infinity,
trim: boolean()
]
@type splitter_opts :: [trim: boolean()]
@type replace_opts :: [global: boolean()]
@conditional_mappings [:greek, :turkic]
@doc """
@@ -502,7 +511,8 @@ defmodule String do
["a", "b", " c "]
"""
@spec split(t, pattern | Regex.t(), keyword) :: [t]
@spec split(t, pattern, split_opts()) :: [t]
@spec split(t, Regex.t(), Regex.split_opts()) :: [t]
def split(string, pattern, options \\ [])
def split(string, %Regex{} = pattern, options) when is_binary(string) and is_list(options) do
@@ -607,7 +617,7 @@ defmodule String do
["1", "2", "3", "4"]
"""
@spec splitter(t, pattern, keyword) :: Enumerable.t()
@spec splitter(t, pattern, splitter_opts) :: Enumerable.t()
def splitter(string, pattern, options \\ [])
def splitter(string, "", options) when is_binary(string) and is_list(options) do
@@ -1616,7 +1626,7 @@ defmodule String do
"é"
"""
@spec replace(t, pattern | Regex.t(), t | (t -> t | iodata), keyword) :: t
@spec replace(t, pattern | Regex.t(), t | (t -> t | iodata), replace_opts) :: t
def replace(subject, pattern, replacement, options \\ [])
when is_binary(subject) and
(is_binary(replacement) or is_function(replacement, 1)) and
+9 -3
View File
@@ -17,6 +17,11 @@ defmodule StringIO do
"""
@type open_opts :: [
capture_prompt: boolean(),
encoding: :unicode | :latin1
]
# We're implementing the GenServer behaviour instead of using the
# `use GenServer` macro, because we don't want the `child_spec/1`
# function as it doesn't make sense to be started under a supervisor.
@@ -59,7 +64,7 @@ defmodule StringIO do
"""
@doc since: "1.7.0"
@spec open(binary, keyword, (pid -> res)) :: {:ok, res} when res: var
@spec open(binary, open_opts, (pid -> res)) :: {:ok, res} when res: var
def open(string, options, function)
when is_binary(string) and is_list(options) and is_function(function, 1) do
{:ok, pid} = GenServer.start(__MODULE__, {self(), string, options}, [])
@@ -83,7 +88,8 @@ defmodule StringIO do
If options are provided, the result will be `{:ok, pid}`, returning the
IO device created. The option `:capture_prompt`, when set to `true`, causes
prompts (which are specified as arguments to `IO.get*` functions) to be
included in the device's output.
included in the device's output. See `options/3` for the list of supported
options.
If a function is provided, the device will be created and sent to the
function. When the function returns, the device will be closed. The final
@@ -111,7 +117,7 @@ defmodule StringIO do
{:ok, {"", "The input was foo"}}
"""
@spec open(binary, keyword) :: {:ok, pid}
@spec open(binary, open_opts) :: {:ok, pid}
@spec open(binary, (pid -> res)) :: {:ok, res} when res: var
def open(string, options_or_function \\ [])
+14 -1
View File
@@ -659,6 +659,19 @@ defmodule Supervisor do
@typedoc since: "1.16.0"
@type module_spec :: {module(), args :: term()} | module()
@typedoc """
Options for overriding child specification fields.
"""
@type child_spec_overrides :: [
id: atom() | term(),
start: {module(), atom(), [term()]},
restart: restart(),
shutdown: shutdown(),
type: type(),
modules: [module()] | :dynamic,
significant: boolean()
]
@doc """
Starts a supervisor with the given children.
@@ -896,7 +909,7 @@ defmodule Supervisor do
#=> start: {Agent, :start_link, [fn -> :ok end]}}
"""
@spec child_spec(child_spec() | module_spec(), keyword()) :: child_spec()
@spec child_spec(child_spec() | module_spec(), child_spec_overrides()) :: child_spec()
def child_spec(module_or_map, overrides)
def child_spec({_, _, _, _, _, _} = tuple, _overrides) do
+24 -2
View File
@@ -113,6 +113,28 @@ defmodule System do
| :sigusr1
| :sigusr2
@type cmd_opts :: [
into: Collectable.t(),
lines: pos_integer(),
cd: Path.t(),
env: [{binary(), binary() | nil}],
arg0: binary(),
stderr_to_stdout: boolean(),
use_stdio: boolean(),
parallelism: boolean()
]
@type shell_opts :: [
into: Collectable.t(),
lines: pos_integer(),
cd: Path.t(),
env: [{binary(), binary() | nil}],
stderr_to_stdout: boolean(),
use_stdio: boolean(),
parallelism: boolean(),
close_stdin: boolean()
]
@vm_signals [:sigquit, :sigterm, :sigusr1]
@os_signals [:sighup, :sigabrt, :sigalrm, :sigusr2, :sigchld, :sigstop, :sigtstp]
@signals @vm_signals ++ @os_signals
@@ -941,7 +963,7 @@ defmodule System do
immediately terminate. Defaults to false.
"""
@doc since: "1.12.0"
@spec shell(binary, keyword) :: {Collectable.t(), exit_status :: non_neg_integer}
@spec shell(binary, shell_opts) :: {Collectable.t(), exit_status :: non_neg_integer}
def shell(command, opts \\ []) when is_binary(command) do
command |> String.trim() |> do_shell(opts)
end
@@ -1101,7 +1123,7 @@ defmodule System do
If you desire to execute a trusted command inside a shell, with pipes,
redirecting and so on, please check `shell/2`.
"""
@spec cmd(binary, [binary], keyword) :: {Collectable.t(), exit_status :: non_neg_integer}
@spec cmd(binary, [binary], cmd_opts) :: {Collectable.t(), exit_status :: non_neg_integer}
def cmd(command, args, opts \\ []) when is_binary(command) and is_list(args) do
assert_no_null_byte!(command, "System.cmd/3")
+18 -6
View File
@@ -87,6 +87,18 @@ defmodule Task.Supervisor do
@typedoc since: "1.17.0"
@type async_stream_option :: Task.async_stream_option() | {:shutdown, Supervisor.shutdown()}
@typedoc """
Options for `async/3`, `async/5`, `async_nolink/3`, and `async_nolink/5` functions.
"""
@type async_opts :: [
shutdown: :brutal_kill | timeout()
]
@type start_child_opts :: [
restart: :temporary | :transient | :permanent,
shutdown: :brutal_kill | timeout()
]
@doc false
def child_spec(opts) when is_list(opts) do
id =
@@ -175,7 +187,7 @@ defmodule Task.Supervisor do
The tasks must trap exits for the timeout to have an effect.
"""
@spec async(Supervisor.supervisor(), (-> any), Keyword.t()) :: Task.t()
@spec async(Supervisor.supervisor(), (-> any), async_opts) :: Task.t()
def async(supervisor, fun, options \\ []) do
async(supervisor, :erlang, :apply, [fun, []], options)
end
@@ -197,7 +209,7 @@ defmodule Task.Supervisor do
The tasks must trap exits for the timeout to have an effect.
"""
@spec async(Supervisor.supervisor(), module, atom, [term], Keyword.t()) :: Task.t()
@spec async(Supervisor.supervisor(), module, atom, [term], async_opts) :: Task.t()
def async(supervisor, module, fun, args, options \\ []) do
async(supervisor, :link, module, fun, args, options)
end
@@ -284,7 +296,7 @@ defmodule Task.Supervisor do
end
"""
@spec async_nolink(Supervisor.supervisor(), (-> any), Keyword.t()) :: Task.t()
@spec async_nolink(Supervisor.supervisor(), (-> any), async_opts) :: Task.t()
def async_nolink(supervisor, fun, options \\ []) do
async_nolink(supervisor, :erlang, :apply, [fun, []], options)
end
@@ -303,7 +315,7 @@ defmodule Task.Supervisor do
as the `:restart` option (the default), as `async_nolink/5` keeps a
direct reference to the task which is lost if the task is restarted.
"""
@spec async_nolink(Supervisor.supervisor(), module, atom, [term], Keyword.t()) :: Task.t()
@spec async_nolink(Supervisor.supervisor(), module, atom, [term], async_opts) :: Task.t()
def async_nolink(supervisor, module, fun, args, options \\ []) do
async(supervisor, :nolink, module, fun, args, options)
end
@@ -523,7 +535,7 @@ defmodule Task.Supervisor do
The task must trap exits for the timeout to have an effect.
"""
@spec start_child(Supervisor.supervisor(), (-> any), keyword) ::
@spec start_child(Supervisor.supervisor(), (-> any), start_child_opts) ::
DynamicSupervisor.on_start_child()
def start_child(supervisor, fun, options \\ []) do
restart = options[:restart]
@@ -538,7 +550,7 @@ defmodule Task.Supervisor do
Similar to `start_child/3` except the task is specified
by the given `module`, `fun` and `args`.
"""
@spec start_child(Supervisor.supervisor(), module, atom, [term], keyword) ::
@spec start_child(Supervisor.supervisor(), module, atom, [term], start_child_opts) ::
DynamicSupervisor.on_start_child()
def start_child(supervisor, module, fun, args, options \\ [])
when is_atom(fun) and is_list(args) do
+3 -1
View File
@@ -118,6 +118,8 @@ defmodule Version do
@type build :: String.t() | nil
@type t :: %__MODULE__{major: major, minor: minor, patch: patch, pre: pre, build: build}
@type match_opts :: [allow_pre: boolean()]
defmodule Requirement do
@moduledoc """
A struct that holds version requirement information.
@@ -296,7 +298,7 @@ defmodule Version do
** (Version.InvalidRequirementError) invalid requirement: "== == 1.0.0"
"""
@spec match?(version, requirement, keyword) :: boolean
@spec match?(version, requirement, match_opts) :: boolean
def match?(version, requirement, opts \\ [])
def match?(version, requirement, opts) when is_binary(requirement) do
+46 -2
View File
@@ -93,6 +93,50 @@ defmodule ExUnit do
@type test_id :: {module, name :: atom}
@typedoc """
Configuration options for ExUnit.
See `configure/1` for detailed documentation of each option.
"""
@type configure_opts :: [
{:assert_receive_timeout, non_neg_integer()}
| {:autorun, boolean()}
| {:capture_log, boolean() | [level: Logger.level()]}
| {:colors,
[
enabled: boolean(),
success: atom(),
invalid: atom(),
skipped: atom(),
failure: atom(),
error_info: atom(),
extra_info: atom(),
location_info: [atom()],
diff_insert: atom(),
diff_insert_whitespace: IO.ANSI.ansidata(),
diff_delete: atom(),
diff_delete_whitespace: IO.ANSI.ansidata()
]}
| {:exclude, keyword()}
| {:exit_status, non_neg_integer()}
| {:failures_manifest_path, String.t()}
| {:formatters, [module()]}
| {:include, keyword()}
| {:max_cases, pos_integer()}
| {:max_failures, pos_integer() | :infinity}
| {:only_test_ids, [test_id()]}
| {:rand_algorithm, atom()}
| {:refute_receive_timeout, non_neg_integer()}
| {:seed, non_neg_integer()}
| {:slowest, non_neg_integer()}
| {:slowest_modules, non_neg_integer()}
| {:stacktrace_depth, non_neg_integer()}
| {:timeout, pos_integer()}
| {:trace, boolean()}
| {:test_location_relative_path, String.t()}
| {atom(), term()}
]
defmodule Test do
@moduledoc """
A struct that keeps information about the test.
@@ -218,7 +262,7 @@ defmodule ExUnit do
If you want to run tests manually, you can set the `:autorun` option
to `false` and use `run/0` to run tests.
"""
@spec start(Keyword.t()) :: :ok
@spec start(configure_opts()) :: :ok
def start(options \\ []) do
{:ok, _} = Application.ensure_all_started(:ex_unit)
@@ -357,7 +401,7 @@ defmodule ExUnit do
and these options can then be used in places such as custom formatters. These
other options will be ignored by ExUnit itself.
"""
@spec configure(Keyword.t()) :: :ok
@spec configure(configure_opts()) :: :ok
def configure(options) when is_list(options) do
Enum.each(options, fn {k, v} ->
Application.put_env(:ex_unit, k, v)
+13 -3
View File
@@ -169,6 +169,12 @@ defmodule ExUnit.Callbacks do
end
"""
@type child_spec_overrides :: [
restart: :permanent | :transient | :temporary,
shutdown: :brutal_kill | timeout(),
type: :worker | :supervisor
]
@doc false
def __register__(module) do
Module.put_attribute(module, :ex_unit_describe, nil)
@@ -560,7 +566,7 @@ defmodule ExUnit.Callbacks do
more about these keys in [the `Task` module](`Task#module-ancestor-and-caller-tracking`).
"""
@doc since: "1.5.0"
@spec start_supervised(Supervisor.child_spec() | module | {module, term}, keyword) ::
@spec start_supervised(Supervisor.child_spec() | module | {module, term}, child_spec_overrides) ::
Supervisor.on_start_child()
def start_supervised(child_spec_or_module, opts \\ []) do
sup =
@@ -581,7 +587,8 @@ defmodule ExUnit.Callbacks do
not started properly.
"""
@doc since: "1.6.0"
@spec start_supervised!(Supervisor.child_spec() | module | {module, term}, keyword) :: pid
@spec start_supervised!(Supervisor.child_spec() | module | {module, term}, child_spec_overrides) ::
pid
def start_supervised!(child_spec_or_module, opts \\ []) do
case start_supervised(child_spec_or_module, opts) do
{:ok, pid} ->
@@ -627,7 +634,10 @@ defmodule ExUnit.Callbacks do
> *by the test supervisor* in reverse order, ensuring graceful termination.
"""
@doc since: "1.14.0"
@spec start_link_supervised!(Supervisor.child_spec() | module | {module, term}, keyword) ::
@spec start_link_supervised!(
Supervisor.child_spec() | module | {module, term},
child_spec_overrides
) ::
pid
def start_link_supervised!(child_spec_or_module, opts \\ []) do
pid = start_supervised!(child_spec_or_module, opts)
+10 -4
View File
@@ -28,6 +28,12 @@ defmodule ExUnit.CaptureIO do
"""
@type capture_io_opts :: [
input: String.t(),
capture_prompt: boolean(),
encoding: :unicode | :latin1
]
@doc """
Captures IO generated when evaluating `fun`.
@@ -152,7 +158,7 @@ defmodule ExUnit.CaptureIO do
See `capture_io/1` for more information.
"""
@spec capture_io(atom() | pid() | String.t() | keyword(), (-> any())) :: String.t()
@spec capture_io(atom() | pid() | String.t() | capture_io_opts, (-> any())) :: String.t()
def capture_io(device_pid_input_or_options, fun)
def capture_io(device_or_pid, fun)
@@ -172,7 +178,7 @@ defmodule ExUnit.CaptureIO do
See `capture_io/1` for more information.
"""
@spec capture_io(atom() | pid(), String.t() | keyword(), (-> any())) :: String.t()
@spec capture_io(atom() | pid(), String.t() | capture_io_opts, (-> any())) :: String.t()
def capture_io(device_or_pid, input_or_options, fun)
when (is_atom(device_or_pid) or is_pid(device_or_pid)) and
(is_binary(input_or_options) or is_list(input_or_options)) and is_function(fun, 0) do
@@ -209,7 +215,7 @@ defmodule ExUnit.CaptureIO do
See `with_io/1` for more information.
"""
@doc since: "1.13.0"
@spec with_io(atom() | pid() | String.t() | keyword(), (-> any())) :: {any(), String.t()}
@spec with_io(atom() | pid() | String.t() | capture_io_opts, (-> any())) :: {any(), String.t()}
def with_io(device_pid_input_or_options, fun)
def with_io(device, fun) when is_atom(device) and is_function(fun, 0) do
@@ -234,7 +240,7 @@ defmodule ExUnit.CaptureIO do
See `with_io/1` for more information.
"""
@doc since: "1.13.0"
@spec with_io(atom() | pid(), String.t() | keyword(), (-> any())) :: {any(), String.t()}
@spec with_io(atom() | pid(), String.t() | capture_io_opts, (-> any())) :: {any(), String.t()}
def with_io(device_or_pid, input_or_options, fun)
def with_io(device, input, fun)
+6 -2
View File
@@ -43,6 +43,10 @@ defmodule ExUnit.CaptureLog do
@compile {:no_warn_undefined, Logger}
@type capture_log_opts :: [
level: Logger.level() | nil
]
@doc """
Captures Logger messages generated when evaluating `fun`.
@@ -74,7 +78,7 @@ defmodule ExUnit.CaptureLog do
To get the result of the evaluation along with the captured log,
use `with_log/2`.
"""
@spec capture_log(keyword, (-> any)) :: String.t()
@spec capture_log(capture_log_opts, (-> any)) :: String.t()
def capture_log(opts \\ [], fun) do
{_, log} = with_log(opts, fun)
log
@@ -98,7 +102,7 @@ defmodule ExUnit.CaptureLog do
"""
@doc since: "1.13.0"
@spec with_log(keyword, (-> result)) :: {result, log :: String.t()} when result: any
@spec with_log(capture_log_opts, (-> result)) :: {result, log :: String.t()} when result: any
def with_log(opts \\ [], fun) when is_list(opts) do
opts =
if opts[:level] == :warn do
+8 -3
View File
@@ -338,6 +338,11 @@ defmodule ExUnit.Case do
"""
@type env :: module() | Macro.Env.t()
@type register_attribute_opts :: [
accumulate: boolean(),
persist: boolean()
]
@compile {:no_warn_undefined, [IEx.Pry]}
@reserved [:module, :file, :line, :test, :async, :registered, :describe]
@@ -767,7 +772,7 @@ defmodule ExUnit.Case do
"""
@doc since: "1.3.0"
@spec register_attribute(env, atom, keyword) :: :ok
@spec register_attribute(env, atom, register_attribute_opts) :: :ok
def register_attribute(env, name, opts \\ [])
def register_attribute(%{module: mod}, name, opts), do: register_attribute(mod, name, opts)
@@ -809,7 +814,7 @@ defmodule ExUnit.Case do
"""
@doc since: "1.10.0"
@spec register_describe_attribute(env, atom, keyword) :: :ok
@spec register_describe_attribute(env, atom, register_attribute_opts) :: :ok
def register_describe_attribute(env, name, opts \\ [])
def register_describe_attribute(%{module: mod}, name, opts) do
@@ -849,7 +854,7 @@ defmodule ExUnit.Case do
"""
@doc since: "1.10.0"
@spec register_module_attribute(env, atom, keyword) :: :ok
@spec register_module_attribute(env, atom, register_attribute_opts) :: :ok
def register_module_attribute(env, name, opts \\ [])
def register_module_attribute(%{module: mod}, name, opts) do
+73 -1
View File
@@ -390,6 +390,78 @@ defmodule IEx do
"""
@typedoc """
Color settings used by the IEx shell.
"""
@type colors_opts :: [
enabled: boolean(),
eval_result: IO.ANSI.ansidata(),
eval_info: IO.ANSI.ansidata(),
eval_error: IO.ANSI.ansidata(),
eval_interrupt: IO.ANSI.ansidata(),
stack_info: IO.ANSI.ansidata(),
blame_diff: IO.ANSI.ansidata(),
ls_directory: IO.ANSI.ansidata(),
ls_device: IO.ANSI.ansidata(),
doc_code: IO.ANSI.ansidata(),
doc_inline_code: IO.ANSI.ansidata(),
doc_headings: IO.ANSI.ansidata(),
doc_title: IO.ANSI.ansidata(),
doc_bold: IO.ANSI.ansidata(),
doc_underline: IO.ANSI.ansidata(),
syntax_colors: syntax_colors_opts() | false
]
@typedoc """
Syntax coloring settings for inspected expressions.
"""
@type syntax_colors_opts :: [
atom: IO.ANSI.ansidata(),
binary: IO.ANSI.ansidata(),
boolean: IO.ANSI.ansidata(),
charlist: IO.ANSI.ansidata(),
list: IO.ANSI.ansidata(),
map: IO.ANSI.ansidata(),
nil: IO.ANSI.ansidata(),
number: IO.ANSI.ansidata(),
string: IO.ANSI.ansidata(),
tuple: IO.ANSI.ansidata(),
variable: IO.ANSI.ansidata(),
call: IO.ANSI.ansidata(),
operator: IO.ANSI.ansidata(),
reset: IO.ANSI.ansidata()
]
@typedoc """
Inspect settings used by the IEx shell.
"""
@type inspect_opts :: [
base: :binary | :decimal | :octal | :hex,
binaries: :infer | :as_binaries | :as_strings,
charlists: :infer | :as_charlists | :as_lists,
custom_options: keyword(),
inspect_fun: (term(), Inspect.Opts.t() -> Inspect.Algebra.t()),
limit: pos_integer() | :infinity,
pretty: boolean(),
printable_limit: pos_integer() | :infinity,
safe: boolean(),
structs: boolean(),
syntax_colors: syntax_colors_opts(),
width: pos_integer() | :infinity
]
@type configure_opts :: [
auto_reload: boolean(),
alive_prompt: String.t(),
colors: colors_opts(),
default_prompt: String.t(),
dot_iex: String.t() | nil,
history_size: integer(),
inspect: inspect_opts(),
parser: {module(), atom(), [any()]},
width: pos_integer()
]
@doc """
Configures IEx.
@@ -521,7 +593,7 @@ defmodule IEx do
in-memory modules when they get invalidated by a concurrent compilation
happening in the Operating System.
"""
@spec configure(keyword()) :: :ok
@spec configure(configure_opts) :: :ok
def configure(options) do
IEx.Config.configure(options)
end
+8 -1
View File
@@ -9,6 +9,13 @@ defmodule IEx.Broker do
@type take_ref :: {takeover_ref :: reference(), server_ref :: reference()}
@type shell :: pid | nil
@typedoc """
Options for `take_over/3`.
"""
@type take_over_opts :: [
evaluator: pid()
]
use GenServer
## Shell API
@@ -58,7 +65,7 @@ defmodule IEx.Broker do
@doc """
Client requests a takeover.
"""
@spec take_over(binary, iodata, keyword) ::
@spec take_over(binary, iodata, take_over_opts) ::
{:ok, server :: pid, group_leader :: pid, counter :: integer}
| {:error, :no_iex | :refused | atom()}
def take_over(location, whereami, opts) do
+1
View File
@@ -113,6 +113,7 @@ defmodule IEx.Helpers do
* `:force` - when `true`, forces the application to recompile
"""
@spec recompile(force: boolean()) :: :ok | :error | :noop
def recompile(options \\ []) do
cond do
not mix_started?() ->
+9 -1
View File
@@ -14,6 +14,14 @@ defmodule IEx.Server do
"""
@type run_opts :: [
prefix: String.t(),
env: Macro.Env.t(),
binding: keyword(),
on_eof: :stop_evaluator | :halt,
register: boolean()
]
@doc false
defstruct parser_state: [],
counter: 1,
@@ -35,7 +43,7 @@ defmodule IEx.Server do
"""
@doc since: "1.8.0"
@spec run(keyword) :: :ok
@spec run(run_opts) :: :ok
def run(opts) when is_list(opts) do
if Keyword.get(opts, :register, true) do
IEx.Broker.register(self())
+20 -2
View File
@@ -62,7 +62,16 @@ defmodule IEx.AutocompleteTest do
assert expand(~c"t String") == {:yes, ~c"", [~c"String", ~c"StringIO"]}
assert expand(~c"t String.") ==
{:yes, ~c"", [~c"codepoint/0", ~c"grapheme/0", ~c"pattern/0", ~c"t/0"]}
{:yes, ~c"",
[
~c"codepoint/0",
~c"grapheme/0",
~c"pattern/0",
~c"replace_opts/0",
~c"split_opts/0",
~c"splitter_opts/0",
~c"t/0"
]}
assert expand(~c"t String.grap") == {:yes, ~c"heme", []}
assert expand(~c"t String.grap") == {:yes, ~c"heme", []}
@@ -85,7 +94,16 @@ defmodule IEx.AutocompleteTest do
assert expand(~c"t(String") == {:yes, ~c"", [~c"String", ~c"StringIO"]}
assert expand(~c"t(String.") ==
{:yes, ~c"", [~c"codepoint/0", ~c"grapheme/0", ~c"pattern/0", ~c"t/0"]}
{:yes, ~c"",
[
~c"codepoint/0",
~c"grapheme/0",
~c"pattern/0",
~c"replace_opts/0",
~c"split_opts/0",
~c"splitter_opts/0",
~c"t/0"
]}
assert expand(~c"t(String.grap") == {:yes, ~c"heme", []}
end
+1 -1
View File
@@ -967,7 +967,7 @@ defmodule IEx.HelpersTest do
describe "t" do
test "prints when there is no type information or the type is private" do
assert capture_io(fn -> t(IEx) end) == "No type information for IEx was found\n"
assert capture_io(fn -> t(List) end) == "No type information for List was found\n"
assert capture_io(fn -> t(Enum.doesnt_exist()) end) ==
"No type information for Enum.doesnt_exist was found or " <>
+27 -3
View File
@@ -507,6 +507,30 @@ defmodule Logger do
@type report :: map() | keyword()
@type message :: :unicode.chardata() | String.Chars.t() | report()
@type metadata :: keyword()
@type configure_opts :: [
level: level(),
translator_inspect_opts: Inspect.Opts.t(),
sync_threshold: non_neg_integer(),
discard_threshold: non_neg_integer(),
truncate: non_neg_integer() | :infinity,
utc_log: boolean()
]
@type formatter_opts :: [
colors: [
enabled: boolean(),
debug: atom(),
info: atom(),
warning: atom(),
error: atom()
],
format: String.t() | {module(), atom()},
metadata: :all | [atom()],
truncate: pos_integer() | :infinity,
utc_log: boolean()
]
@new_erlang_levels [:emergency, :alert, :critical, :warning, :notice]
@levels [:error, :info, :debug] ++ @new_erlang_levels
@metadata :logger_level
@@ -552,7 +576,7 @@ defmodule Logger do
instead.
"""
@doc since: "1.15.0"
@spec default_formatter(keyword) :: {module, :logger.formatter_config()}
@spec default_formatter(formatter_opts) :: {module, :logger.formatter_config()}
def default_formatter(overrides \\ []) when is_list(overrides) do
Application.get_env(:logger, :default_formatter, [])
|> Keyword.merge(overrides)
@@ -712,7 +736,7 @@ defmodule Logger do
:translator_inspect_opts
]
@backend_options [:sync_threshold, :discard_threshold, :truncate, :utc_log]
@spec configure(keyword) :: :ok
@spec configure(configure_opts) :: :ok
def configure(options) do
for {k, v} <- options do
cond do
@@ -973,7 +997,7 @@ defmodule Logger do
anonymous functions to `bare_log/3` and they will only be evaluated
if there is something to be logged.
"""
@spec bare_log(level, message | (-> message | {message, keyword}), keyword) :: :ok
@spec bare_log(level, message | (-> message | {message, keyword}), metadata) :: :ok
def bare_log(level, message_or_fun, metadata \\ []) do
level = elixir_level_to_erlang_level(level)
+22 -3
View File
@@ -8,13 +8,32 @@ defmodule Logger.Backends.Internal do
@name __MODULE__
@type backend :: :gen_event.handler()
@typedoc """
Configuration options for Logger backends.
These are the built-in backend options that can be configured at runtime.
"""
@type backend_config_opts :: [
sync_threshold: pos_integer(),
discard_threshold: pos_integer() | :infinity,
truncate: pos_integer() | :infinity,
utc_log: boolean()
]
@typedoc """
Options for `add/2` and `remove/2` operations.
"""
@type add_remove_opts :: [
flush: boolean()
]
@doc """
Apply runtime configuration to all backends.
See the module doc for more information.
"""
@backend_options [:sync_threshold, :discard_threshold, :truncate, :utc_log]
@spec configure(keyword) :: :ok
@spec configure(backend_config_opts) :: :ok
def configure(options) do
ensure_started()
Logger.Backends.Config.configure(Keyword.take(options, @backend_options))
@@ -65,7 +84,7 @@ defmodule Logger.Backends.Internal do
{:ok, _pid} = Logger.add_backend(MyBackend, flush: true)
"""
@spec add(backend, keyword) :: Supervisor.on_start_child()
@spec add(backend, add_remove_opts) :: Supervisor.on_start_child()
def add(backend, opts \\ []) do
ensure_started()
_ = if opts[:flush], do: Logger.flush()
@@ -91,7 +110,7 @@ defmodule Logger.Backends.Internal do
to `Logger` are processed before the backend is removed
"""
@spec remove(backend, keyword) :: :ok | {:error, term}
@spec remove(backend, add_remove_opts) :: :ok | {:error, term}
def remove(backend, opts \\ []) do
ensure_started()
_ = if opts[:flush], do: Logger.flush()
+15 -1
View File
@@ -99,6 +99,20 @@ defmodule Logger.Formatter do
@type date_time_ms :: {date, time_ms}
@type pattern :: :date | :level | :levelpad | :message | :metadata | :node | :time
@type new_opts :: [
colors: [
enabled: boolean(),
debug: atom(),
info: atom(),
warning: atom(),
error: atom()
],
format: String.t() | {module(), atom()},
metadata: :all | [atom()],
truncate: pos_integer() | :infinity,
utc_log: boolean()
]
@valid_patterns [:time, :date, :message, :level, :node, :metadata, :levelpad]
@default_pattern "\n$time $metadata[$level] $message\n"
@replacement "�"
@@ -152,7 +166,7 @@ defmodule Logger.Formatter do
The color of the message can also be configured per message via
the `:ansi_color` metadata.
"""
@spec new(keyword) :: formatter when formatter: term
@spec new(new_opts) :: formatter when formatter: term
def new(options \\ []) do
template = compile(options[:format])
colors = colors(options[:colors] || [])
+6
View File
@@ -127,6 +127,12 @@ defmodule Logger.Utils do
For information about format scanning and how to consume them,
check `:io_lib.scan_format/2`.
"""
@spec scan_inspect(
atom() | binary() | charlist(),
list(),
non_neg_integer() | :infinity,
Inspect.Opts.t()
) :: [:io_lib.format_spec()]
def scan_inspect(format, args, truncate, opts \\ %Inspect.Opts{})
def scan_inspect(format, args, truncate, opts) when is_atom(format) do
+23
View File
@@ -424,6 +424,25 @@ defmodule Mix do
"""
@typedoc """
Options for `install/2`.
See the `install/2` function documentation for detailed information about each option.
"""
@type install_opts :: [
force: boolean(),
verbose: boolean(),
consolidate_protocols: boolean(),
elixir: String.t(),
system_env: Enum.t(),
config: keyword(),
config_path: String.t() | atom(),
lockfile: String.t() | atom(),
start_applications: boolean(),
compilers: [atom()],
runtime_config: keyword()
]
@mix_install_project Mix.InstallProject
@mix_install_app :mix_install
@mix_install_app_string Atom.to_string(@mix_install_app)
@@ -845,6 +864,10 @@ defmodule Mix do
if `:force` is enabled.
"""
@doc since: "1.12.0"
@spec install(
[atom() | {atom(), String.t()} | {atom(), String.t(), keyword()} | {atom(), keyword()}],
install_opts()
) :: :ok
def install(deps, opts \\ [])
def install(deps, opts) when is_list(deps) and is_list(opts) do
+17
View File
@@ -7,6 +7,15 @@ defmodule Mix.Compilers.Erlang do
@manifest_vsn 1
@typedoc """
Options for `compile/6`.
"""
@type compile_opts :: [
force: boolean(),
parallel: MapSet.t(Path.t()),
preload: (-> term())
]
@doc """
Compiles the given `mappings`.
@@ -58,6 +67,14 @@ defmodule Mix.Compilers.Erlang do
`{:error, errors, warnings}` in case of error. This function returns
`{status, diagnostics}` as specified in `Mix.Task.Compiler`.
"""
@spec compile(
Path.t(),
[{Path.t(), Path.t()}],
atom(),
atom(),
compile_opts,
(Path.t(), Path.t() -> {:ok, term(), [term()]} | {:error, [term()], [term()]})
) :: {Mix.Task.Compiler.status(), [Mix.Task.Compiler.Diagnostic.t()]}
def compile(manifest, mappings, src_ext, dest_ext, opts, callback)
when is_atom(src_ext) and is_atom(dest_ext) and is_list(opts) do
force = opts[:force]
+8
View File
@@ -79,6 +79,13 @@ defmodule Mix.Dep do
system_env: keyword
}
@typedoc """
Options for `filter_by_name/3`.
"""
@type filter_by_name_opts :: [
include_children: boolean()
]
@doc """
Returns loaded dependencies from the cache for the current environment.
@@ -197,6 +204,7 @@ defmodule Mix.Dep do
Raises if any of the names are missing.
"""
@spec filter_by_name([atom() | String.t()], [t()], filter_by_name_opts) :: [t()]
def filter_by_name(given, all_deps, opts \\ []) do
# Ensure all apps are atoms
apps = to_app_names(given)
+10
View File
@@ -8,6 +8,14 @@
defmodule Mix.Dep.Converger do
@moduledoc false
@typedoc """
Options for `converge/1` and `converge/4`.
"""
@type converge_opts :: [
env: atom(),
target: atom()
]
@doc """
Topologically sorts the given dependencies.
"""
@@ -72,6 +80,7 @@ defmodule Mix.Dep.Converger do
See `Mix.Dep.Loader.children/1` for options.
"""
@spec converge(converge_opts) :: [Mix.Dep.t()]
def converge(opts \\ []) do
converge(nil, nil, opts, &{&1, &2, &3}) |> elem(0)
end
@@ -89,6 +98,7 @@ defmodule Mix.Dep.Converger do
See `Mix.Dep.Loader.children/1` for options.
"""
@spec converge(term(), map() | nil, converge_opts, function()) :: {[Mix.Dep.t()], term(), map()}
def converge(acc, lock, opts, callback) do
{deps, acc, lock} = all(acc, lock, opts, callback)
if remote = Mix.RemoteConverger.get(), do: remote.post_converge()
+9 -1
View File
@@ -9,6 +9,14 @@
defmodule Mix.Dep.Lock do
@moduledoc false
@typedoc """
Options for `write/2`.
"""
@type write_opts :: [
file: Path.t(),
check_locked: boolean()
]
@doc """
Reads the lockfile, returns a map containing
each app name and its current lock information.
@@ -30,7 +38,7 @@ defmodule Mix.Dep.Lock do
@doc """
Receives a map and writes it as the latest lock.
"""
@spec write(map(), keyword) :: :ok
@spec write(map(), write_opts) :: :ok
def write(map, opts \\ []) do
lockfile = opts[:file] || lockfile()
+12 -4
View File
@@ -7,6 +7,12 @@ defmodule Mix.Generator do
Conveniences for working with paths and generating content.
"""
@type generator_opts :: [
force: boolean(),
quiet: boolean(),
format_elixir: boolean()
]
@doc ~S"""
Creates a file with the given contents.
@@ -17,6 +23,7 @@ defmodule Mix.Generator do
* `:force` - forces creation without a shell prompt
* `:quiet` - does not log command output
* `:format_elixir` (since v1.18.0) - if `true`, apply formatter to the generated file
## Examples
@@ -25,7 +32,7 @@ defmodule Mix.Generator do
true
"""
@spec create_file(Path.t(), iodata, keyword) :: boolean()
@spec create_file(Path.t(), iodata, generator_opts) :: boolean()
def create_file(path, contents, opts \\ []) when is_binary(path) do
log(:green, :creating, Path.relative_to_cwd(path), opts)
@@ -62,7 +69,7 @@ defmodule Mix.Generator do
true
"""
@spec create_directory(Path.t(), keyword) :: true
@spec create_directory(Path.t(), quiet: boolean()) :: true
def create_directory(path, options \\ []) when is_binary(path) do
log(:green, "creating", Path.relative_to_cwd(path), options)
File.mkdir_p!(path)
@@ -79,6 +86,7 @@ defmodule Mix.Generator do
* `:force` - forces copying without a shell prompt
* `:quiet` - does not log command output
* `:format_elixir` (since v1.18.0) - if `true`, apply formatter to the generated file
## Examples
@@ -88,7 +96,7 @@ defmodule Mix.Generator do
"""
@doc since: "1.9.0"
@spec copy_file(Path.t(), Path.t(), keyword) :: boolean()
@spec copy_file(Path.t(), Path.t(), generator_opts) :: boolean()
def copy_file(source, target, options \\ []) do
create_file(target, File.read!(source), options)
end
@@ -116,7 +124,7 @@ defmodule Mix.Generator do
"""
@doc since: "1.9.0"
@spec copy_template(Path.t(), Path.t(), keyword, keyword) :: boolean()
@spec copy_template(Path.t(), Path.t(), keyword, generator_opts) :: boolean()
def copy_template(source, target, assigns, options \\ []) do
create_file(target, EEx.eval_file(source, assigns: assigns), options)
end
+20 -3
View File
@@ -23,10 +23,27 @@ defmodule Mix.Local.Installer do
| {:url, url :: binary}
| {:fetcher, dep_spec :: tuple}
@typedoc """
Options for installer functions.
These options are used by various installer functions to control behavior
during installation, parsing, and uninstallation.
"""
@type installer_opts :: [
app: String.t(),
submodules: boolean(),
sparse: String.t(),
force: boolean(),
sha512: String.t(),
organization: String.t(),
repo: String.t(),
timeout: pos_integer()
]
@doc """
Checks that the `install_spec` and `opts` are supported by the respective module.
"""
@callback check_install_spec(install_spec, opts :: keyword) :: :ok | {:error, String.t()}
@callback check_install_spec(install_spec, opts :: installer_opts) :: :ok | {:error, String.t()}
@doc """
Returns a list of already installed version of the same artifact.
@@ -37,7 +54,7 @@ defmodule Mix.Local.Installer do
Builds a local artifact either from a remote dependency or for
the current project.
"""
@callback build(install_spec, opts :: Keyword.t()) :: Path.t()
@callback build(install_spec, opts :: installer_opts) :: Path.t()
@doc """
The installation itself.
@@ -175,7 +192,7 @@ defmodule Mix.Local.Installer do
@doc """
Receives `argv` and `opts` from options parsing and returns an `install_spec`.
"""
@spec parse_args([String.t()], keyword) :: install_spec | {:error, String.t()}
@spec parse_args([String.t()], installer_opts) :: install_spec | {:error, String.t()}
def parse_args(argv, opts)
def parse_args([], _opts) do
+24 -5
View File
@@ -158,6 +158,22 @@ defmodule Mix.Project do
"""
@type build_structure_opts :: [
symlink_ebin: boolean(),
source: String.t()
]
@typedoc """
Options for dependency traversal functions.
These options control how dependency trees are traversed and filtered
in functions like `deps_scms/1`, `deps_paths/1`, and `deps_tree/1`.
"""
@type deps_traversal_opts :: [
depth: pos_integer(),
parents: [atom()]
]
@doc false
defmacro __using__(_) do
quote do
@@ -540,7 +556,7 @@ defmodule Mix.Project do
"""
@doc since: "1.10.0"
@spec deps_scms(keyword) :: %{optional(atom) => Mix.SCM.t()}
@spec deps_scms(deps_traversal_opts) :: %{optional(atom) => Mix.SCM.t()}
def deps_scms(opts \\ []) when is_list(opts) do
traverse_deps(opts, fn %{scm: scm} -> scm end)
end
@@ -561,7 +577,7 @@ defmodule Mix.Project do
#=> %{foo: "deps/foo", bar: "custom/path/dep"}
"""
@spec deps_paths(keyword) :: %{optional(atom) => Path.t()}
@spec deps_paths(deps_traversal_opts) :: %{optional(atom) => Path.t()}
def deps_paths(opts \\ []) when is_list(opts) do
traverse_deps(opts, fn %{opts: opts} -> opts[:dest] end)
end
@@ -583,7 +599,7 @@ defmodule Mix.Project do
"""
@doc since: "1.15.0"
@spec deps_tree(keyword) :: %{optional(atom) => [atom]}
@spec deps_tree(deps_traversal_opts) :: %{optional(atom) => [atom]}
def deps_tree(opts \\ []) when is_list(opts) do
traverse_deps(opts, fn %{deps: deps} -> Enum.map(deps, & &1.app) end)
end
@@ -843,8 +859,11 @@ defmodule Mix.Project do
* `:symlink_ebin` - symlink ebin instead of copying it
* `:source` - the source directory to copy from.
Defaults to the current working directory.
"""
@spec build_structure(keyword, keyword) :: :ok
@spec build_structure(keyword, build_structure_opts) :: :ok
def build_structure(config \\ config(), opts \\ []) do
source = opts[:source] || File.cwd!()
target = app_path(config)
@@ -878,7 +897,7 @@ defmodule Mix.Project do
`opts` are the same options that can be passed to `build_structure/2`.
"""
@spec ensure_structure(keyword, keyword) :: :ok
@spec ensure_structure(keyword, build_structure_opts) :: :ok
def ensure_structure(config \\ config(), opts \\ []) do
if File.exists?(app_path(config)) do
:ok
+37 -2
View File
@@ -68,6 +68,23 @@ defmodule Mix.Release do
steps: [(t -> t) | :assemble, ...]
}
@typedoc """
Options for stripping BEAM files.
"""
@type strip_beam_opts :: [
keep: [String.t()],
compress: boolean()
]
@typedoc """
Erlang/OTP sys.config structure.
A list of tuples where each tuple contains an application name and its
configuration as a keyword list. This is the standard format for Erlang
application configuration.
"""
@type sys_config :: [{application(), keyword()}]
@default_apps [kernel: :permanent, stdlib: :permanent, elixir: :permanent, sasl: :permanent]
@safe_modes [:permanent, :temporary, :transient]
@unsafe_modes [:load, :none]
@@ -445,7 +462,7 @@ defmodule Mix.Release do
In case there are no config providers, it doesn't change `sys_config`.
"""
@spec make_sys_config(t, keyword(), Config.Provider.config_path()) ::
@spec make_sys_config(t, sys_config(), Config.Provider.config_path()) ::
:ok | {:error, String.t()}
def make_sys_config(release, sys_config, config_provider_path) do
{sys_config, runtime_config?} =
@@ -900,8 +917,26 @@ defmodule Mix.Release do
The exact chunks that are kept are not documented and may change in
future versions.
## Options
* `:keep` - a list of additional chunk names (as strings) to keep in the
stripped BEAM file. These will be added to the significant chunks
determined by `:beam_lib.significant_chunks/0`
* `:compress` - when `true`, the resulting BEAM file will be compressed
using gzip. Defaults to `false`
## Examples
# Strip with default options
Mix.Release.strip_beam(beam_binary)
# Keep additional chunks and compress
Mix.Release.strip_beam(beam_binary, keep: ["Docs", "ChunkName"], compress: true)
"""
@spec strip_beam(binary(), keyword()) :: {:ok, binary()} | {:error, :beam_lib, term()}
@spec strip_beam(binary(), strip_beam_opts()) :: {:ok, binary()} | {:error, :beam_lib, term()}
def strip_beam(binary, options \\ []) when is_list(options) do
chunks_to_keep = options[:keep] |> List.wrap() |> Enum.map(&String.to_charlist/1)
all_chunks = Enum.uniq(@additional_chunks ++ :beam_lib.significant_chunks() ++ chunks_to_keep)
+26 -3
View File
@@ -7,6 +7,29 @@ defmodule Mix.Shell do
Defines `Mix.Shell` contract.
"""
@type cmd_opts :: [
{:print_app, boolean()}
| {:stderr_to_stdout, boolean()}
| {:quiet, boolean()}
| {:env, [{String.t(), String.t()}]}
| {:cd, String.t()}
| {atom(), term()}
]
@type yes_opts :: [
{:default, :yes | :no}
| {atom(), term()}
]
@type stream_cmd_opts :: [
{:cd, String.t()}
| {:stderr_to_stdout, boolean()}
| {:use_stdio, boolean()}
| {:env, [{String.t(), String.t()}]}
| {:quiet, boolean()}
| {atom(), term()}
]
@doc false
defstruct [:callback]
@@ -48,7 +71,7 @@ defmodule Mix.Shell do
All the built-in shells support these.
"""
@callback cmd(command :: String.t(), options :: keyword) :: integer
@callback cmd(command :: String.t(), options :: cmd_opts) :: integer
@doc """
Prompts the user for input.
@@ -69,7 +92,7 @@ defmodule Mix.Shell do
* `:default` - `:yes` or `:no` (the default is `:yes`)
"""
@callback yes?(message :: binary, options :: keyword) :: boolean
@callback yes?(message :: binary, options :: yes_opts) :: boolean
@doc """
Prints the current application to the shell if
@@ -117,7 +140,7 @@ defmodule Mix.Shell do
* `:quiet` - overrides the callback to no-op
"""
@spec cmd(String.t() | {String.t(), [String.t()]}, keyword, (binary -> term)) ::
@spec cmd(String.t() | {String.t(), [String.t()]}, stream_cmd_opts, (binary -> term)) ::
exit_status :: non_neg_integer
def cmd(command, options \\ [], callback) when is_function(callback, 1) do
callback =
+6
View File
@@ -11,6 +11,11 @@ defmodule Mix.Shell.IO do
@behaviour Mix.Shell
@typedoc """
Options for `yes?/2`.
"""
@type yes_opts :: [default: :yes | :no]
@doc """
Prints the current application to the shell if it
was not printed yet.
@@ -72,6 +77,7 @@ defmodule Mix.Shell.IO do
end
"""
@spec yes?(String.t(), yes_opts) :: boolean()
def yes?(message, options \\ []) do
default = Keyword.get(options, :default, :yes)
+3
View File
@@ -52,11 +52,14 @@ defmodule Mix.Shell.Quiet do
the prompt instead. Defaults to `:yes`.
"""
@spec yes?(String.t(), Mix.Shell.IO.yes_opts()) :: boolean()
defdelegate yes?(message, options \\ []), to: Mix.Shell.IO
@doc """
Executes the given command quietly without outputting anything.
"""
@spec cmd(String.t() | {String.t(), [String.t()]}, Mix.Shell.stream_cmd_opts()) ::
exit_status :: non_neg_integer
def cmd(command, opts \\ []) do
Mix.Shell.cmd(command, opts, fn data -> data end)
end
+8 -1
View File
@@ -73,6 +73,13 @@ defmodule Mix.Sync.Lock do
@probe_data_size byte_size(@probe_data)
@probe_timeout_ms 5_000
@typedoc """
Options for `with_lock/3`.
"""
@type with_lock_opts :: [
on_taken: (String.t() -> any())
]
@doc """
Acquires a lock identified by the given key.
@@ -95,7 +102,7 @@ defmodule Mix.Sync.Lock do
is successfully acquired by this process.
"""
@spec with_lock(iodata(), (-> term()), keyword()) :: term()
@spec with_lock(iodata(), (-> term()), with_lock_opts()) :: term()
def with_lock(key, fun, opts \\ []) do
opts = Keyword.validate!(opts, [:on_taken])
+65 -3
View File
@@ -223,15 +223,55 @@ defmodule Mix.Tasks.Format do
ins: [text: :green, space: :green_background]
]
@typedoc """
Options passed to plugin `features/1` callback.
These are the same formatter options from `.formatter.exs` configuration,
allowing plugins to access formatting settings when determining their capabilities.
"""
@type features_opts :: [
inputs: [String.t()],
plugins: [module()],
subdirectories: [String.t()],
import_deps: [atom()],
export: keyword(),
locals_without_parens: keyword(),
line_length: pos_integer(),
normalize_bitstring_modifiers: boolean(),
normalize_charlists_as_binaries: boolean()
]
@typedoc """
Options passed to plugin `format/2` callback.
These options include context-specific information about what is being formatted
(sigil, extension, file) along with all the standard formatter configuration options.
"""
@type format_opts :: [
{:sigil, atom()}
| {:modifiers, charlist()}
| {:extension, String.t()}
| {:file, String.t()}
| {:inputs, [String.t()]}
| {:plugins, [module()]}
| {:subdirectories, [String.t()]}
| {:import_deps, [atom()]}
| {:export, keyword()}
| {:locals_without_parens, keyword()}
| {:line_length, pos_integer()}
| {:normalize_bitstring_modifiers, boolean()}
| {:normalize_charlists_as_binaries, boolean()}
]
@doc """
Returns which features this plugin should plug into.
"""
@callback features(Keyword.t()) :: [sigils: [atom()], extensions: [binary()]]
@callback features(features_opts) :: [sigils: [atom()], extensions: [binary()]]
@doc """
Receives a string to be formatted with options and returns said string.
"""
@callback format(String.t(), Keyword.t()) :: String.t()
@callback format(String.t(), format_opts) :: String.t()
@impl true
def run(all_args) do
@@ -356,6 +396,16 @@ defmodule Mix.Tasks.Format do
plugins
end
@typedoc """
Options for `formatter_for_file/2`.
"""
@type formatter_for_file_opts :: [
deps_paths: %{atom() => String.t()},
dot_formatter: String.t(),
plugin_loader: ([module()] -> [module()]),
root: String.t()
]
@doc """
Returns a formatter function and the formatter options to
be used for the given file.
@@ -389,6 +439,8 @@ defmodule Mix.Tasks.Format do
* `:root` - use the given root as the current working directory.
"""
@doc since: "1.13.0"
@spec formatter_for_file(String.t(), formatter_for_file_opts) ::
{(String.t() -> String.t()), keyword()}
def formatter_for_file(file, opts \\ []) do
cwd = Keyword.get_lazy(opts, :root, &File.cwd!/0)
{dot_formatter, formatter_opts} = eval_dot_formatter(cwd, opts)
@@ -809,8 +861,18 @@ defmodule Mix.Tasks.Format do
end)
end
@typedoc """
Options for `text_diff_format/3`.
"""
@type text_diff_format_opts :: [
after: non_neg_integer(),
before: non_neg_integer(),
color: boolean(),
line: pos_integer()
]
@doc false
@spec text_diff_format(String.t(), String.t()) :: iolist()
@spec text_diff_format(String.t(), String.t(), text_diff_format_opts) :: iolist()
def text_diff_format(old, new, opts \\ [])
def text_diff_format(code, code, _opts), do: []
+10 -1
View File
@@ -95,6 +95,15 @@ defmodule Mix.Tasks.Profile.Cprof do
(for example, 2147483647 in a 32-bit host).
"""
@typedoc """
Options for the cprof profiler.
"""
@type profile_opts :: [
matching: {module() | :_, atom() | :_, arity() | :_},
limit: non_neg_integer(),
module: module()
]
@switches [
parallel: :boolean,
require: :keep,
@@ -172,7 +181,7 @@ defmodule Mix.Tasks.Profile.Cprof do
* `:module` - filters out any results not pertaining to the given module
"""
@spec profile((-> result), keyword()) :: result when result: any()
@spec profile((-> result), profile_opts()) :: result when result: any()
def profile(fun, opts \\ []) when is_function(fun, 0) do
Mix.ensure_application!(:tools)
{return_value, num_matched_functions, analysis_result} = profile_and_analyse(fun, opts)
+13 -1
View File
@@ -101,6 +101,18 @@ defmodule Mix.Tasks.Profile.Eprof do
`Mix.Tasks.Profile.Cprof` that uses [`:cprof`](`:cprof`) and has a low performance degradation effect.
"""
@typedoc """
Options for the eprof profiler.
"""
@type profile_opts :: [
matching: {module() | :_, atom() | :_, arity() | :_},
calls: non_neg_integer(),
time: non_neg_integer(),
sort: :time | :calls,
warmup: boolean(),
set_on_spawn: boolean()
]
@switches [
parallel: :boolean,
require: :keep,
@@ -189,7 +201,7 @@ defmodule Mix.Tasks.Profile.Eprof do
* `:set_on_spawn` - if newly spawned processes should be measured (default: `true`)
"""
@spec profile((-> result), keyword()) :: result when result: any()
@spec profile((-> result), profile_opts()) :: result when result: any()
def profile(fun, opts \\ []) when is_function(fun, 0) do
Mix.ensure_application!(:tools)
{return_value, results} = profile_and_analyse(fun, opts)
+11 -1
View File
@@ -114,6 +114,16 @@ defmodule Mix.Tasks.Profile.Fprof do
this should provide more realistic insights into bottlenecks.
"""
@typedoc """
Options for the fprof profiler.
"""
@type profile_opts :: [
callers: boolean(),
details: boolean(),
sort: :acc | :own,
trace_to_file: boolean()
]
@switches [
parallel: :boolean,
require: :keep,
@@ -184,7 +194,7 @@ defmodule Mix.Tasks.Profile.Fprof do
usage for larger workloads.
"""
@spec profile((-> result), keyword()) :: result when result: any()
@spec profile((-> result), profile_opts()) :: result when result: any()
def profile(fun, opts \\ []) when is_function(fun, 0) do
Mix.ensure_application!(:runtime_tools)
Mix.ensure_application!(:tools)
+16 -1
View File
@@ -144,6 +144,21 @@ defmodule Mix.Tasks.Profile.Tprof do
which is more limited but has a lower footprint.
"""
@typedoc """
Options for the tprof profiler.
"""
@type profile_opts :: [
matching: {module() | :_, atom() | :_, arity() | :_},
type: :time | :memory | :calls,
calls: non_neg_integer(),
time: non_neg_integer(),
memory: non_neg_integer(),
sort: :calls | :per_call | :time | :memory,
report: :process | :total,
warmup: boolean(),
set_on_spawn: boolean()
]
@switches [
parallel: :boolean,
require: :keep,
@@ -260,7 +275,7 @@ defmodule Mix.Tasks.Profile.Tprof do
* `:set_on_spawn` - if newly spawned processes should be measured (default: `true`)
"""
@spec profile((-> result), keyword()) :: result when result: any()
@spec profile((-> result), profile_opts()) :: result when result: any()
def profile(fun, opts \\ []) when is_function(fun, 0) do
Mix.ensure_application!(:tools)
{type, return_value, results} = profile_and_analyse(fun, opts)
+14 -1
View File
@@ -65,6 +65,19 @@ defmodule Mix.Tasks.Run do
"""
@typedoc """
Options for the internal `run/5` function.
These options are typically parsed from command-line arguments.
"""
@type run_opts :: [
{:parallel_require, String.t()}
| {:eval, String.t()}
| {:require, String.t()}
| {:parallel, boolean()}
| {:config, String.t()}
]
@impl true
def run(args) do
{opts, head} =
@@ -99,7 +112,7 @@ defmodule Mix.Tasks.Run do
@doc false
@spec run(
OptionParser.argv(),
keyword,
run_opts,
OptionParser.argv(),
(String.t() -> term()),
(String.t() -> term())
+28 -5
View File
@@ -276,7 +276,7 @@ defmodule Mix.Utils do
Returns the name of the file written to, or "-" if the output was to STDOUT.
This function is made public mostly for testing.
"""
@spec write_according_to_opts!(Path.t(), iodata(), keyword) :: Path.t()
@spec write_according_to_opts!(Path.t(), iodata(), write_opts) :: Path.t()
def write_according_to_opts!(default_file_spec, contents, opts) do
file_spec = Keyword.get(opts, :output, default_file_spec)
@@ -305,7 +305,7 @@ defmodule Mix.Utils do
If the `:output` option is `-` then prints to standard output,
see write_according_to_opts!/3 for details.
"""
@spec write_json_tree!(Path.t(), [node], (node -> {formatted_node, [node]}), keyword) ::
@spec write_json_tree!(Path.t(), [node], (node -> {formatted_node, [node]}), write_opts) ::
Path.t()
when node: term()
def write_json_tree!(default_file_spec, nodes, callback, opts \\ []) do
@@ -336,13 +336,36 @@ defmodule Mix.Utils do
@type formatted_node :: {name :: String.Chars.t(), edge_info :: String.Chars.t()}
@typedoc """
Options for `write_according_to_opts!/3`, `write_json_tree!/4`, and `write_dot_graph!/5`.
"""
@type write_opts :: [
output: String.t()
]
@typedoc """
Options for `print_tree/3`.
"""
@type print_tree_opts :: [
format: String.t()
]
@typedoc """
Options for `read_path/2`.
"""
@type read_path_opts :: [
timeout: pos_integer(),
sha512: String.t()
]
@doc """
Prints the given tree according to the callback.
The callback will be invoked for each node and it
must return a `{printed, children}` tuple.
"""
@spec print_tree([node], (node -> {formatted_node, [node]}), keyword) :: :ok when node: term()
@spec print_tree([node], (node -> {formatted_node, [node]}), print_tree_opts) :: :ok
when node: term()
def print_tree(nodes, callback, opts \\ []) do
pretty? =
case Keyword.get(opts, :format) do
@@ -414,7 +437,7 @@ defmodule Mix.Utils do
String.t(),
[node],
(node -> {formatted_node, [node]}),
keyword
write_opts
) :: Path.t()
when node: term()
def write_dot_graph!(default_file_spec, title, nodes, callback, opts \\ []) do
@@ -632,7 +655,7 @@ defmodule Mix.Utils do
seconds
"""
@spec read_path(String.t(), keyword) ::
@spec read_path(String.t(), read_path_opts) ::
{:ok, binary}
| :badpath
| {:remote, String.t()}