Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/elixir/lib/io/ansi/docs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ defmodule IO.ANSI.Docs do
end

@doc """
Prints documentation metadata (only `since` and `deprecated` for now).
Prints documentation metadata (only `delegate_to`, `deprecated`, `guard`, and `since` for now).

See `default_options/0` for docs on the supported options.
"""
Expand All @@ -78,6 +78,10 @@ defmodule IO.ANSI.Docs do
{key, value}, _printed when is_boolean(value) and key in @metadata_filter ->
IO.puts([metadata_label(key, options), ' ', to_string(value)])

{:delegate_to, {m, f, a}}, _printed ->
label = metadata_label(:delegate_to, options)
IO.puts([label, ' ', Exception.format_mfa(m, f, a)])

_metadata, printed ->
printed
end)
Expand Down
2 changes: 2 additions & 0 deletions lib/elixir/lib/kernel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5021,6 +5021,8 @@ defmodule Kernel do
for fun <- List.wrap(funs) do
{name, args, as, as_args} = Kernel.Utils.defdelegate(fun, opts)

@doc delegate_to: {target, as, :erlang.length(as_args)}

def unquote(name)(unquote_splicing(args)) do
unquote(target).unquote(as)(unquote_splicing(as_args))
end
Expand Down
12 changes: 12 additions & 0 deletions lib/elixir/lib/module.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,18 @@ defmodule Module do
"representing the replacement for the deprecated entity, got: #{inspect(value)}"
end

defp validate_doc_meta(:delegate_to, value) do
case value do
{m, f, a} when is_atom(m) and is_atom(f) and is_integer(a) and a >= 0 ->
:ok

_ ->
raise ArgumentError,
":delegate_to is a built-in documentation metadata key. It should be a three-element " <>
"tuple in the form of {module, function, arity}, got: #{inspect(value)}"
end
end

defp validate_doc_meta(_, _), do: :ok

defp get_doc_info(table, env) do
Expand Down
17 changes: 15 additions & 2 deletions lib/elixir/test/elixir/io/ansi/docs_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,21 @@ defmodule IO.ANSI.DocsTest do
end

test "metadata is formatted" do
result = format_metadata(%{since: "1.2.3", deprecated: "Use that other one", author: "Alice"})
assert result == "\e[33mdeprecated:\e[0m Use that other one\n\e[33msince:\e[0m 1.2.3\n\n"
result =
format_metadata(%{
since: "1.2.3",
deprecated: "Use that other one",
author: "Alice",
delegate_to: {Foo, :bar, 3}
})

assert result == """
\e[33mdelegate_to:\e[0m Foo.bar/3
\e[33mdeprecated:\e[0m Use that other one
\e[33msince:\e[0m 1.2.3

"""

assert format_metadata(%{author: "Alice"}) == ""
end

Expand Down
28 changes: 28 additions & 0 deletions lib/iex/test/iex/helpers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,34 @@ defmodule IEx.HelpersTest do
cleanup_modules([Impl, MyBehaviour])
end

test "prints documentation for delegates" do
filename = "delegate.ex"

content = """
defmodule Delegator do
defdelegate func1, to: Delegated
@doc "Delegator func2 doc"
defdelegate func2, to: Delegated
end
defmodule Delegated do
def func1, do: 1
def func2, do: 2
end
"""

with_file(filename, content, fn ->
assert c(filename, ".") |> Enum.sort() == [Delegated, Delegator]

assert capture_io(fn -> h(Delegator.func1()) end) ==
"* def func1()\n\ndelegate_to: Delegated.func1/0\n\n\n"

assert capture_io(fn -> h(Delegator.func2()) end) ==
"* def func2()\n\ndelegate_to: Delegated.func2/0\n\nDelegator func2 doc\n"
end)
after
cleanup_modules([Delegated, Delegator])
end

test "prints type documentation when function docs are not available" do
content = """
defmodule MyTypes do
Expand Down