There were instances of IO.puts/1 calls without parens throughout the
whole codebase (in docs, code, tests). I removed most of them where it
made sense to do so, so that users will find documentation and other
things consistent with how the formatter behaves.
Let's see some use cases. First we configure IEx to use our custom
function:
iex> IEx.configure(inspect: [inspect_fun: &Pretty.inspect/2])
:ok
1. Pretty-printing integers
iex> :math.pow(2, 32) |> trunc()
4_294_967_296
2. Inspect tuples as records
iex> {:foo, :bar}
{:foo, :bar}
iex> {:person, "Alice", 30}
#person(name: "Alice", age: 30)
3. Overwrite struct's Inspect implementation
iex> URI.parse("https://elixir-lang.org")
#URI<https://elixir-lang.org>
---
Code for the `Pretty.inspect/2` function:
defmodule Pretty do
def inspect(integer, opts) when is_integer(integer) do
PrettyIntegers.inspect(integer, opts)
end
def inspect(tuple, opts) when is_tuple(tuple) do
records = %{
{:person, 2} => [:name, :age]
}
PrettyTuples.inspect(tuple, records, opts)
end
def inspect(%URI{} = uri, _opts) do
Inspect.Algebra.concat(["#URI<", URI.to_string(uri), ">"])
end
def inspect(term, opts) do
Inspect.inspect(term, opts)
end
end
defmodule PrettyIntegers do
def inspect(term, %Inspect.Opts{base: :decimal}) do
pretty_decimal(term, "_")
end
def inspect(term, %Inspect.Opts{base: base}) do
Integer.to_string(term, base_to_value(base))
|> prepend_prefix(base)
end
def pretty_decimal(n, separator) when n < 0 do
"-" <> pretty_decimal(abs(n), separator)
end
def pretty_decimal(n, separator) when n >= 1000 do
left = div(n, 1_000)
right = rem(n, 1_000)
right_str = :io_lib.format("~3..0B", [right]) |> IO.iodata_to_binary
pretty_decimal(left, separator) <> separator <> right_str
end
def pretty_decimal(n, _) do
Integer.to_string(n)
end
defp base_to_value(base) do
case base do
:binary -> 2
:octal -> 8
:hex -> 16
end
end
defp prepend_prefix(value, base) do
prefix = case base do
:binary -> "0b"
:octal -> "0o"
:hex -> "0x"
end
prefix <> value
end
end
defmodule PrettyTuples do
import Inspect.Algebra
def inspect({}, _records, opts), do: inspect_tuple([], opts)
def inspect(tuple, records, opts) do
list = Tuple.to_list(tuple)
[record_name | values] = list
case record_fields(records, record_name, tuple) do
{:ok, fields} ->
inspect_record(record_name, fields, values, opts)
_ ->
inspect_tuple(list, opts)
end
end
defp record_fields(records, record_name, tuple) do
fields_size = tuple_size(tuple) - 1
Map.fetch(records, {record_name, fields_size})
end
defp inspect_tuple(list, opts) do
inspect("{", list, "}", &to_doc/2, :flex, opts)
end
defp inspect_record(record_name, fields, values, opts) do
kwlist = Enum.zip(fields, values)
inspect("##{record_name}(", kwlist, ")", &Inspect.List.keyword/2, :strict, opts)
end
defp inspect(open, list, close, fun, break, opts) do
open = color(open, :tuple, opts)
sep = color(",", :tuple, opts)
close = color(close, :tuple, opts)
container_opts = [separator: sep, break: break]
container_doc(open, list, close, opts, fun, container_opts)
end
end
"Keyword.{take|drop|split}" don't offer support for an Enumerable of
keys to take/drop/split based on. However, the "Map" counterparts do.
With this commit, we hard-deprecate support for Enumerables of keys in
"Map.{take|drop|split}". Only lists of keys are allowed.
This fixes an issue where a registry's PIDPartition table would gain an
entry each time after the first call to Registry.register on a unique
registry.
We also guarantee unregistered works generally with "tricky keys".
Closes#8611.
Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
The previous implementation was generating an unnecessary
intermediate function when using `&super/arity`.
In addition, capture expressions using `super` with sequential
value placeholders (`&n`) were not optimized like other functions.
For example, the capture expression `&foo(&1, &2, &3)` is
optimized to `&foo/3` because the value placeholders (`&n`) are
sequential `&1, &2, &3`.