Compare commits

...
8 Commits
Author SHA1 Message Date
José Valim 1164784b8e Release v1.7.0-rc.0 2018-07-13 14:43:27 +02:00
José Valim 6694ddbd2f Properly add parens around when with keywords as argument 2018-07-13 00:07:26 +02:00
José Valim 85a4d55efb Update CHANGELOG 2018-07-12 20:28:19 +02:00
Arkadiusz Gil 9b238e0316 Ignore unknown child info in Logger.Translator (#7892)
This prevents Logger application from crashing when supervisors report
children progress with fields unknown to Logger.Translator.

Closes #7889

Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2018-07-12 20:15:08 +02:00
László Bácsi ca82388792 Show documentation metadata in IEx (only since and deprecated for now) (#7886) 2018-07-12 20:07:45 +02:00
Lukasz Samson b33dd12d86 Fix error when :trim_bom is used with :encoding
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2018-07-12 14:37:14 +02:00
Dimitrios Zorbas c36b2c9070 Fix syntax highlighting of Calendar.ISO docs (#7880)
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
2018-07-12 12:44:41 +02:00
José Valim ac75cdbe05 Prepare for v1.7 release 2018-07-12 11:57:29 +02:00
17 changed files with 302 additions and 74 deletions
+19 -1
View File
@@ -2,6 +2,21 @@
Elixir v1.7 is the last release to support Erlang/OTP 19. We recommend everyone to migrate to Erlang/OTP 20+.
## Documentation metadata
Elixir v1.7 implements [EEP 48](http://erlang.org/eep/eeps/eep-0048.html). EEP 48 aims to bring documentation interoperability across all languages running on the Erlang VM. The documentation format proposed by EEP 48 also supports metadata, which is now fully exposed to Elixir developers:
```elixir
@moduledoc "A brand new module"
@moduledoc authors: ["Jane", "Mary"], since: "1.4.0"
```
Currently Elixir supports two metadata keys: `:deprecated` and `:since`. Other keys will be added in the future. Passing metadata is supported on `@doc`, `@moduledoc` and `@typedoc`.
To access the new documentation, developers should use `Code.fetch_docs/1`. The old documentation format is no longer available and the old `Code.get_docs/1` function will return `nil` accordingly.
Tools like IEx and ExDoc have been updated to leverage the new format and show relevant metadata to users.
## The `__STACKTRACE__` construct
Erlang/OTP 21.0 introduces a new way to retrieve the stacktrace that is lexically scoped and no longer relies on side-effects like `System.stacktrace/0` does. Before one would write:
@@ -101,7 +116,7 @@ Percentage | Module
77.19% | Total
```
## v1.7.0-dev
## v1.7.0-rc.0 (2018-07-13)
### 1. Enhancements
@@ -119,6 +134,7 @@ Percentage | Module
* [Function] Add `Function` module with `capture/3`, `info/1` and `info/2` functions
* [GenServer] Support the new `handle_continue/2` callback on Erlang/OTP 21+
* [IO.ANSI] Add cursor movement to `IO.ANSI`
* [Kernel] Support adding arbitrary documentation metadata by passing a keyword list to `@doc`, `@moduledoc` and `@typedoc`
* [Kernel] Introduce `__STACKTRACE__` to retrieve the current stacktrace inside `catch`/`rescue` (this will be a requirement for Erlang/OTP 21+)
* [Kernel] Raise on unsafe variables in order to allow us to better track unused variables
* [Kernel] Warn when using `length` to check if a list is not empty on guards
@@ -146,6 +162,7 @@ Percentage | Module
* [IEx.Helpers] Add `use_if_available/2`
* [IEx.Helpers] Allow `force: true` option in `recompile/1`
* [IEx.Helpers] Add `:allocators` pane to `runtime_info/1`
* [IEx.Helpers] Show documentation metadata in `h/1` helpers
#### Logger
@@ -179,6 +196,7 @@ Percentage | Module
* [Code] Ensure `string_to_quoted` returns error tuples instead of raising in certain constructs
* [Code.Formatter] Consistently format keyword lists in function calls with and without parens
* [Code.Formatter] Do not break after `->` when there are only comments and one-line clauses
* [File] Allow the `:trim_bom` option to be used with `:encoding`
* [Kernel] Raise on unsafe variables as some of the code emitted with unsafe variables would not correctly propagate variables or would disable tail call optimization semantics
* [Kernel] Do not crash on dynamic sizes in binary generators with collectable into in comprehensions
* [Kernel] Do not crash on literals with non-unary size in binary generators with collectable into in comprehensions
+1 -1
View File
@@ -1,6 +1,6 @@
PREFIX ?= /usr/local
SHARE_PREFIX ?= $(PREFIX)/share
CANONICAL := master/
CANONICAL := v1.7/
ELIXIRC := bin/elixirc --verbose --ignore-module-conflict
ERLC := erlc -I lib/elixir/include
ERL := erl -I lib/elixir/include -noshell -pa lib/elixir/ebin
+1 -1
View File
@@ -1 +1 @@
1.7.0-dev
1.7.0-rc.0
+32 -32
View File
@@ -351,12 +351,12 @@ defmodule Calendar.ISO do
## Examples
iex> Calendar.ISO.date_to_string(2015, 2, 28)
"2015-02-28"
iex> Calendar.ISO.date_to_string(2017, 8, 1)
"2017-08-01"
iex> Calendar.ISO.date_to_string(-99, 1, 31)
"-0099-01-31"
iex> Calendar.ISO.date_to_string(2015, 2, 28)
"2015-02-28"
iex> Calendar.ISO.date_to_string(2017, 8, 1)
"2017-08-01"
iex> Calendar.ISO.date_to_string(-99, 1, 31)
"-0099-01-31"
"""
@spec date_to_string(year, month, day) :: String.t()
@@ -378,10 +378,10 @@ defmodule Calendar.ISO do
## Examples
iex> Calendar.ISO.naive_datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 6})
"2015-02-28 01:02:03.000004"
iex> Calendar.ISO.naive_datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5})
"2017-08-01 01:02:03.00000"
iex> Calendar.ISO.naive_datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 6})
"2015-02-28 01:02:03.000004"
iex> Calendar.ISO.naive_datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5})
"2017-08-01 01:02:03.00000"
"""
@impl true
@@ -403,14 +403,14 @@ defmodule Calendar.ISO do
## Examples
iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, "Europe/Berlin", "CET", 3600, 0)
"2017-08-01 01:02:03.00000+01:00 CET Europe/Berlin"
iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, "Europe/Berlin", "CDT", 3600, 3600)
"2017-08-01 01:02:03.00000+02:00 CDT Europe/Berlin"
iex> Calendar.ISO.datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 5}, "America/Los_Angeles", "PST", -28800, 0)
"2015-02-28 01:02:03.00000-08:00 PST America/Los_Angeles"
iex> Calendar.ISO.datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 5}, "America/Los_Angeles", "PDT", -28800, 3600)
"2015-02-28 01:02:03.00000-07:00 PDT America/Los_Angeles"
iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, "Europe/Berlin", "CET", 3600, 0)
"2017-08-01 01:02:03.00000+01:00 CET Europe/Berlin"
iex> Calendar.ISO.datetime_to_string(2017, 8, 1, 1, 2, 3, {4, 5}, "Europe/Berlin", "CDT", 3600, 3600)
"2017-08-01 01:02:03.00000+02:00 CDT Europe/Berlin"
iex> Calendar.ISO.datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 5}, "America/Los_Angeles", "PST", -28800, 0)
"2015-02-28 01:02:03.00000-08:00 PST America/Los_Angeles"
iex> Calendar.ISO.datetime_to_string(2015, 2, 28, 1, 2, 3, {4, 5}, "America/Los_Angeles", "PDT", -28800, 3600)
"2015-02-28 01:02:03.00000-07:00 PDT America/Los_Angeles"
"""
@impl true
@@ -452,14 +452,14 @@ defmodule Calendar.ISO do
## Examples
iex> Calendar.ISO.valid_date?(2015, 2, 28)
true
iex> Calendar.ISO.valid_date?(2015, 2, 30)
false
iex> Calendar.ISO.valid_date?(-1, 12, 31)
true
iex> Calendar.ISO.valid_date?(-1, 12, 32)
false
iex> Calendar.ISO.valid_date?(2015, 2, 28)
true
iex> Calendar.ISO.valid_date?(2015, 2, 30)
false
iex> Calendar.ISO.valid_date?(-1, 12, 31)
true
iex> Calendar.ISO.valid_date?(-1, 12, 32)
false
"""
@doc since: "1.5.0"
@@ -476,12 +476,12 @@ defmodule Calendar.ISO do
## Examples
iex> Calendar.ISO.valid_time?(10, 50, 25, {3006, 6})
true
iex> Calendar.ISO.valid_time?(23, 59, 60, {0, 0})
true
iex> Calendar.ISO.valid_time?(24, 0, 0, {0, 0})
false
iex> Calendar.ISO.valid_time?(10, 50, 25, {3006, 6})
true
iex> Calendar.ISO.valid_time?(23, 59, 60, {0, 0})
true
iex> Calendar.ISO.valid_time?(24, 0, 0, {0, 0})
false
"""
@doc since: "1.5.0"
+15 -8
View File
@@ -716,14 +716,21 @@ defmodule Code.Formatter do
{concat(op_string, doc), @empty, newlines, state}
end
operand_to_algebra_with_comments(
operands,
meta,
min_line,
max_line,
state,
operand_to_algebra
)
{doc, state} =
operand_to_algebra_with_comments(
operands,
meta,
min_line,
max_line,
state,
operand_to_algebra
)
if keyword?(right_arg) and context in [:parens_arg, :no_parens_arg] do
{wrap_in_parens(doc), state}
else
{doc, state}
end
end
defp binary_op_to_algebra(op, _, meta, left_arg, right_arg, context, state, _nesting)
+5 -1
View File
@@ -1512,7 +1512,8 @@ defmodule File do
in raw mode for performance reasons. Therefore, Elixir **will** open
streams in `:raw` mode with the `:read_ahead` option unless an encoding
is specified. This means any data streamed into the file must be
converted to `t:iodata/0` type. If you pass `[:utf8]` in the modes parameter,
converted to `t:iodata/0` type. If you pass e.g. `[encoding: :utf8]`
or `[encoding: {:utf16, :little}]` in the modes parameter,
the underlying stream will use `IO.write/2` and the `String.Chars` protocol
to convert the data. See `IO.binwrite/2` and `IO.write/2` .
@@ -1524,6 +1525,9 @@ defmodule File do
If you pass `:trim_bom` in the modes parameter, the stream will
trim UTF-8, UTF-16 and UTF-32 byte order marks when reading from file.
Note that this function does not try to discover the file encoding basing
on BOM.
## Examples
# Read in 2048 byte chunks rather than lines
+15 -3
View File
@@ -140,12 +140,24 @@ defmodule File.Stream do
end
end
defp trim_bom(device, raw) do
header = if raw, do: IO.binread(device, 4), else: IO.read(device, 1)
{:ok, new_pos} = :file.position(device, bom_length(header))
defp trim_bom(device, true) do
bom_length = device |> IO.binread(4) |> bom_length()
{:ok, new_pos} = :file.position(device, bom_length)
{device, new_pos}
end
defp trim_bom(device, false) do
# Or we read the bom in the correct amount or it isn't there
case bom_length(IO.read(device, 1)) do
0 ->
{:ok, _} = :file.position(device, 0)
{device, 0}
_ ->
{device, 1}
end
end
defp bom_length(<<239, 187, 191, _rest::binary>>), do: 3
defp bom_length(<<254, 255, _rest::binary>>), do: 2
defp bom_length(<<255, 254, _rest::binary>>), do: 2
+36 -1
View File
@@ -7,12 +7,13 @@ defmodule IO.ANSI.Docs do
@doc """
The default options used by this module.
The supported values are:
The supported keys are:
* `:enabled` - toggles coloring on and off (true)
* `:doc_bold` - bold text (bright)
* `:doc_code` - code blocks (cyan)
* `:doc_headings` - h1, h2, h3, h4, h5, h6 headings (yellow)
* `:doc_metadata` - documentation metadata keys (yellow)
* `:doc_inline_code` - inline code (cyan)
* `:doc_table_heading` - the style for table headings
* `:doc_title` - top level heading (reverse, yellow)
@@ -29,6 +30,7 @@ defmodule IO.ANSI.Docs do
doc_bold: [:bright],
doc_code: [:cyan],
doc_headings: [:yellow],
doc_metadata: [:yellow],
doc_inline_code: [:cyan],
doc_table_heading: [:reverse],
doc_title: [:reverse, :yellow],
@@ -53,6 +55,39 @@ defmodule IO.ANSI.Docs do
newline_after_block()
end
@doc """
Prints documentation metadata (only `since` and `deprecated` for now).
See `default_options/0` for docs on the supported options.
"""
@spec print_metadata(map, keyword) :: :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")
end
@metadata_filter [:deprecated, :since]
defp print_each_metadata(metadata, options) do
Enum.reduce(metadata, false, fn
{key, value}, _printed when is_binary(value) and key in @metadata_filter ->
label = metadata_label(key, options)
indent = String.duplicate(" ", length_without_escape(label, 0) + 1)
write_with_wrap([label | String.split(value, @spaces)], options[:width], indent, true)
_metadata, printed ->
printed
end)
end
defp metadata_label(key, options) do
if options[:enabled] do
"#{color(:doc_metadata, options)}#{key}:#{IO.ANSI.reset()}"
else
"#{key}:"
end
end
@doc """
Prints the documentation body.
@@ -136,4 +136,4 @@ Non-map as second argument in `URI.decode_query/2` | [v1.3] | Use a map (v1
[v1.4]: https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#4-deprecations
[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations
[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations
[v1.7]: https://github.com/elixir-lang/elixir/blob/master/CHANGELOG.md#4-hard-deprecations
[v1.7]: https://github.com/elixir-lang/elixir/blob/v1.7/CHANGELOG.md#4-hard-deprecations
@@ -447,6 +447,20 @@ defmodule Code.Formatter.IntegrationTest do
"""
end
test "when with keywords inside call" do
assert_same """
quote((bar(foo(1)) when bat: foo(1)), [])
"""
assert_same """
quote(do: (bar(foo(1)) when bat: foo(1)), line: 1)
"""
assert_same """
typespec(quote(do: (bar(foo(1)) when bat: foo(1))), [foo: 1], [])
"""
end
test "capture with operators" do
assert_same """
"this works" |> (&String.upcase/1) |> (&String.downcase/1)
+44 -4
View File
@@ -1569,11 +1569,11 @@ defmodule FileTest do
src = fixture_path("utf8_bom.txt")
assert src
|> File.stream!([:utf8])
|> File.stream!([{:encoding, :utf8}])
|> Enum.take(1) == [<<239, 187, 191>> <> "Русский\n"]
assert src
|> File.stream!([:utf8], 1)
|> File.stream!([{:encoding, :utf8}], 1)
|> Enum.take(9) == ["\uFEFF", "Р", "у", "с", "с", "к", "и", "й", "\n"]
end
@@ -1581,11 +1581,51 @@ defmodule FileTest do
src = fixture_path("utf8_bom.txt")
assert src
|> File.stream!([:utf8, :trim_bom])
|> File.stream!([{:encoding, :utf8}, :trim_bom])
|> Enum.take(1) == ["Русский\n"]
assert src
|> File.stream!([:utf8, :trim_bom], 1)
|> File.stream!([{:encoding, :utf8}, :trim_bom], 1)
|> Enum.take(8) == ["Р", "у", "с", "с", "к", "и", "й", "\n"]
end
test "keeps BOM with UTF16 BE" do
src = fixture_path("utf16_be_bom.txt")
assert src
|> File.stream!([{:encoding, {:utf16, :big}}])
|> Enum.take(1) == ["\uFEFFРусский\n"]
end
test "keeps BOM with UTF16 LE" do
src = fixture_path("utf16_le_bom.txt")
assert src
|> File.stream!([{:encoding, {:utf16, :little}}])
|> Enum.take(1) == ["\uFEFFРусский\n"]
end
test "trims BOM via option with utf16 BE encoding" do
src = fixture_path("utf16_be_bom.txt")
assert src
|> File.stream!([{:encoding, {:utf16, :big}}, :trim_bom])
|> Enum.take(1) == ["Русский\n"]
assert src
|> File.stream!([{:encoding, {:utf16, :big}}, :trim_bom], 1)
|> Enum.take(8) == ["Р", "у", "с", "с", "к", "и", "й", "\n"]
end
test "trims BOM via option with utf16 LE encoding" do
src = fixture_path("utf16_le_bom.txt")
assert src
|> File.stream!([{:encoding, {:utf16, :little}}, :trim_bom])
|> Enum.take(1) == ["Русский\n"]
assert src
|> File.stream!([{:encoding, {:utf16, :little}}, :trim_bom], 1)
|> Enum.take(8) == ["Р", "у", "с", "с", "к", "и", "й", "\n"]
end
Binary file not shown.
Binary file not shown.
@@ -8,6 +8,10 @@ defmodule IO.ANSI.DocsTest do
capture_io(fn -> IO.ANSI.Docs.print_heading(str, []) end) |> String.trim_trailing()
end
def format_metadata(map) do
capture_io(fn -> IO.ANSI.Docs.print_metadata(map, []) end)
end
def format(str) do
capture_io(fn -> IO.ANSI.Docs.print(str, []) end) |> String.trim_trailing()
end
@@ -19,6 +23,12 @@ defmodule IO.ANSI.DocsTest do
assert String.contains?(result, " wibble ")
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"
assert format_metadata(%{author: "Alice"}) == ""
end
test "first level heading is converted" do
result = format("# wibble\n\ntext\n")
assert result == "\e[33m# wibble\e[0m\n\e[0m\ntext\n\e[0m"
+25 -21
View File
@@ -250,8 +250,8 @@ defmodule IEx.Introspection do
case Code.ensure_loaded(module) do
{:module, _} ->
case Code.fetch_docs(module) do
{:docs_v1, _, _, _, %{} = doc, _, _} ->
print_doc(inspect(module), [], doc)
{:docs_v1, _, _, _, %{} = doc, metadata, _} ->
print_doc(inspect(module), [], doc, metadata)
{:docs_v1, _, _, _, _, _, _} ->
docs_not_found(inspect(module))
@@ -376,7 +376,7 @@ defmodule IEx.Introspection do
is_nil(docs) and spec != [] ->
message = %{"en" => "Module was compiled without docs. Showing only specs."}
print_doc("#{inspect(mod)}.#{fun}/#{arity}", spec, message)
print_doc("#{inspect(mod)}.#{fun}/#{arity}", spec, message, %{})
:ok
is_nil(docs) ->
@@ -449,7 +449,7 @@ defmodule IEx.Introspection do
defp has_content?({{_, name, _}, _, _, :none, _}), do: hd(Atom.to_charlist(name)) != ?_
defp has_content?({_, _, _, _, _}), do: true
defp print_fun(mod, {{kind, fun, arity}, _line, signature, doc, _meta}, spec) do
defp print_fun(mod, {{kind, fun, arity}, _line, signature, doc, metadata}, spec) do
if callback_module = doc == :none and callback_module(mod, fun, arity) do
filter = &match?({_, ^fun, ^arity}, elem(&1, 0))
@@ -458,7 +458,7 @@ defmodule IEx.Introspection do
_ -> nil
end
else
print_doc("#{kind_to_def(kind)} #{Enum.join(signature, " ")}", spec, doc)
print_doc("#{kind_to_def(kind)} #{Enum.join(signature, " ")}", spec, doc, metadata)
end
end
@@ -513,7 +513,7 @@ defmodule IEx.Introspection do
{:ok, docs} ->
docs
|> add_optional_callback_docs(mod)
|> Enum.each(fn {definition, _} -> IO.puts(definition) end)
|> Enum.each(fn {definition, _, _} -> IO.puts(definition) end)
end
dont_display_result()
@@ -565,12 +565,12 @@ defmodule IEx.Introspection do
docs
|> Enum.filter(filter)
|> Enum.map(fn
{{:macrocallback, fun, arity}, _, _, doc, _} ->
{{:macrocallback, fun, arity}, _, _, doc, metadata} ->
macro = {:"MACRO-#{fun}", arity + 1}
{format_callback(:macrocallback, fun, macro, callbacks), doc}
{format_callback(:macrocallback, fun, macro, callbacks), doc, metadata}
{{kind, fun, arity}, _, _, doc, _} ->
{format_callback(kind, fun, {fun, arity}, callbacks), doc}
{{kind, fun, arity}, _, _, doc, metadata} ->
{format_callback(kind, fun, {fun, arity}, callbacks), doc, metadata}
end)
{:ok, docs}
@@ -588,7 +588,7 @@ defmodule IEx.Introspection do
if optional_callbacks == [] do
docs
else
docs ++ [{format_optional_callbacks(optional_callbacks), ""}]
docs ++ [{format_optional_callbacks(optional_callbacks), "", %{}}]
end
end
@@ -637,8 +637,8 @@ defmodule IEx.Introspection do
{:ok, types} ->
printed =
for {_, {^type, _, args}} = typespec <- types do
doc = {format_type(typespec), type_doc(module, type, length(args))}
print_typespec(doc)
type_doc(module, type, length(args), typespec)
|> print_typespec()
end
if printed == [] do
@@ -657,8 +657,8 @@ defmodule IEx.Introspection do
{:ok, types} ->
printed =
for {_, {^type, _, args}} = typespec <- types, length(args) == arity do
doc = {format_type(typespec), type_doc(module, type, arity)}
print_typespec(doc)
type_doc(module, type, arity, typespec)
|> print_typespec()
end
if printed == [] do
@@ -674,12 +674,12 @@ defmodule IEx.Introspection do
dont_display_result()
end
defp type_doc(module, type, arity) do
defp type_doc(module, type, arity, typespec) do
if docs = get_docs(module, [:type]) do
{_, _, _, content, _} = Enum.find(docs, &match?({:type, ^type, ^arity}, elem(&1, 0)))
content
{_, _, _, content, metadata} = Enum.find(docs, &match?({:type, ^type, ^arity}, elem(&1, 0)))
{format_type(typespec), content, metadata}
else
:none
{format_type(typespec), :none, %{}}
end
end
@@ -717,27 +717,31 @@ defmodule IEx.Introspection do
IEx.color(:doc_inline_code, left) <> " " <> right
end
defp print_doc(heading, types, doc) do
defp print_doc(heading, types, doc, metadata) do
doc = translate_doc(doc) || ""
if opts = IEx.Config.ansi_docs() do
IO.ANSI.Docs.print_heading(heading, opts)
IO.write(types)
IO.ANSI.Docs.print_metadata(metadata, opts)
IO.ANSI.Docs.print(doc, opts)
else
IO.puts("* #{heading}\n")
IO.write(types)
IO.ANSI.Docs.print_metadata(metadata, enabled: false)
IO.puts(doc)
end
end
defp print_typespec({types, doc}) do
defp print_typespec({types, doc, metadata}) do
IO.puts(types)
doc = translate_doc(doc)
if opts = IEx.Config.ansi_docs() do
IO.ANSI.Docs.print_metadata(metadata, opts)
doc && IO.ANSI.Docs.print(doc, opts)
else
IO.ANSI.Docs.print_metadata(metadata, enabled: false)
doc && IO.puts(doc)
end
end
+80
View File
@@ -403,6 +403,38 @@ defmodule IEx.HelpersTest do
"No documentation for Kernel.__info__ was found\n"
end
test "prints documentation metadata" do
content = """
defmodule Sample do
@moduledoc "Sample module"
@moduledoc deprecated: "Use OtherSample", since: "1.2.3", authors: ["Alice", "Bob"]
@doc "With metadata"
@doc since: "1.2.3", author: "Alice"
@deprecated "Use OtherSample.with_metadata/0"
def with_metadata(), do: 0
@doc "Without metadata"
def without_metadata(), do: 1
end
"""
filename = "sample.ex"
with_file(filename, content, fn ->
assert c(filename, ".") == [Sample]
assert capture_io(fn -> h(Sample) end) ==
"* Sample\n\ndeprecated: Use OtherSample\nsince: 1.2.3\n\nSample module\n"
assert capture_io(fn -> h(Sample.with_metadata()) end) ==
"* def with_metadata()\n\ndeprecated: Use OtherSample.with_metadata/0\nsince: 1.2.3\n\nWith metadata\n"
assert capture_io(fn -> h(Sample.without_metadata()) end) ==
"* def without_metadata()\n\nWithout metadata\n"
end)
after
cleanup_modules([Sample])
end
test "considers underscored functions without docs by default" do
content = """
defmodule Sample do
@@ -593,6 +625,27 @@ defmodule IEx.HelpersTest do
"@callback message(t()) :: String.t()\n\n"
end
test "prints callback documentation metadata" do
filename = "callback_with_metadata.ex"
content = """
defmodule CallbackWithMetadata do
@doc "callback"
@doc since: "1.2.3", deprecated: "Use handle_test/1", purpose: :test
@callback test(:foo) :: integer
end
"""
with_file(filename, content, fn ->
assert c(filename, ".") == [CallbackWithMetadata]
assert capture_io(fn -> b(CallbackWithMetadata.test()) end) ==
"@callback test(:foo) :: integer()\n\ndeprecated: Use handle_test/1\nsince: 1.2.3\n\ncallback\n"
end)
after
cleanup_modules([CallbackWithMetadata])
end
test "prints optional callback" do
filename = "optional_callbacks.ex"
@@ -666,6 +719,33 @@ defmodule IEx.HelpersTest do
after
cleanup_modules([TypeSample])
end
test "prints type documentation metadata" do
content = """
defmodule TypeSample do
@typedoc "An id with description."
@typedoc since: "1.2.3", deprecated: "Use t/0", purpose: :test
@type id_with_desc :: {number, String.t}
end
"""
filename = "typesample.ex"
with_file(filename, content, fn ->
assert c(filename, ".") == [TypeSample]
assert capture_io(fn -> t(TypeSample.id_with_desc()) end) == """
@type id_with_desc() :: {number(), String.t()}
deprecated: Use t/0
since: 1.2.3
An id with description.
"""
end)
after
cleanup_modules([TypeSample])
end
end
describe "v" do
+4
View File
@@ -339,6 +339,10 @@ defmodule Logger.Translator do
["\nStart Module: ", inspect(mod) | child_debug(min_level, debug)]
end
defp child_info(_min_level, _child) do
[]
end
defp child_debug(:debug, restart_type: restart, shutdown: shutdown, child_type: type) do
["\nRestart: ", inspect(restart), "\nShutdown: ", inspect(shutdown)] ++
["\nType: ", inspect(type)]